s3-vfs_gpfs: Fix bug #9003, posix acl on gpfs
[samba.git] / source3 / modules / vfs_gpfs.c
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 struct gpfs_config_data {
34         bool sharemodes;
35         bool leases;
36 };
37
38
39 static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, 
40                                  uint32 share_mode, uint32 access_mask)
41 {
42
43         struct gpfs_config_data *config;
44
45         SMB_VFS_HANDLE_GET_DATA(handle, config,
46                                 struct gpfs_config_data,
47                                 return -1);
48
49         START_PROFILE(syscall_kernel_flock);
50
51         kernel_flock(fsp->fh->fd, share_mode, access_mask);
52
53         if (config->sharemodes
54                 && !set_gpfs_sharemode(fsp, access_mask, fsp->share_access)) {
55                 return -1;
56         }
57
58         END_PROFILE(syscall_kernel_flock);
59
60         return 0;
61 }
62
63 static int vfs_gpfs_close(vfs_handle_struct *handle, files_struct *fsp)
64 {
65
66         struct gpfs_config_data *config;
67
68         SMB_VFS_HANDLE_GET_DATA(handle, config,
69                                 struct gpfs_config_data,
70                                 return -1);
71
72         if (config->sharemodes && (fsp->fh != NULL) && (fsp->fh->fd != -1)) {
73                 set_gpfs_sharemode(fsp, 0, 0);
74         }
75
76         return SMB_VFS_NEXT_CLOSE(handle, fsp);
77 }
78
79 static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, 
80                              int leasetype)
81 {
82         struct gpfs_config_data *config;
83         int ret=0;
84
85         SMB_VFS_HANDLE_GET_DATA(handle, config,
86                                 struct gpfs_config_data,
87                                 return -1);
88
89         START_PROFILE(syscall_linux_setlease);
90
91         if (linux_set_lease_sighandler(fsp->fh->fd) == -1)
92                 return -1;
93
94         if (config->leases) {
95                 ret = set_gpfs_lease(fsp->fh->fd,leasetype);
96         }
97
98         if (ret < 0) {
99                 /* This must have come from GPFS not being available */
100                 /* or some other error, hence call the default */
101                 ret = linux_setlease(fsp->fh->fd, leasetype);
102         }
103
104         END_PROFILE(syscall_linux_setlease);
105
106         return ret;
107 }
108
109 static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
110                                       const char *path,
111                                       const char *name,
112                                       TALLOC_CTX *mem_ctx,
113                                       char **found_name)
114 {
115         int result;
116         char *full_path;
117         char real_pathname[PATH_MAX+1];
118         int buflen;
119
120         full_path = talloc_asprintf(talloc_tos(), "%s/%s", path, name);
121         if (full_path == NULL) {
122                 errno = ENOMEM;
123                 return -1;
124         }
125
126         buflen = sizeof(real_pathname) - 1;
127
128         result = smbd_gpfs_get_realfilename_path(full_path, real_pathname,
129                                                  &buflen);
130
131         TALLOC_FREE(full_path);
132
133         if ((result == -1) && (errno == ENOSYS)) {
134                 return SMB_VFS_NEXT_GET_REAL_FILENAME(
135                         handle, path, name, mem_ctx, found_name);
136         }
137
138         if (result == -1) {
139                 DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n",
140                            strerror(errno)));
141                 return -1;
142         }
143
144         /*
145          * GPFS does not necessarily null-terminate the returned path
146          * but instead returns the buffer length in buflen.
147          */
148
149         if (buflen < sizeof(real_pathname)) {
150                 real_pathname[buflen] = '\0';
151         } else {
152                 real_pathname[sizeof(real_pathname)-1] = '\0';
153         }
154
155         DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n",
156                    path, name, real_pathname));
157
158         name = strrchr_m(real_pathname, '/');
159         if (name == NULL) {
160                 errno = ENOENT;
161                 return -1;
162         }
163
164         *found_name = talloc_strdup(mem_ctx, name+1);
165         if (*found_name == NULL) {
166                 errno = ENOMEM;
167                 return -1;
168         }
169
170         return 0;
171 }
172
173 static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
174 {
175         int     i;
176         if (gacl==NULL)
177         {
178                 DEBUG(0, ("gpfs acl is NULL\n"));
179                 return;
180         }
181
182         DEBUG(level, ("gpfs acl: nace: %d, type:%d, version:%d, level:%d, len:%d\n",
183                 gacl->acl_nace, gacl->acl_type, gacl->acl_version, gacl->acl_level, gacl->acl_len));
184         for(i=0; i<gacl->acl_nace; i++)
185         {
186                 struct gpfs_ace_v4 *gace = gacl->ace_v4 + i;
187                 DEBUG(level, ("\tace[%d]: type:%d, flags:0x%x, mask:0x%x, iflags:0x%x, who:%u\n",
188                         i, gace->aceType, gace->aceFlags, gace->aceMask,
189                         gace->aceIFlags, gace->aceWho));
190         }
191 }
192
193 static struct gpfs_acl *gpfs_getacl_alloc(const char *fname, gpfs_aclType_t type)
194 {
195         struct gpfs_acl *acl;
196         size_t len = 200;
197         int ret;
198         TALLOC_CTX *mem_ctx = talloc_tos();
199
200         acl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, len);
201         if (acl == NULL) {
202                 errno = ENOMEM;
203                 return NULL;
204         }
205
206         acl->acl_len = len;
207         acl->acl_level = 0;
208         acl->acl_version = 0;
209         acl->acl_type = type;
210
211         ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
212         if ((ret != 0) && (errno == ENOSPC)) {
213                 struct gpfs_acl *new_acl = (struct gpfs_acl *)TALLOC_SIZE(
214                         mem_ctx, acl->acl_len + sizeof(struct gpfs_acl));
215                 if (new_acl == NULL) {
216                         errno = ENOMEM;
217                         return NULL;
218                 }
219
220                 new_acl->acl_len = acl->acl_len;
221                 new_acl->acl_level = acl->acl_level;
222                 new_acl->acl_version = acl->acl_version;
223                 new_acl->acl_type = acl->acl_type;
224                 acl = new_acl;
225
226                 ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
227         }
228         if (ret != 0)
229         {
230                 DEBUG(8, ("smbd_gpfs_getacl failed with %s\n",strerror(errno)));
231                 return NULL;
232         }
233
234         return acl;
235 }
236
237 /* Tries to get nfs4 acls and returns SMB ACL allocated.
238  * On failure returns 1 if it got non-NFSv4 ACL to prompt 
239  * retry with POSIX ACL checks.
240  * On failure returns -1 if there is system (GPFS) error, check errno.
241  * Returns 0 on success
242  */
243 static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
244 {
245         int i;
246         struct gpfs_acl *gacl = NULL;
247         DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
248
249         /* First get the real acl length */
250         gacl = gpfs_getacl_alloc(fname, 0);
251         if (gacl == NULL) {
252                 DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
253                            fname, strerror(errno)));
254                 return -1;
255         }
256
257         if (gacl->acl_type != GPFS_ACL_TYPE_NFS4) {
258                 DEBUG(10, ("Got non-nfsv4 acl\n"));
259                 /* Retry with POSIX ACLs check */
260                 return 1;
261         }
262
263         *ppacl = smb_create_smb4acl();
264
265         DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
266                    gacl->acl_len, gacl->acl_level, gacl->acl_version,
267                    gacl->acl_nace));
268
269         for (i=0; i<gacl->acl_nace; i++) {
270                 struct gpfs_ace_v4 *gace = &gacl->ace_v4[i];
271                 SMB_ACE4PROP_T smbace;
272                 DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
273                            "who: %d\n", gace->aceType, gace->aceIFlags,
274                            gace->aceFlags, gace->aceMask, gace->aceWho));
275
276                 ZERO_STRUCT(smbace);
277                 if (gace->aceIFlags & ACE4_IFLAG_SPECIAL_ID) {
278                         smbace.flags |= SMB_ACE4_ID_SPECIAL;
279                         switch (gace->aceWho) {
280                         case ACE4_SPECIAL_OWNER:
281                                 smbace.who.special_id = SMB_ACE4_WHO_OWNER;
282                                 break;
283                         case ACE4_SPECIAL_GROUP:
284                                 smbace.who.special_id = SMB_ACE4_WHO_GROUP;
285                                 break;
286                         case ACE4_SPECIAL_EVERYONE:
287                                 smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
288                                 break;
289                         default:
290                                 DEBUG(8, ("invalid special gpfs id %d "
291                                           "ignored\n", gace->aceWho));
292                                 continue; /* don't add it */
293                         }
294                 } else {
295                         if (gace->aceFlags & ACE4_FLAG_GROUP_ID)
296                                 smbace.who.gid = gace->aceWho;
297                         else
298                                 smbace.who.uid = gace->aceWho;
299                 }
300
301                 /* remove redundent deny entries */
302                 if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
303                         struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1];
304                         if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
305                             prev->aceFlags == gace->aceFlags &&
306                             prev->aceIFlags == gace->aceIFlags &&
307                             (gace->aceMask & prev->aceMask) == 0 &&
308                             gace->aceWho == prev->aceWho) {
309                                 /* its redundent - skip it */
310                                 continue;
311                         }                                                
312                 }
313
314                 smbace.aceType = gace->aceType;
315                 smbace.aceFlags = gace->aceFlags;
316                 smbace.aceMask = gace->aceMask;
317                 smb_add_ace4(*ppacl, &smbace);
318         }
319
320         return 0;
321 }
322
323 static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
324         files_struct *fsp, uint32 security_info,
325         SEC_DESC **ppdesc)
326 {
327         SMB4ACL_T *pacl = NULL;
328         int     result;
329
330         *ppdesc = NULL;
331         result = gpfs_get_nfs4_acl(fsp->fsp_name->base_name, &pacl);
332
333         if (result == 0)
334                 return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
335
336         if (result > 0) {
337                 DEBUG(10, ("retrying with posix acl...\n"));
338                 return posix_fget_nt_acl(fsp, security_info, ppdesc);
339         }
340
341         /* GPFS ACL was not read, something wrong happened, error code is set in errno */
342         return map_nt_error_from_unix(errno);
343 }
344
345 static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
346         const char *name,
347         uint32 security_info, SEC_DESC **ppdesc)
348 {
349         SMB4ACL_T *pacl = NULL;
350         int     result;
351
352         *ppdesc = NULL;
353         result = gpfs_get_nfs4_acl(name, &pacl);
354
355         if (result == 0)
356                 return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl);
357
358         if (result > 0) {
359                 DEBUG(10, ("retrying with posix acl...\n"));
360                 return posix_get_nt_acl(handle->conn, name, security_info, ppdesc);
361         }
362
363         /* GPFS ACL was not read, something wrong happened, error code is set in errno */
364         return map_nt_error_from_unix(errno);
365 }
366
367 static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
368 {
369         int ret;
370         gpfs_aclLen_t gacl_len;
371         SMB4ACE_T       *smbace;
372         struct gpfs_acl *gacl;
373         TALLOC_CTX *mem_ctx  = talloc_tos();
374
375         gacl_len = sizeof(struct gpfs_acl) +
376                 (smb_get_naces(smbacl)-1)*sizeof(gpfs_ace_v4_t);
377
378         gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len);
379         if (gacl == NULL) {
380                 DEBUG(0, ("talloc failed\n"));
381                 errno = ENOMEM;
382                 return False;
383         }
384
385         gacl->acl_len = gacl_len;
386         gacl->acl_level = 0;
387         gacl->acl_version = GPFS_ACL_VERSION_NFS4;
388         gacl->acl_type = GPFS_ACL_TYPE_NFS4;
389         gacl->acl_nace = 0; /* change later... */
390
391         for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
392                 struct gpfs_ace_v4 *gace = &gacl->ace_v4[gacl->acl_nace];
393                 SMB_ACE4PROP_T  *aceprop = smb_get_ace4(smbace);
394
395                 gace->aceType = aceprop->aceType;
396                 gace->aceFlags = aceprop->aceFlags;
397                 gace->aceMask = aceprop->aceMask;
398
399                 /*
400                  * GPFS can't distinguish between WRITE and APPEND on
401                  * files, so one being set without the other is an
402                  * error. Sorry for the many ()'s :-)
403                  */
404
405                 if (!fsp->is_directory
406                     &&
407                     ((((gace->aceMask & ACE4_MASK_WRITE) == 0)
408                       && ((gace->aceMask & ACE4_MASK_APPEND) != 0))
409                      ||
410                      (((gace->aceMask & ACE4_MASK_WRITE) != 0)
411                       && ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
412                     &&
413                     lp_parm_bool(fsp->conn->params->service, "gpfs",
414                                  "merge_writeappend", True)) {
415                         DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
416                                   "WRITE^APPEND, setting WRITE|APPEND\n",
417                                   fsp_str_dbg(fsp)));
418                         gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
419                 }
420
421                 gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;
422
423                 if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
424                 {
425                         switch(aceprop->who.special_id)
426                         {
427                         case SMB_ACE4_WHO_EVERYONE:
428                                 gace->aceWho = ACE4_SPECIAL_EVERYONE;
429                                 break;
430                         case SMB_ACE4_WHO_OWNER:
431                                 gace->aceWho = ACE4_SPECIAL_OWNER;
432                                 break;
433                         case SMB_ACE4_WHO_GROUP:
434                                 gace->aceWho = ACE4_SPECIAL_GROUP;
435                                 break;
436                         default:
437                                 DEBUG(8, ("unsupported special_id %d\n", aceprop->who.special_id));
438                                 continue; /* don't add it !!! */
439                         }
440                 } else {
441                         /* just only for the type safety... */
442                         if (aceprop->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
443                                 gace->aceWho = aceprop->who.gid;
444                         else
445                                 gace->aceWho = aceprop->who.uid;
446                 }
447
448                 gacl->acl_nace++;
449         }
450
451         ret = smbd_gpfs_putacl(fsp->fsp_name->base_name,
452                                GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
453         if (ret != 0) {
454                 DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
455                 gpfs_dumpacl(8, gacl);
456                 return False;
457         }
458
459         DEBUG(10, ("gpfs_putacl succeeded\n"));
460         return True;
461 }
462
463 static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd)
464 {
465         struct gpfs_acl *acl;
466         NTSTATUS result = NT_STATUS_ACCESS_DENIED;
467
468         acl = gpfs_getacl_alloc(fsp->fsp_name->base_name, 0);
469         if (acl == NULL)
470                 return result;
471
472         if (acl->acl_version&GPFS_ACL_VERSION_NFS4)
473         {
474                 if (lp_parm_bool(fsp->conn->params->service, "gpfs",
475                                  "refuse_dacl_protected", false)
476                     && (psd->type&SEC_DESC_DACL_PROTECTED)) {
477                         DEBUG(2, ("Rejecting unsupported ACL with DACL_PROTECTED bit set\n"));
478                         return NT_STATUS_NOT_SUPPORTED;
479                 }
480
481                 result = smb_set_nt_acl_nfs4(
482                         fsp, security_info_sent, psd,
483                         gpfsacl_process_smbacl);
484         } else { /* assume POSIX ACL - by default... */
485                 result = set_nt_acl(fsp, security_info_sent, psd);
486         }
487
488         return result;
489 }
490
491 static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd)
492 {
493         return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd);
494 }
495
496 static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl)
497 {
498         SMB_ACL_T result;
499         int i;
500
501         result = sys_acl_init(pacl->acl_nace);
502         if (result == NULL) {
503                 errno = ENOMEM;
504                 return NULL;
505         }
506
507         result->count = pacl->acl_nace;
508
509         for (i=0; i<pacl->acl_nace; i++) {
510                 struct smb_acl_entry *ace = &result->acl[i];
511                 const struct gpfs_ace_v1 *g_ace = &pacl->ace_v1[i];
512
513                 DEBUG(10, ("Converting type %d id %lu perm %x\n",
514                            (int)g_ace->ace_type, (unsigned long)g_ace->ace_who,
515                            (int)g_ace->ace_perm));
516
517                 switch (g_ace->ace_type) {
518                 case GPFS_ACL_USER:
519                         ace->a_type = SMB_ACL_USER;
520                         ace->uid = (uid_t)g_ace->ace_who;
521                         break;
522                 case GPFS_ACL_USER_OBJ:
523                         ace->a_type = SMB_ACL_USER_OBJ;
524                         break;
525                 case GPFS_ACL_GROUP:
526                         ace->a_type = SMB_ACL_GROUP;
527                         ace->gid = (gid_t)g_ace->ace_who;
528                         break;
529                 case GPFS_ACL_GROUP_OBJ:
530                         ace->a_type = SMB_ACL_GROUP_OBJ;
531                         break;
532                 case GPFS_ACL_OTHER:
533                         ace->a_type = SMB_ACL_OTHER;
534                         break;
535                 case GPFS_ACL_MASK:
536                         ace->a_type = SMB_ACL_MASK;
537                         break;
538                 default:
539                         DEBUG(10, ("Got invalid ace_type: %d\n",
540                                    g_ace->ace_type));
541                         errno = EINVAL;
542                         SAFE_FREE(result);
543                         return NULL;
544                 }
545
546                 ace->a_perm = 0;
547                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_READ) ?
548                         SMB_ACL_READ : 0;
549                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_WRITE) ?
550                         SMB_ACL_WRITE : 0;
551                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_EXECUTE) ?
552                         SMB_ACL_EXECUTE : 0;
553
554                 DEBUGADD(10, ("Converted to %d perm %x\n",
555                               ace->a_type, ace->a_perm));
556         }
557
558         return result;
559 }
560
561 static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type)
562 {
563         struct gpfs_acl *pacl;
564         SMB_ACL_T result = NULL;
565
566         pacl = gpfs_getacl_alloc(path, type);
567
568         if (pacl == NULL) {
569                 DEBUG(10, ("gpfs_getacl failed for %s with %s\n",
570                            path, strerror(errno)));
571                 if (errno == 0) {
572                         errno = EINVAL;
573                 }
574                 goto done;
575         }
576
577         if (pacl->acl_version != GPFS_ACL_VERSION_POSIX) {
578                 DEBUG(10, ("Got acl version %d, expected %d\n",
579                            pacl->acl_version, GPFS_ACL_VERSION_POSIX));
580                 errno = EINVAL;
581                 goto done;
582         }
583
584         DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
585                    pacl->acl_len, pacl->acl_level, pacl->acl_version,
586                    pacl->acl_nace));
587
588         result = gpfs2smb_acl(pacl);
589         if (result != NULL) {
590                 errno = 0;
591         }
592
593  done:
594
595         if (errno != 0) {
596                 SAFE_FREE(result);
597         }
598         return result;  
599 }
600
601 static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
602                                           const char *path_p,
603                                           SMB_ACL_TYPE_T type)
604 {
605         gpfs_aclType_t gpfs_type;
606
607         switch(type) {
608         case SMB_ACL_TYPE_ACCESS:
609                 gpfs_type = GPFS_ACL_TYPE_ACCESS;
610                 break;
611         case SMB_ACL_TYPE_DEFAULT:
612                 gpfs_type = GPFS_ACL_TYPE_DEFAULT;
613                 break;
614         default:
615                 DEBUG(0, ("Got invalid type: %d\n", type));
616                 smb_panic("exiting");
617         }
618
619         return gpfsacl_get_posix_acl(path_p, gpfs_type);
620 }
621
622 static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
623                                         files_struct *fsp)
624 {
625         return gpfsacl_get_posix_acl(fsp->fsp_name->base_name,
626                                      GPFS_ACL_TYPE_ACCESS);
627 }
628
629 static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
630                                      SMB_ACL_TYPE_T type)
631 {
632         gpfs_aclLen_t len;
633         struct gpfs_acl *result;
634         int i;
635         union gpfs_ace_union
636         {
637                 gpfs_ace_v1_t  ace_v1[1]; /* when GPFS_ACL_VERSION_POSIX */
638                 gpfs_ace_v4_t  ace_v4[1]; /* when GPFS_ACL_VERSION_NFS4  */
639         };
640
641         DEBUG(10, ("smb2gpfs_acl: Got ACL with %d entries\n", pacl->count));
642
643         len = sizeof(struct gpfs_acl) - sizeof(union gpfs_ace_union) +
644                 (pacl->count)*sizeof(gpfs_ace_v1_t);
645
646         result = (struct gpfs_acl *)SMB_MALLOC(len);
647         if (result == NULL) {
648                 errno = ENOMEM;
649                 return result;
650         }
651
652         result->acl_len = len;
653         result->acl_level = 0;
654         result->acl_version = GPFS_ACL_VERSION_POSIX;
655         result->acl_type = (type == SMB_ACL_TYPE_DEFAULT) ?
656                 GPFS_ACL_TYPE_DEFAULT : GPFS_ACL_TYPE_ACCESS;
657         result->acl_nace = pacl->count;
658
659         for (i=0; i<pacl->count; i++) {
660                 const struct smb_acl_entry *ace = &pacl->acl[i];
661                 struct gpfs_ace_v1 *g_ace = &result->ace_v1[i];
662
663                 DEBUG(10, ("Converting type %d perm %x\n",
664                            (int)ace->a_type, (int)ace->a_perm));
665
666                 g_ace->ace_perm = 0;
667
668                 switch(ace->a_type) {
669                 case SMB_ACL_USER:
670                         g_ace->ace_type = GPFS_ACL_USER;
671                         g_ace->ace_who = (gpfs_uid_t)ace->uid;
672                         break;
673                 case SMB_ACL_USER_OBJ:
674                         g_ace->ace_type = GPFS_ACL_USER_OBJ;
675                         g_ace->ace_perm |= ACL_PERM_CONTROL;
676                         g_ace->ace_who = 0;
677                         break;
678                 case SMB_ACL_GROUP:
679                         g_ace->ace_type = GPFS_ACL_GROUP;
680                         g_ace->ace_who = (gpfs_uid_t)ace->gid;
681                         break;
682                 case SMB_ACL_GROUP_OBJ:
683                         g_ace->ace_type = GPFS_ACL_GROUP_OBJ;
684                         g_ace->ace_who = 0;
685                         break;
686                 case SMB_ACL_MASK:
687                         g_ace->ace_type = GPFS_ACL_MASK;
688                         g_ace->ace_perm = 0x8f;
689                         g_ace->ace_who = 0;
690                         break;
691                 case SMB_ACL_OTHER:
692                         g_ace->ace_type = GPFS_ACL_OTHER;
693                         g_ace->ace_who = 0;
694                         break;
695                 default:
696                         DEBUG(10, ("Got invalid ace_type: %d\n", ace->a_type));
697                         errno = EINVAL;
698                         SAFE_FREE(result);
699                         return NULL;
700                 }
701
702                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_READ) ?
703                         ACL_PERM_READ : 0;
704                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_WRITE) ?
705                         ACL_PERM_WRITE : 0;
706                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_EXECUTE) ?
707                         ACL_PERM_EXECUTE : 0;
708
709                 DEBUGADD(10, ("Converted to %d id %d perm %x\n",
710                               g_ace->ace_type, g_ace->ace_who, g_ace->ace_perm));
711         }
712
713         return result;
714 }
715
716 static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
717                                     const char *name,
718                                     SMB_ACL_TYPE_T type,
719                                     SMB_ACL_T theacl)
720 {
721         struct gpfs_acl *gpfs_acl;
722         int result;
723
724         gpfs_acl = smb2gpfs_acl(theacl, type);
725         if (gpfs_acl == NULL) {
726                 return -1;
727         }
728
729         result = smbd_gpfs_putacl((char *)name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gpfs_acl);
730
731         SAFE_FREE(gpfs_acl);
732         return result;
733 }
734
735 static int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
736                                   files_struct *fsp,
737                                   SMB_ACL_T theacl)
738 {
739         return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name->base_name,
740                                         SMB_ACL_TYPE_ACCESS, theacl);
741 }
742
743 static int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
744                                            const char *path)
745 {
746         errno = ENOTSUP;
747         return -1;
748 }
749
750 /*
751  * Assumed: mode bits are shiftable and standard
752  * Output: the new aceMask field for an smb nfs4 ace
753  */
754 static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx)
755 {
756         const uint32 posix_nfs4map[3] = {
757                 SMB_ACE4_EXECUTE, /* execute */
758                 SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
759                 SMB_ACE4_READ_DATA /* read */
760         };
761         int     i;
762         uint32_t        posix_mask = 0x01;
763         uint32_t        posix_bit;
764         uint32_t        nfs4_bits;
765
766         for(i=0; i<3; i++) {
767                 nfs4_bits = posix_nfs4map[i];
768                 posix_bit = rwx & posix_mask;
769
770                 if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
771                         if (posix_bit)
772                                 aceMask |= nfs4_bits;
773                         else
774                                 aceMask &= ~nfs4_bits;
775                 } else {
776                         /* add deny bits when suitable */
777                         if (!posix_bit)
778                                 aceMask |= nfs4_bits;
779                         else
780                                 aceMask &= ~nfs4_bits;
781                 } /* other ace types are unexpected */
782
783                 posix_mask <<= 1;
784         }
785
786         return aceMask;
787 }
788
789 static int gpfsacl_emu_chmod(const char *path, mode_t mode)
790 {
791         SMB4ACL_T *pacl = NULL;
792         int     result;
793         bool    haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
794         int     i;
795         files_struct    fake_fsp; /* TODO: rationalize parametrization */
796         SMB4ACE_T       *smbace;
797         NTSTATUS status;
798
799         DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
800
801         result = gpfs_get_nfs4_acl(path, &pacl);
802         if (result)
803                 return result;
804
805         if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
806                 DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
807         }
808
809         for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
810                 SMB_ACE4PROP_T  *ace = smb_get_ace4(smbace);
811                 uint32_t        specid = ace->who.special_id;
812
813                 if (ace->flags&SMB_ACE4_ID_SPECIAL &&
814                     ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
815                     specid <= SMB_ACE4_WHO_EVERYONE) {
816
817                         uint32_t newMask;
818
819                         if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
820                                 haveAllowEntry[specid] = True;
821
822                         /* mode >> 6 for @owner, mode >> 3 for @group,
823                          * mode >> 0 for @everyone */
824                         newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
825                                                       mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
826                         if (ace->aceMask!=newMask) {
827                                 DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
828                                            path, ace->aceMask, newMask, specid));
829                         }
830                         ace->aceMask = newMask;
831                 }
832         }
833
834         /* make sure we have at least ALLOW entries
835          * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
836          * - if necessary
837          */
838         for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
839                 SMB_ACE4PROP_T  ace;
840
841                 if (haveAllowEntry[i]==True)
842                         continue;
843
844                 ZERO_STRUCT(ace);
845                 ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
846                 ace.flags |= SMB_ACE4_ID_SPECIAL;
847                 ace.who.special_id = i;
848
849                 if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
850                         ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
851
852                 ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
853                                                   mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
854
855                 /* don't add unnecessary aces */
856                 if (!ace.aceMask)
857                         continue;
858
859                 /* we add it to the END - as windows expects allow aces */
860                 smb_add_ace4(pacl, &ace);
861                 DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
862                            path, mode, i, ace.aceMask));
863         }
864
865         /* don't add complementary DENY ACEs here */
866         ZERO_STRUCT(fake_fsp);
867         status = create_synthetic_smb_fname(talloc_tos(), path, NULL, NULL,
868                                             &fake_fsp.fsp_name);
869         if (!NT_STATUS_IS_OK(status)) {
870                 errno = map_errno_from_nt_status(status);
871                 return -1;
872         }
873         /* put the acl */
874         if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False) {
875                 TALLOC_FREE(fake_fsp.fsp_name);
876                 return -1;
877         }
878
879         TALLOC_FREE(fake_fsp.fsp_name);
880         return 0; /* ok for [f]chmod */
881 }
882
883 static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
884 {
885         struct smb_filename *smb_fname_cpath;
886         int rc;
887         NTSTATUS status;
888
889         status = create_synthetic_smb_fname(
890                 talloc_tos(), path, NULL, NULL, &smb_fname_cpath);
891
892         if (SMB_VFS_NEXT_STAT(handle, smb_fname_cpath) != 0) {
893                 return -1;
894         }
895
896         /* avoid chmod() if possible, to preserve acls */
897         if ((smb_fname_cpath->st.st_ex_mode & ~S_IFMT) == mode) {
898                 return 0;
899         }
900
901         rc = gpfsacl_emu_chmod(path, mode);
902         if (rc == 1)
903                 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
904         return rc;
905 }
906
907 static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
908 {
909                  SMB_STRUCT_STAT st;
910                  int rc;
911
912                  if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
913                          return -1;
914                  }
915
916                  /* avoid chmod() if possible, to preserve acls */
917                  if ((st.st_ex_mode & ~S_IFMT) == mode) {
918                          return 0;
919                  }
920
921                  rc = gpfsacl_emu_chmod(fsp->fsp_name->base_name, mode);
922                  if (rc == 1)
923                          return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
924                  return rc;
925 }
926
927 static int gpfs_set_xattr(struct vfs_handle_struct *handle,  const char *path,
928                            const char *name, const void *value, size_t size,  int flags){
929         const char *attrstr = value;
930         unsigned int dosmode=0;
931         struct gpfs_winattr attrs;
932         int ret = 0;
933
934         DEBUG(10, ("gpfs_set_xattr: %s \n",path));
935
936         /* Only handle DOS Attributes */
937         if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
938                 DEBUG(1, ("gpfs_set_xattr:name is %s\n",name));
939                 return SMB_VFS_NEXT_SETXATTR(handle,path,name,value,size,flags);
940         }
941
942         if (size < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
943                                 sscanf(attrstr, "%x", &dosmode) != 1) {
944                         DEBUG(1,("gpfs_set_xattr: Trying to set badly formed DOSATTRIB on file %s - %s\n", path, attrstr));
945                 return False;
946         }
947
948         attrs.winAttrs = 0;
949         /*Just map RD_ONLY, ARCHIVE, SYSTEM and HIDDEN. Ignore the others*/
950         if (dosmode & FILE_ATTRIBUTE_ARCHIVE){
951                 attrs.winAttrs |= GPFS_WINATTR_ARCHIVE;
952         }
953         if (dosmode & FILE_ATTRIBUTE_HIDDEN){
954                         attrs.winAttrs |= GPFS_WINATTR_HIDDEN;
955                 }
956         if (dosmode & FILE_ATTRIBUTE_SYSTEM){
957                         attrs.winAttrs |= GPFS_WINATTR_SYSTEM;
958                 }
959         if (dosmode & FILE_ATTRIBUTE_READONLY){
960                         attrs.winAttrs |= GPFS_WINATTR_READONLY;
961         }
962
963
964         ret = set_gpfs_winattrs(CONST_DISCARD(char *, path),
965                                 GPFS_WINATTR_SET_ATTRS, &attrs);
966         if ( ret == -1){
967                 if (errno == ENOSYS) {
968                         return SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
969                                                      size, flags);
970                 }
971
972                 DEBUG(1, ("gpfs_set_xattr:Set GPFS attributes failed %d\n",ret));
973                 return -1;
974         }
975
976         DEBUG(10, ("gpfs_set_xattr:Set attributes: 0x%x\n",attrs.winAttrs));
977         return 0;
978 }
979
980 static ssize_t gpfs_get_xattr(struct vfs_handle_struct *handle,  const char *path,
981                               const char *name, void *value, size_t size){
982         char *attrstr = value;
983         unsigned int dosmode = 0;
984         struct gpfs_winattr attrs;
985         int ret = 0;
986         ssize_t result;
987
988         DEBUG(10, ("gpfs_get_xattr: %s \n",path));
989
990         /* Only handle DOS Attributes */
991         if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
992                 DEBUG(1, ("gpfs_get_xattr:name is %s\n",name));
993                 return SMB_VFS_NEXT_GETXATTR(handle,path,name,value,size);
994         }
995
996         ret = get_gpfs_winattrs(CONST_DISCARD(char *, path), &attrs);
997         if ( ret == -1){
998                 if (errno == ENOSYS) {
999                         return SMB_VFS_NEXT_GETXATTR(handle, path, name, value,
1000                                                      size);
1001                 }
1002
1003                 DEBUG(1, ("gpfs_get_xattr: Get GPFS attributes failed: %d\n",ret));
1004                 return -1;
1005         }
1006
1007         DEBUG(10, ("gpfs_get_xattr:Got attributes: 0x%x\n",attrs.winAttrs));
1008
1009         /*Just map RD_ONLY, ARCHIVE, SYSTEM and HIDDEN. Ignore the others*/
1010         if (attrs.winAttrs & GPFS_WINATTR_ARCHIVE){
1011                 dosmode |= FILE_ATTRIBUTE_ARCHIVE;
1012         }
1013         if (attrs.winAttrs & GPFS_WINATTR_HIDDEN){
1014                 dosmode |= FILE_ATTRIBUTE_HIDDEN;
1015         }
1016         if (attrs.winAttrs & GPFS_WINATTR_SYSTEM){
1017                 dosmode |= FILE_ATTRIBUTE_SYSTEM;
1018         }
1019         if (attrs.winAttrs & GPFS_WINATTR_READONLY){
1020                 dosmode |= FILE_ATTRIBUTE_READONLY;
1021         }
1022
1023         result = snprintf(attrstr, size, "0x%x",
1024                           dosmode & SAMBA_ATTRIBUTES_MASK) + 1;
1025
1026         DEBUG(10, ("gpfs_get_xattr: returning %s\n",attrstr));
1027         return result;
1028 }
1029
1030 static int vfs_gpfs_stat(struct vfs_handle_struct *handle,
1031                          struct smb_filename *smb_fname)
1032 {
1033         struct gpfs_winattr attrs;
1034         char *fname = NULL;
1035         NTSTATUS status;
1036         int ret;
1037
1038         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1039         if (ret == -1) {
1040                 return -1;
1041         }
1042         status = get_full_smb_filename(talloc_tos(), smb_fname, &fname);
1043         if (!NT_STATUS_IS_OK(status)) {
1044                 errno = map_errno_from_nt_status(status);
1045                 return -1;
1046         }
1047         ret = get_gpfs_winattrs(CONST_DISCARD(char *, fname), &attrs);
1048         TALLOC_FREE(fname);
1049         if (ret == 0) {
1050                 smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1051                 smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1052         }
1053         return 0;
1054 }
1055
1056 static int vfs_gpfs_fstat(struct vfs_handle_struct *handle,
1057                           struct files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1058 {
1059         struct gpfs_winattr attrs;
1060         int ret;
1061
1062         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1063         if (ret == -1) {
1064                 return -1;
1065         }
1066         if ((fsp->fh == NULL) || (fsp->fh->fd == -1)) {
1067                 return 0;
1068         }
1069         ret = smbd_fget_gpfs_winattrs(fsp->fh->fd, &attrs);
1070         if (ret == 0) {
1071                 sbuf->st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1072                 sbuf->st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1073         }
1074         return 0;
1075 }
1076
1077 static int vfs_gpfs_lstat(struct vfs_handle_struct *handle,
1078                           struct smb_filename *smb_fname)
1079 {
1080         struct gpfs_winattr attrs;
1081         char *path = NULL;
1082         NTSTATUS status;
1083         int ret;
1084
1085         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1086         if (ret == -1) {
1087                 return -1;
1088         }
1089         status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1090         if (!NT_STATUS_IS_OK(status)) {
1091                 errno = map_errno_from_nt_status(status);
1092                 return -1;
1093         }
1094         ret = get_gpfs_winattrs(CONST_DISCARD(char *, path), &attrs);
1095         TALLOC_FREE(path);
1096         if (ret == 0) {
1097                 smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1098                 smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1099         }
1100         return 0;
1101 }
1102
1103 static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
1104                         const struct smb_filename *smb_fname,
1105                         struct smb_file_time *ft)
1106 {
1107
1108         struct gpfs_winattr attrs;
1109         int ret;
1110         char *path = NULL;
1111         NTSTATUS status;
1112
1113         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1114         if(ret == -1){
1115                 DEBUG(1,("vfs_gpfs_ntimes: SMB_VFS_NEXT_NTIMES failed\n"));
1116                 return -1;
1117         }
1118
1119         if(null_timespec(ft->create_time)){
1120                 DEBUG(10,("vfs_gpfs_ntimes:Create Time is NULL\n"));
1121                 return 0;
1122         }
1123
1124         status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1125         if (!NT_STATUS_IS_OK(status)) {
1126                 errno = map_errno_from_nt_status(status);
1127                 return -1;
1128         }
1129
1130         attrs.winAttrs = 0;
1131         attrs.creationTime.tv_sec = ft->create_time.tv_sec;
1132         attrs.creationTime.tv_nsec = ft->create_time.tv_nsec;
1133
1134         ret = set_gpfs_winattrs(CONST_DISCARD(char *, path),
1135                                 GPFS_WINATTR_SET_CREATION_TIME, &attrs);
1136         if(ret == -1 && errno != ENOSYS){
1137                 DEBUG(1,("vfs_gpfs_ntimes: set GPFS ntimes failed %d\n",ret));
1138                 return -1;
1139         }
1140         return 0;
1141
1142 }
1143
1144 int vfs_gpfs_connect(struct vfs_handle_struct *handle, const char *service,
1145                         const char *user)
1146 {
1147         struct gpfs_config_data *config;
1148         int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
1149
1150         if (ret < 0) {
1151                 return ret;
1152         }
1153
1154         config = talloc_zero(handle->conn, struct gpfs_config_data);
1155         if (!config) {
1156                 SMB_VFS_NEXT_DISCONNECT(handle);
1157                 DEBUG(0, ("talloc_zero() failed\n")); return -1;
1158         }
1159
1160         config->sharemodes = lp_parm_bool(SNUM(handle->conn), "gpfs",
1161                                         "sharemodes", true);
1162
1163         config->leases = lp_parm_bool(SNUM(handle->conn), "gpfs",
1164                                         "leases", true);
1165
1166         SMB_VFS_HANDLE_SET_DATA(handle, config,
1167                                 NULL, struct gpfs_config_data,
1168                                 return -1);
1169
1170         return 0;
1171 }
1172
1173
1174 static int vfs_gpfs_ftruncate(struct vfs_handle_struct *handle,
1175                               struct files_struct *fsp,
1176                               SMB_OFF_T len)
1177 {
1178        int result;
1179
1180        result = smbd_gpfs_ftrunctate(fsp->fh->fd, len);
1181        if ((result == -1) && (errno == ENOSYS)) {
1182                return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
1183        }
1184        return result;
1185 }
1186
1187 static struct vfs_fn_pointers vfs_gpfs_fns = {
1188         .connect_fn = vfs_gpfs_connect,
1189         .kernel_flock = vfs_gpfs_kernel_flock,
1190         .linux_setlease = vfs_gpfs_setlease,
1191         .get_real_filename = vfs_gpfs_get_real_filename,
1192         .fget_nt_acl = gpfsacl_fget_nt_acl,
1193         .get_nt_acl = gpfsacl_get_nt_acl,
1194         .fset_nt_acl = gpfsacl_fset_nt_acl,
1195         .sys_acl_get_file = gpfsacl_sys_acl_get_file,
1196         .sys_acl_get_fd = gpfsacl_sys_acl_get_fd,
1197         .sys_acl_set_file = gpfsacl_sys_acl_set_file,
1198         .sys_acl_set_fd = gpfsacl_sys_acl_set_fd,
1199         .sys_acl_delete_def_file = gpfsacl_sys_acl_delete_def_file,
1200         .chmod = vfs_gpfs_chmod,
1201         .fchmod = vfs_gpfs_fchmod,
1202         .close_fn = vfs_gpfs_close,
1203         .setxattr = gpfs_set_xattr,
1204         .getxattr = gpfs_get_xattr,
1205         .stat = vfs_gpfs_stat,
1206         .fstat = vfs_gpfs_fstat,
1207         .lstat = vfs_gpfs_lstat,
1208         .ntimes = vfs_gpfs_ntimes,
1209         .ftruncate = vfs_gpfs_ftruncate,
1210 };
1211
1212 NTSTATUS vfs_gpfs_init(void);
1213 NTSTATUS vfs_gpfs_init(void)
1214 {
1215         init_gpfs();
1216
1217         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs",
1218                                 &vfs_gpfs_fns);
1219 }