~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/modules/vfs_gpfs.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Unix SMB/CIFS implementation.
 
3
   Wrap gpfs calls in vfs functions.
 
4
 
 
5
   Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006
 
6
 
 
7
   Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com>
 
8
                            and Gomati Mohanan <gomati.mohanan@in.ibm.com>
 
9
 
 
10
   This program is free software; you can redistribute it and/or modify
 
11
   it under the terms of the GNU General Public License as published by
 
12
   the Free Software Foundation; either version 3 of the License, or
 
13
   (at your option) any later version.
 
14
 
 
15
   This program is distributed in the hope that it will be useful,
 
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
   GNU General Public License for more details.
 
19
 
 
20
   You should have received a copy of the GNU General Public License
 
21
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
22
*/
 
23
 
 
24
#include "includes.h"
 
25
 
 
26
#undef DBGC_CLASS
 
27
#define DBGC_CLASS DBGC_VFS
 
28
 
 
29
#include <gpfs_gpl.h>
 
30
#include "nfs4_acls.h"
 
31
#include "vfs_gpfs.h"
 
32
 
 
33
static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, 
 
34
                                 uint32 share_mode)
 
35
{
 
36
 
 
37
        START_PROFILE(syscall_kernel_flock);
 
38
 
 
39
        kernel_flock(fsp->fh->fd, share_mode);
 
40
 
 
41
        if (!set_gpfs_sharemode(fsp, fsp->access_mask, fsp->share_access)) {
 
42
 
 
43
                return -1;
 
44
 
 
45
        }
 
46
 
 
47
        END_PROFILE(syscall_kernel_flock);
 
48
 
 
49
        return 0;
 
50
}
 
51
 
 
52
static int vfs_gpfs_close(vfs_handle_struct *handle, files_struct *fsp)
 
53
{
 
54
        if ((fsp->fh != NULL) && (fsp->fh->fd != -1)) {
 
55
                set_gpfs_sharemode(fsp, 0, 0);
 
56
        }
 
57
 
 
58
        return SMB_VFS_NEXT_CLOSE(handle, fsp);
 
59
}
 
60
 
 
61
static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, 
 
62
                             int leasetype)
 
63
{
 
64
        int ret;
 
65
 
 
66
        START_PROFILE(syscall_linux_setlease);
 
67
 
 
68
        if ( linux_set_lease_sighandler(fsp->fh->fd) == -1)
 
69
                return -1;
 
70
 
 
71
        ret = set_gpfs_lease(fsp->fh->fd,leasetype);
 
72
 
 
73
        if ( ret < 0 ) {
 
74
                /* This must have come from GPFS not being available */
 
75
                /* or some other error, hence call the default */
 
76
                ret = linux_setlease(fsp->fh->fd, leasetype);
 
77
        }
 
78
 
 
79
        END_PROFILE(syscall_linux_setlease);
 
80
 
 
81
        return ret;
 
82
}
 
83
 
 
84
static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
 
85
                                      const char *path,
 
86
                                      const char *name,
 
87
                                      TALLOC_CTX *mem_ctx,
 
88
                                      char **found_name)
 
89
{
 
90
        int result;
 
91
        char *full_path;
 
92
        char real_pathname[PATH_MAX+1];
 
93
        int buflen;
 
94
 
 
95
        full_path = talloc_asprintf(talloc_tos(), "%s/%s", path, name);
 
96
        if (full_path == NULL) {
 
97
                errno = ENOMEM;
 
98
                return -1;
 
99
        }
 
100
 
 
101
        buflen = sizeof(real_pathname) - 1;
 
102
 
 
103
        result = smbd_gpfs_get_realfilename_path(full_path, real_pathname,
 
104
                                                 &buflen);
 
105
 
 
106
        TALLOC_FREE(full_path);
 
107
 
 
108
        if ((result == -1) && (errno == ENOSYS)) {
 
109
                return SMB_VFS_NEXT_GET_REAL_FILENAME(
 
110
                        handle, path, name, mem_ctx, found_name);
 
111
        }
 
112
 
 
113
        if (result == -1) {
 
114
                DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n",
 
115
                           strerror(errno)));
 
116
                return -1;
 
117
        }
 
118
 
 
119
        /*
 
120
         * GPFS does not necessarily null-terminate the returned path
 
121
         * but instead returns the buffer length in buflen.
 
122
         */
 
123
 
 
124
        if (buflen < sizeof(real_pathname)) {
 
125
                real_pathname[buflen] = '\0';
 
126
        } else {
 
127
                real_pathname[sizeof(real_pathname)-1] = '\0';
 
128
        }
 
129
 
 
130
        DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n",
 
131
                   path, name, real_pathname));
 
132
 
 
133
        name = strrchr_m(real_pathname, '/');
 
134
        if (name == NULL) {
 
135
                errno = ENOENT;
 
136
                return -1;
 
137
        }
 
138
 
 
139
        *found_name = talloc_strdup(mem_ctx, name+1);
 
140
        if (*found_name == NULL) {
 
141
                errno = ENOMEM;
 
142
                return -1;
 
143
        }
 
144
 
 
145
        return 0;
 
146
}
 
147
 
 
148
static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
 
149
{
 
150
        int     i;
 
151
        if (gacl==NULL)
 
152
        {
 
153
                DEBUG(0, ("gpfs acl is NULL\n"));
 
154
                return;
 
155
        }
 
156
 
 
157
        DEBUG(level, ("gpfs acl: nace: %d, type:%d, version:%d, level:%d, len:%d\n",
 
158
                gacl->acl_nace, gacl->acl_type, gacl->acl_version, gacl->acl_level, gacl->acl_len));
 
159
        for(i=0; i<gacl->acl_nace; i++)
 
160
        {
 
161
                struct gpfs_ace_v4 *gace = gacl->ace_v4 + i;
 
162
                DEBUG(level, ("\tace[%d]: type:%d, flags:0x%x, mask:0x%x, iflags:0x%x, who:%u\n",
 
163
                        i, gace->aceType, gace->aceFlags, gace->aceMask,
 
164
                        gace->aceIFlags, gace->aceWho));
 
165
        }
 
166
}
 
167
 
 
168
static struct gpfs_acl *gpfs_getacl_alloc(const char *fname, gpfs_aclType_t type)
 
169
{
 
170
        struct gpfs_acl *acl;
 
171
        size_t len = 200;
 
172
        int ret;
 
173
        TALLOC_CTX *mem_ctx = talloc_tos();
 
174
 
 
175
        acl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, len);
 
176
        if (acl == NULL) {
 
177
                errno = ENOMEM;
 
178
                return NULL;
 
179
        }
 
180
 
 
181
        acl->acl_len = len;
 
182
        acl->acl_level = 0;
 
183
        acl->acl_version = 0;
 
184
        acl->acl_type = type;
 
185
 
 
186
        ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
 
187
        if ((ret != 0) && (errno == ENOSPC)) {
 
188
                struct gpfs_acl *new_acl = (struct gpfs_acl *)TALLOC_SIZE(
 
189
                        mem_ctx, acl->acl_len + sizeof(struct gpfs_acl));
 
190
                if (new_acl == NULL) {
 
191
                        errno = ENOMEM;
 
192
                        return NULL;
 
193
                }
 
194
 
 
195
                new_acl->acl_len = acl->acl_len;
 
196
                new_acl->acl_level = acl->acl_level;
 
197
                new_acl->acl_version = acl->acl_version;
 
198
                new_acl->acl_type = acl->acl_type;
 
199
                acl = new_acl;
 
200
 
 
201
                ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
 
202
        }
 
203
        if (ret != 0)
 
204
        {
 
205
                DEBUG(8, ("smbd_gpfs_getacl failed with %s\n",strerror(errno)));
 
206
                return NULL;
 
207
        }
 
208
 
 
209
        return acl;
 
210
}
 
211
 
 
212
/* Tries to get nfs4 acls and returns SMB ACL allocated.
 
213
 * On failure returns 1 if it got non-NFSv4 ACL to prompt 
 
214
 * retry with POSIX ACL checks.
 
215
 * On failure returns -1 if there is system (GPFS) error, check errno.
 
216
 * Returns 0 on success
 
217
 */
 
218
static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
 
219
{
 
220
        int i;
 
221
        struct gpfs_acl *gacl = NULL;
 
222
        DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
 
223
 
 
224
        /* First get the real acl length */
 
225
        gacl = gpfs_getacl_alloc(fname, 0);
 
226
        if (gacl == NULL) {
 
227
                DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
 
228
                           fname, strerror(errno)));
 
229
                return -1;
 
230
        }
 
231
 
 
232
        if (gacl->acl_type != GPFS_ACL_TYPE_NFS4) {
 
233
                DEBUG(10, ("Got non-nfsv4 acl\n"));
 
234
                /* Retry with POSIX ACLs check */
 
235
                return 1;
 
236
        }
 
237
 
 
238
        *ppacl = smb_create_smb4acl();
 
239
 
 
240
        DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
 
241
                   gacl->acl_len, gacl->acl_level, gacl->acl_version,
 
242
                   gacl->acl_nace));
 
243
 
 
244
        for (i=0; i<gacl->acl_nace; i++) {
 
245
                struct gpfs_ace_v4 *gace = &gacl->ace_v4[i];
 
246
                SMB_ACE4PROP_T smbace;
 
247
                DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
 
248
                           "who: %d\n", gace->aceType, gace->aceIFlags,
 
249
                           gace->aceFlags, gace->aceMask, gace->aceWho));
 
250
 
 
251
                ZERO_STRUCT(smbace);
 
252
                if (gace->aceIFlags & ACE4_IFLAG_SPECIAL_ID) {
 
253
                        smbace.flags |= SMB_ACE4_ID_SPECIAL;
 
254
                        switch (gace->aceWho) {
 
255
                        case ACE4_SPECIAL_OWNER:
 
256
                                smbace.who.special_id = SMB_ACE4_WHO_OWNER;
 
257
                                break;
 
258
                        case ACE4_SPECIAL_GROUP:
 
259
                                smbace.who.special_id = SMB_ACE4_WHO_GROUP;
 
260
                                break;
 
261
                        case ACE4_SPECIAL_EVERYONE:
 
262
                                smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
 
263
                                break;
 
264
                        default:
 
265
                                DEBUG(8, ("invalid special gpfs id %d "
 
266
                                          "ignored\n", gace->aceWho));
 
267
                                continue; /* don't add it */
 
268
                        }
 
269
                } else {
 
270
                        if (gace->aceFlags & ACE4_FLAG_GROUP_ID)
 
271
                                smbace.who.gid = gace->aceWho;
 
272
                        else
 
273
                                smbace.who.uid = gace->aceWho;
 
274
                }
 
275
 
 
276
                /* remove redundent deny entries */
 
277
                if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
 
278
                        struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1];
 
279
                        if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
 
280
                            prev->aceFlags == gace->aceFlags &&
 
281
                            prev->aceIFlags == gace->aceIFlags &&
 
282
                            (gace->aceMask & prev->aceMask) == 0 &&
 
283
                            gace->aceWho == prev->aceWho) {
 
284
                                /* its redundent - skip it */
 
285
                                continue;
 
286
                        }                                                
 
287
                }
 
288
 
 
289
                smbace.aceType = gace->aceType;
 
290
                smbace.aceFlags = gace->aceFlags;
 
291
                smbace.aceMask = gace->aceMask;
 
292
                smb_add_ace4(*ppacl, &smbace);
 
293
        }
 
294
 
 
295
        return 0;
 
296
}
 
297
 
 
298
static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
 
299
        files_struct *fsp, uint32 security_info,
 
300
        SEC_DESC **ppdesc)
 
301
{
 
302
        SMB4ACL_T *pacl = NULL;
 
303
        int     result;
 
304
 
 
305
        *ppdesc = NULL;
 
306
        result = gpfs_get_nfs4_acl(fsp->fsp_name, &pacl);
 
307
 
 
308
        if (result == 0)
 
309
                return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
 
310
 
 
311
        if (result > 0) {
 
312
                DEBUG(10, ("retrying with posix acl...\n"));
 
313
                return posix_fget_nt_acl(fsp, security_info, ppdesc);
 
314
        }
 
315
 
 
316
        /* GPFS ACL was not read, something wrong happened, error code is set in errno */
 
317
        return map_nt_error_from_unix(errno);
 
318
}
 
319
 
 
320
static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
 
321
        const char *name,
 
322
        uint32 security_info, SEC_DESC **ppdesc)
 
323
{
 
324
        SMB4ACL_T *pacl = NULL;
 
325
        int     result;
 
326
 
 
327
        *ppdesc = NULL;
 
328
        result = gpfs_get_nfs4_acl(name, &pacl);
 
329
 
 
330
        if (result == 0)
 
331
                return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl);
 
332
 
 
333
        if (result > 0) {
 
334
                DEBUG(10, ("retrying with posix acl...\n"));
 
335
                return posix_get_nt_acl(handle->conn, name, security_info, ppdesc);
 
336
        }
 
337
 
 
338
        /* GPFS ACL was not read, something wrong happened, error code is set in errno */
 
339
        return map_nt_error_from_unix(errno);
 
340
}
 
341
 
 
342
static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
 
343
{
 
344
        int ret;
 
345
        gpfs_aclLen_t gacl_len;
 
346
        SMB4ACE_T       *smbace;
 
347
        struct gpfs_acl *gacl;
 
348
        TALLOC_CTX *mem_ctx  = talloc_tos();
 
349
 
 
350
        gacl_len = sizeof(struct gpfs_acl) +
 
351
                (smb_get_naces(smbacl)-1)*sizeof(gpfs_ace_v4_t);
 
352
 
 
353
        gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len);
 
354
        if (gacl == NULL) {
 
355
                DEBUG(0, ("talloc failed\n"));
 
356
                errno = ENOMEM;
 
357
                return False;
 
358
        }
 
359
 
 
360
        gacl->acl_len = gacl_len;
 
361
        gacl->acl_level = 0;
 
362
        gacl->acl_version = GPFS_ACL_VERSION_NFS4;
 
363
        gacl->acl_type = GPFS_ACL_TYPE_NFS4;
 
364
        gacl->acl_nace = 0; /* change later... */
 
365
 
 
366
        for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
 
367
                struct gpfs_ace_v4 *gace = &gacl->ace_v4[gacl->acl_nace];
 
368
                SMB_ACE4PROP_T  *aceprop = smb_get_ace4(smbace);
 
369
 
 
370
                gace->aceType = aceprop->aceType;
 
371
                gace->aceFlags = aceprop->aceFlags;
 
372
                gace->aceMask = aceprop->aceMask;
 
373
 
 
374
                /*
 
375
                 * GPFS can't distinguish between WRITE and APPEND on
 
376
                 * files, so one being set without the other is an
 
377
                 * error. Sorry for the many ()'s :-)
 
378
                 */
 
379
 
 
380
                if (!fsp->is_directory
 
381
                    &&
 
382
                    ((((gace->aceMask & ACE4_MASK_WRITE) == 0)
 
383
                      && ((gace->aceMask & ACE4_MASK_APPEND) != 0))
 
384
                     ||
 
385
                     (((gace->aceMask & ACE4_MASK_WRITE) != 0)
 
386
                      && ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
 
387
                    &&
 
388
                    lp_parm_bool(fsp->conn->params->service, "gpfs",
 
389
                                 "merge_writeappend", True)) {
 
390
                        DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
 
391
                                  "WRITE^APPEND, setting WRITE|APPEND\n",
 
392
                                  fsp->fsp_name));
 
393
                        gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
 
394
                }
 
395
 
 
396
                gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;
 
397
 
 
398
                if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
 
399
                {
 
400
                        switch(aceprop->who.special_id)
 
401
                        {
 
402
                        case SMB_ACE4_WHO_EVERYONE:
 
403
                                gace->aceWho = ACE4_SPECIAL_EVERYONE;
 
404
                                break;
 
405
                        case SMB_ACE4_WHO_OWNER:
 
406
                                gace->aceWho = ACE4_SPECIAL_OWNER;
 
407
                                break;
 
408
                        case SMB_ACE4_WHO_GROUP:
 
409
                                gace->aceWho = ACE4_SPECIAL_GROUP;
 
410
                                break;
 
411
                        default:
 
412
                                DEBUG(8, ("unsupported special_id %d\n", aceprop->who.special_id));
 
413
                                continue; /* don't add it !!! */
 
414
                        }
 
415
                } else {
 
416
                        /* just only for the type safety... */
 
417
                        if (aceprop->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
 
418
                                gace->aceWho = aceprop->who.gid;
 
419
                        else
 
420
                                gace->aceWho = aceprop->who.uid;
 
421
                }
 
422
 
 
423
                gacl->acl_nace++;
 
424
        }
 
425
 
 
426
        ret = smbd_gpfs_putacl(fsp->fsp_name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
 
427
        if (ret != 0) {
 
428
                DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
 
429
                gpfs_dumpacl(8, gacl);
 
430
                return False;
 
431
        }
 
432
 
 
433
        DEBUG(10, ("gpfs_putacl succeeded\n"));
 
434
        return True;
 
435
}
 
436
 
 
437
static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd)
 
438
{
 
439
        struct gpfs_acl *acl;
 
440
        NTSTATUS result = NT_STATUS_ACCESS_DENIED;
 
441
 
 
442
        acl = gpfs_getacl_alloc(fsp->fsp_name, 0);
 
443
        if (acl == NULL)
 
444
                return result;
 
445
 
 
446
        if (acl->acl_version&GPFS_ACL_VERSION_NFS4)
 
447
        {
 
448
                result = smb_set_nt_acl_nfs4(
 
449
                        fsp, security_info_sent, psd,
 
450
                        gpfsacl_process_smbacl);
 
451
        } else { /* assume POSIX ACL - by default... */
 
452
                result = set_nt_acl(fsp, security_info_sent, psd);
 
453
        }
 
454
 
 
455
        return result;
 
456
}
 
457
 
 
458
static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd)
 
459
{
 
460
        return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd);
 
461
}
 
462
 
 
463
static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl)
 
464
{
 
465
        SMB_ACL_T result;
 
466
        int i;
 
467
 
 
468
        result = sys_acl_init(pacl->acl_nace);
 
469
        if (result == NULL) {
 
470
                errno = ENOMEM;
 
471
                return NULL;
 
472
        }
 
473
 
 
474
        result->count = pacl->acl_nace;
 
475
 
 
476
        for (i=0; i<pacl->acl_nace; i++) {
 
477
                struct smb_acl_entry *ace = &result->acl[i];
 
478
                const struct gpfs_ace_v1 *g_ace = &pacl->ace_v1[i];
 
479
 
 
480
                DEBUG(10, ("Converting type %d id %lu perm %x\n",
 
481
                           (int)g_ace->ace_type, (unsigned long)g_ace->ace_who,
 
482
                           (int)g_ace->ace_perm));
 
483
 
 
484
                switch (g_ace->ace_type) {
 
485
                case GPFS_ACL_USER:
 
486
                        ace->a_type = SMB_ACL_USER;
 
487
                        ace->uid = (uid_t)g_ace->ace_who;
 
488
                        break;
 
489
                case GPFS_ACL_USER_OBJ:
 
490
                        ace->a_type = SMB_ACL_USER_OBJ;
 
491
                        break;
 
492
                case GPFS_ACL_GROUP:
 
493
                        ace->a_type = SMB_ACL_GROUP;
 
494
                        ace->gid = (gid_t)g_ace->ace_who;
 
495
                        break;
 
496
                case GPFS_ACL_GROUP_OBJ:
 
497
                        ace->a_type = SMB_ACL_GROUP_OBJ;
 
498
                        break;
 
499
                case GPFS_ACL_OTHER:
 
500
                        ace->a_type = SMB_ACL_OTHER;
 
501
                        break;
 
502
                case GPFS_ACL_MASK:
 
503
                        ace->a_type = SMB_ACL_MASK;
 
504
                        break;
 
505
                default:
 
506
                        DEBUG(10, ("Got invalid ace_type: %d\n",
 
507
                                   g_ace->ace_type));
 
508
                        errno = EINVAL;
 
509
                        SAFE_FREE(result);
 
510
                        return NULL;
 
511
                }
 
512
 
 
513
                ace->a_perm = 0;
 
514
                ace->a_perm |= (g_ace->ace_perm & ACL_PERM_READ) ?
 
515
                        SMB_ACL_READ : 0;
 
516
                ace->a_perm |= (g_ace->ace_perm & ACL_PERM_WRITE) ?
 
517
                        SMB_ACL_WRITE : 0;
 
518
                ace->a_perm |= (g_ace->ace_perm & ACL_PERM_EXECUTE) ?
 
519
                        SMB_ACL_EXECUTE : 0;
 
520
 
 
521
                DEBUGADD(10, ("Converted to %d perm %x\n",
 
522
                              ace->a_type, ace->a_perm));
 
523
        }
 
524
 
 
525
        return result;
 
526
}
 
527
 
 
528
static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type)
 
529
{
 
530
        struct gpfs_acl *pacl;
 
531
        SMB_ACL_T result = NULL;
 
532
 
 
533
        pacl = gpfs_getacl_alloc(path, type);
 
534
 
 
535
        if (pacl == NULL) {
 
536
                DEBUG(10, ("gpfs_getacl failed for %s with %s\n",
 
537
                           path, strerror(errno)));
 
538
                if (errno == 0) {
 
539
                        errno = EINVAL;
 
540
                }
 
541
                goto done;
 
542
        }
 
543
 
 
544
        if (pacl->acl_version != GPFS_ACL_VERSION_POSIX) {
 
545
                DEBUG(10, ("Got acl version %d, expected %d\n",
 
546
                           pacl->acl_version, GPFS_ACL_VERSION_POSIX));
 
547
                errno = EINVAL;
 
548
                goto done;
 
549
        }
 
550
 
 
551
        DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
 
552
                   pacl->acl_len, pacl->acl_level, pacl->acl_version,
 
553
                   pacl->acl_nace));
 
554
 
 
555
        result = gpfs2smb_acl(pacl);
 
556
        if (result == NULL) {
 
557
                goto done;
 
558
        }
 
559
 
 
560
 done:
 
561
 
 
562
        if (errno != 0) {
 
563
                SAFE_FREE(result);
 
564
        }
 
565
        return result;  
 
566
}
 
567
 
 
568
static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
 
569
                                          const char *path_p,
 
570
                                          SMB_ACL_TYPE_T type)
 
571
{
 
572
        gpfs_aclType_t gpfs_type;
 
573
 
 
574
        switch(type) {
 
575
        case SMB_ACL_TYPE_ACCESS:
 
576
                gpfs_type = GPFS_ACL_TYPE_ACCESS;
 
577
                break;
 
578
        case SMB_ACL_TYPE_DEFAULT:
 
579
                gpfs_type = GPFS_ACL_TYPE_DEFAULT;
 
580
                break;
 
581
        default:
 
582
                DEBUG(0, ("Got invalid type: %d\n", type));
 
583
                smb_panic("exiting");
 
584
        }
 
585
 
 
586
        return gpfsacl_get_posix_acl(path_p, gpfs_type);
 
587
}
 
588
 
 
589
static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
 
590
                                        files_struct *fsp)
 
591
{
 
592
        return gpfsacl_get_posix_acl(fsp->fsp_name, GPFS_ACL_TYPE_ACCESS);
 
593
}
 
594
 
 
595
static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
 
596
                                     SMB_ACL_TYPE_T type)
 
597
{
 
598
        gpfs_aclLen_t len;
 
599
        struct gpfs_acl *result;
 
600
        int i;
 
601
        union gpfs_ace_union
 
602
        {
 
603
                gpfs_ace_v1_t  ace_v1[1]; /* when GPFS_ACL_VERSION_POSIX */
 
604
                gpfs_ace_v4_t  ace_v4[1]; /* when GPFS_ACL_VERSION_NFS4  */
 
605
        };
 
606
 
 
607
        DEBUG(10, ("smb2gpfs_acl: Got ACL with %d entries\n", pacl->count));
 
608
 
 
609
        len = sizeof(struct gpfs_acl) - sizeof(union gpfs_ace_union) +
 
610
                (pacl->count)*sizeof(gpfs_ace_v1_t);
 
611
 
 
612
        result = (struct gpfs_acl *)SMB_MALLOC(len);
 
613
        if (result == NULL) {
 
614
                errno = ENOMEM;
 
615
                return result;
 
616
        }
 
617
 
 
618
        result->acl_len = len;
 
619
        result->acl_level = 0;
 
620
        result->acl_version = GPFS_ACL_VERSION_POSIX;
 
621
        result->acl_type = (type == SMB_ACL_TYPE_DEFAULT) ?
 
622
                GPFS_ACL_TYPE_DEFAULT : GPFS_ACL_TYPE_ACCESS;
 
623
        result->acl_nace = pacl->count;
 
624
 
 
625
        for (i=0; i<pacl->count; i++) {
 
626
                const struct smb_acl_entry *ace = &pacl->acl[i];
 
627
                struct gpfs_ace_v1 *g_ace = &result->ace_v1[i];
 
628
 
 
629
                DEBUG(10, ("Converting type %d perm %x\n",
 
630
                           (int)ace->a_type, (int)ace->a_perm));
 
631
 
 
632
                g_ace->ace_perm = 0;
 
633
 
 
634
                switch(ace->a_type) {
 
635
                case SMB_ACL_USER:
 
636
                        g_ace->ace_type = GPFS_ACL_USER;
 
637
                        g_ace->ace_who = (gpfs_uid_t)ace->uid;
 
638
                        break;
 
639
                case SMB_ACL_USER_OBJ:
 
640
                        g_ace->ace_type = GPFS_ACL_USER_OBJ;
 
641
                        g_ace->ace_perm |= ACL_PERM_CONTROL;
 
642
                        g_ace->ace_who = 0;
 
643
                        break;
 
644
                case SMB_ACL_GROUP:
 
645
                        g_ace->ace_type = GPFS_ACL_GROUP;
 
646
                        g_ace->ace_who = (gpfs_uid_t)ace->gid;
 
647
                        break;
 
648
                case SMB_ACL_GROUP_OBJ:
 
649
                        g_ace->ace_type = GPFS_ACL_GROUP_OBJ;
 
650
                        g_ace->ace_who = 0;
 
651
                        break;
 
652
                case SMB_ACL_MASK:
 
653
                        g_ace->ace_type = GPFS_ACL_MASK;
 
654
                        g_ace->ace_perm = 0x8f;
 
655
                        g_ace->ace_who = 0;
 
656
                        break;
 
657
                case SMB_ACL_OTHER:
 
658
                        g_ace->ace_type = GPFS_ACL_OTHER;
 
659
                        g_ace->ace_who = 0;
 
660
                        break;
 
661
                default:
 
662
                        DEBUG(10, ("Got invalid ace_type: %d\n", ace->a_type));
 
663
                        errno = EINVAL;
 
664
                        SAFE_FREE(result);
 
665
                        return NULL;
 
666
                }
 
667
 
 
668
                g_ace->ace_perm |= (ace->a_perm & SMB_ACL_READ) ?
 
669
                        ACL_PERM_READ : 0;
 
670
                g_ace->ace_perm |= (ace->a_perm & SMB_ACL_WRITE) ?
 
671
                        ACL_PERM_WRITE : 0;
 
672
                g_ace->ace_perm |= (ace->a_perm & SMB_ACL_EXECUTE) ?
 
673
                        ACL_PERM_EXECUTE : 0;
 
674
 
 
675
                DEBUGADD(10, ("Converted to %d id %d perm %x\n",
 
676
                              g_ace->ace_type, g_ace->ace_who, g_ace->ace_perm));
 
677
        }
 
678
 
 
679
        return result;
 
680
}
 
681
 
 
682
static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
 
683
                                    const char *name,
 
684
                                    SMB_ACL_TYPE_T type,
 
685
                                    SMB_ACL_T theacl)
 
686
{
 
687
        struct gpfs_acl *gpfs_acl;
 
688
        int result;
 
689
 
 
690
        gpfs_acl = smb2gpfs_acl(theacl, type);
 
691
        if (gpfs_acl == NULL) {
 
692
                return -1;
 
693
        }
 
694
 
 
695
        result = smbd_gpfs_putacl((char *)name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gpfs_acl);
 
696
 
 
697
        SAFE_FREE(gpfs_acl);
 
698
        return result;
 
699
}
 
700
 
 
701
static int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
 
702
                                  files_struct *fsp,
 
703
                                  SMB_ACL_T theacl)
 
704
{
 
705
        return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name, SMB_ACL_TYPE_ACCESS, theacl);
 
706
}
 
707
 
 
708
static int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
 
709
                                           const char *path)
 
710
{
 
711
        errno = ENOTSUP;
 
712
        return -1;
 
713
}
 
714
 
 
715
/*
 
716
 * Assumed: mode bits are shiftable and standard
 
717
 * Output: the new aceMask field for an smb nfs4 ace
 
718
 */
 
719
static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx)
 
720
{
 
721
        const uint32 posix_nfs4map[3] = {
 
722
                SMB_ACE4_EXECUTE, /* execute */
 
723
                SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
 
724
                SMB_ACE4_READ_DATA /* read */
 
725
        };
 
726
        int     i;
 
727
        uint32_t        posix_mask = 0x01;
 
728
        uint32_t        posix_bit;
 
729
        uint32_t        nfs4_bits;
 
730
 
 
731
        for(i=0; i<3; i++) {
 
732
                nfs4_bits = posix_nfs4map[i];
 
733
                posix_bit = rwx & posix_mask;
 
734
 
 
735
                if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
 
736
                        if (posix_bit)
 
737
                                aceMask |= nfs4_bits;
 
738
                        else
 
739
                                aceMask &= ~nfs4_bits;
 
740
                } else {
 
741
                        /* add deny bits when suitable */
 
742
                        if (!posix_bit)
 
743
                                aceMask |= nfs4_bits;
 
744
                        else
 
745
                                aceMask &= ~nfs4_bits;
 
746
                } /* other ace types are unexpected */
 
747
 
 
748
                posix_mask <<= 1;
 
749
        }
 
750
 
 
751
        return aceMask;
 
752
}
 
753
 
 
754
static int gpfsacl_emu_chmod(const char *path, mode_t mode)
 
755
{
 
756
        SMB4ACL_T *pacl = NULL;
 
757
        int     result;
 
758
        bool    haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
 
759
        int     i;
 
760
        files_struct    fake_fsp; /* TODO: rationalize parametrization */
 
761
        SMB4ACE_T       *smbace;
 
762
 
 
763
        DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
 
764
 
 
765
        result = gpfs_get_nfs4_acl(path, &pacl);
 
766
        if (result)
 
767
                return result;
 
768
 
 
769
        if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
 
770
                DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
 
771
        }
 
772
 
 
773
        for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
 
774
                SMB_ACE4PROP_T  *ace = smb_get_ace4(smbace);
 
775
                uint32_t        specid = ace->who.special_id;
 
776
 
 
777
                if (ace->flags&SMB_ACE4_ID_SPECIAL &&
 
778
                    ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
 
779
                    specid <= SMB_ACE4_WHO_EVERYONE) {
 
780
 
 
781
                        uint32_t newMask;
 
782
 
 
783
                        if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
 
784
                                haveAllowEntry[specid] = True;
 
785
 
 
786
                        /* mode >> 6 for @owner, mode >> 3 for @group,
 
787
                         * mode >> 0 for @everyone */
 
788
                        newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
 
789
                                                      mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
 
790
                        if (ace->aceMask!=newMask) {
 
791
                                DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
 
792
                                           path, ace->aceMask, newMask, specid));
 
793
                        }
 
794
                        ace->aceMask = newMask;
 
795
                }
 
796
        }
 
797
 
 
798
        /* make sure we have at least ALLOW entries
 
799
         * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
 
800
         * - if necessary
 
801
         */
 
802
        for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
 
803
                SMB_ACE4PROP_T  ace;
 
804
 
 
805
                if (haveAllowEntry[i]==True)
 
806
                        continue;
 
807
 
 
808
                ZERO_STRUCT(ace);
 
809
                ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
 
810
                ace.flags |= SMB_ACE4_ID_SPECIAL;
 
811
                ace.who.special_id = i;
 
812
 
 
813
                if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
 
814
                        ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
 
815
 
 
816
                ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
 
817
                                                  mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
 
818
 
 
819
                /* don't add unnecessary aces */
 
820
                if (!ace.aceMask)
 
821
                        continue;
 
822
 
 
823
                /* we add it to the END - as windows expects allow aces */
 
824
                smb_add_ace4(pacl, &ace);
 
825
                DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
 
826
                           path, mode, i, ace.aceMask));
 
827
        }
 
828
 
 
829
        /* don't add complementary DENY ACEs here */
 
830
        ZERO_STRUCT(fake_fsp);
 
831
        fake_fsp.fsp_name = (char *)path; /* no file_new is needed here */
 
832
 
 
833
        /* put the acl */
 
834
        if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False)
 
835
                return -1;
 
836
        return 0; /* ok for [f]chmod */
 
837
}
 
838
 
 
839
static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
 
840
{
 
841
                 SMB_STRUCT_STAT st;
 
842
                 int rc;
 
843
 
 
844
                 if (SMB_VFS_NEXT_STAT(handle, path, &st) != 0) {
 
845
                         return -1;
 
846
                 }
 
847
 
 
848
                 /* avoid chmod() if possible, to preserve acls */
 
849
                 if ((st.st_mode & ~S_IFMT) == mode) {
 
850
                         return 0;
 
851
                 }
 
852
 
 
853
                 rc = gpfsacl_emu_chmod(path, mode);
 
854
                 if (rc == 1)
 
855
                         return SMB_VFS_NEXT_CHMOD(handle, path, mode);
 
856
                 return rc;
 
857
}
 
858
 
 
859
static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
 
860
{
 
861
                 SMB_STRUCT_STAT st;
 
862
                 int rc;
 
863
 
 
864
                 if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
 
865
                         return -1;
 
866
                 }
 
867
 
 
868
                 /* avoid chmod() if possible, to preserve acls */
 
869
                 if ((st.st_mode & ~S_IFMT) == mode) {
 
870
                         return 0;
 
871
                 }
 
872
 
 
873
                 rc = gpfsacl_emu_chmod(fsp->fsp_name, mode);
 
874
                 if (rc == 1)
 
875
                         return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
 
876
                 return rc;
 
877
}
 
878
 
 
879
/* VFS operations structure */
 
880
 
 
881
static vfs_op_tuple gpfs_op_tuples[] = {
 
882
 
 
883
        { SMB_VFS_OP(vfs_gpfs_kernel_flock), 
 
884
          SMB_VFS_OP_KERNEL_FLOCK,
 
885
          SMB_VFS_LAYER_OPAQUE },
 
886
 
 
887
        { SMB_VFS_OP(vfs_gpfs_setlease), 
 
888
          SMB_VFS_OP_LINUX_SETLEASE,
 
889
          SMB_VFS_LAYER_OPAQUE },
 
890
 
 
891
        { SMB_VFS_OP(vfs_gpfs_get_real_filename),
 
892
          SMB_VFS_OP_GET_REAL_FILENAME,
 
893
          SMB_VFS_LAYER_OPAQUE },
 
894
 
 
895
        { SMB_VFS_OP(gpfsacl_fget_nt_acl), 
 
896
          SMB_VFS_OP_FGET_NT_ACL,
 
897
          SMB_VFS_LAYER_TRANSPARENT },
 
898
 
 
899
        { SMB_VFS_OP(gpfsacl_get_nt_acl), 
 
900
          SMB_VFS_OP_GET_NT_ACL,
 
901
          SMB_VFS_LAYER_TRANSPARENT },
 
902
 
 
903
        { SMB_VFS_OP(gpfsacl_fset_nt_acl), 
 
904
          SMB_VFS_OP_FSET_NT_ACL,
 
905
          SMB_VFS_LAYER_TRANSPARENT },
 
906
 
 
907
        { SMB_VFS_OP(gpfsacl_sys_acl_get_file), 
 
908
          SMB_VFS_OP_SYS_ACL_GET_FILE,
 
909
          SMB_VFS_LAYER_TRANSPARENT },
 
910
 
 
911
        { SMB_VFS_OP(gpfsacl_sys_acl_get_fd), 
 
912
          SMB_VFS_OP_SYS_ACL_GET_FD,
 
913
          SMB_VFS_LAYER_TRANSPARENT },
 
914
 
 
915
        { SMB_VFS_OP(gpfsacl_sys_acl_set_file), 
 
916
          SMB_VFS_OP_SYS_ACL_SET_FILE,
 
917
          SMB_VFS_LAYER_TRANSPARENT },
 
918
 
 
919
        { SMB_VFS_OP(gpfsacl_sys_acl_set_fd), 
 
920
          SMB_VFS_OP_SYS_ACL_SET_FD,
 
921
          SMB_VFS_LAYER_TRANSPARENT },
 
922
 
 
923
        { SMB_VFS_OP(gpfsacl_sys_acl_delete_def_file),
 
924
          SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
 
925
          SMB_VFS_LAYER_TRANSPARENT },
 
926
 
 
927
        { SMB_VFS_OP(vfs_gpfs_chmod), 
 
928
          SMB_VFS_OP_CHMOD,
 
929
          SMB_VFS_LAYER_TRANSPARENT },
 
930
 
 
931
        { SMB_VFS_OP(vfs_gpfs_fchmod), 
 
932
          SMB_VFS_OP_FCHMOD,
 
933
          SMB_VFS_LAYER_TRANSPARENT },
 
934
 
 
935
        { SMB_VFS_OP(vfs_gpfs_close),
 
936
          SMB_VFS_OP_CLOSE,
 
937
          SMB_VFS_LAYER_TRANSPARENT },
 
938
 
 
939
        { SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP }
 
940
 
 
941
};
 
942
 
 
943
 
 
944
NTSTATUS vfs_gpfs_init(void);
 
945
NTSTATUS vfs_gpfs_init(void)
 
946
{
 
947
        init_gpfs();
 
948
 
 
949
        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs",
 
950
                                gpfs_op_tuples);
 
951
}