8860803906606c7848c84597b7ec7bce1ac430dc
[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 #include "smbd/smbd.h"
26 #include "librpc/gen_ndr/ndr_xattr.h"
27 #include "include/smbprofile.h"
28 #include "modules/non_posix_acls.h"
29
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_VFS
32
33 #include <gpfs_fcntl.h>
34 #include "nfs4_acls.h"
35 #include "vfs_gpfs.h"
36 #include "system/filesys.h"
37 #include "auth.h"
38 #include "lib/util/tevent_unix.h"
39
40 struct gpfs_config_data {
41         bool sharemodes;
42         bool leases;
43         bool hsm;
44         bool syncio;
45         bool winattr;
46         bool ftruncate;
47         bool getrealfilename;
48         bool dfreequota;
49         bool prealloc;
50         bool acl;
51         bool settimes;
52         bool recalls;
53 };
54
55 static inline unsigned int gpfs_acl_flags(gpfs_acl_t *gacl)
56 {
57         if (gacl->acl_level == 1) { /* GPFS_ACL_LEVEL_V4FLAGS */
58                 /* gacl->v4Level1.acl_flags requires gpfs 3.5 */
59                 return *(unsigned int *)&gacl->ace_v4;
60         }
61         return 0;
62 }
63
64 static inline gpfs_ace_v4_t *gpfs_ace_ptr(gpfs_acl_t *gacl, unsigned int i)
65 {
66         if (gacl->acl_level == 1) { /* GPFS_ACL_LEVEL_V4FLAGS */
67                 /* &gacl->v4Level1.ace_v4[i] requires gpfs 3.5 */
68                 char *ptr = (char *)&gacl->ace_v4[i] + sizeof(unsigned int);
69                 return (gpfs_ace_v4_t *)ptr;
70         }
71         return &gacl->ace_v4[i];
72 }
73
74 static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
75                                  uint32 share_mode, uint32 access_mask)
76 {
77
78         struct gpfs_config_data *config;
79         int ret = 0;
80
81         START_PROFILE(syscall_kernel_flock);
82
83         SMB_VFS_HANDLE_GET_DATA(handle, config,
84                                 struct gpfs_config_data,
85                                 return -1);
86
87         if(!config->sharemodes) {
88                 return 0;
89         }
90
91         kernel_flock(fsp->fh->fd, share_mode, access_mask);
92
93         if (!set_gpfs_sharemode(fsp, access_mask, fsp->share_access)) {
94                 ret = -1;
95         }
96
97         END_PROFILE(syscall_kernel_flock);
98
99         return ret;
100 }
101
102 static int vfs_gpfs_close(vfs_handle_struct *handle, files_struct *fsp)
103 {
104
105         struct gpfs_config_data *config;
106
107         SMB_VFS_HANDLE_GET_DATA(handle, config,
108                                 struct gpfs_config_data,
109                                 return -1);
110
111         if (config->sharemodes && (fsp->fh != NULL) && (fsp->fh->fd != -1)) {
112                 set_gpfs_sharemode(fsp, 0, 0);
113         }
114
115         return SMB_VFS_NEXT_CLOSE(handle, fsp);
116 }
117
118 static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, 
119                              int leasetype)
120 {
121         struct gpfs_config_data *config;
122         int ret=0;
123
124         START_PROFILE(syscall_linux_setlease);
125
126         SMB_VFS_HANDLE_GET_DATA(handle, config,
127                                 struct gpfs_config_data,
128                                 return -1);
129
130         if (linux_set_lease_sighandler(fsp->fh->fd) == -1)
131                 return -1;
132
133         if (config->leases) {
134                 /*
135                  * Ensure the lease owner is root to allow
136                  * correct delivery of lease-break signals.
137                  */
138                 become_root();
139                 ret = set_gpfs_lease(fsp->fh->fd,leasetype);
140                 unbecome_root();
141         }
142
143         END_PROFILE(syscall_linux_setlease);
144
145         return ret;
146 }
147
148 static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
149                                       const char *path,
150                                       const char *name,
151                                       TALLOC_CTX *mem_ctx,
152                                       char **found_name)
153 {
154         int result;
155         char *full_path;
156         char real_pathname[PATH_MAX+1];
157         int buflen;
158         bool mangled;
159         struct gpfs_config_data *config;
160
161         SMB_VFS_HANDLE_GET_DATA(handle, config,
162                                 struct gpfs_config_data,
163                                 return -1);
164
165         if (!config->getrealfilename) {
166                 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
167                                                       mem_ctx, found_name);
168         }
169
170         mangled = mangle_is_mangled(name, handle->conn->params);
171         if (mangled) {
172                 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
173                                                       mem_ctx, found_name);
174         }
175
176         full_path = talloc_asprintf(talloc_tos(), "%s/%s", path, name);
177         if (full_path == NULL) {
178                 errno = ENOMEM;
179                 return -1;
180         }
181
182         buflen = sizeof(real_pathname) - 1;
183
184         result = gpfswrap_get_realfilename_path(full_path, real_pathname,
185                                                 &buflen);
186
187         TALLOC_FREE(full_path);
188
189         if ((result == -1) && (errno == ENOSYS)) {
190                 return SMB_VFS_NEXT_GET_REAL_FILENAME(
191                         handle, path, name, mem_ctx, found_name);
192         }
193
194         if (result == -1) {
195                 DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n",
196                            strerror(errno)));
197                 return -1;
198         }
199
200         /*
201          * GPFS does not necessarily null-terminate the returned path
202          * but instead returns the buffer length in buflen.
203          */
204
205         if (buflen < sizeof(real_pathname)) {
206                 real_pathname[buflen] = '\0';
207         } else {
208                 real_pathname[sizeof(real_pathname)-1] = '\0';
209         }
210
211         DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n",
212                    path, name, real_pathname));
213
214         name = strrchr_m(real_pathname, '/');
215         if (name == NULL) {
216                 errno = ENOENT;
217                 return -1;
218         }
219
220         *found_name = talloc_strdup(mem_ctx, name+1);
221         if (*found_name == NULL) {
222                 errno = ENOMEM;
223                 return -1;
224         }
225
226         return 0;
227 }
228
229 static void sd2gpfs_control(uint16_t control, struct gpfs_acl *gacl)
230 {
231         unsigned int gpfs_aclflags = 0;
232         control &= SEC_DESC_DACL_PROTECTED | SEC_DESC_SACL_PROTECTED |
233                 SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_SACL_AUTO_INHERITED |
234                 SEC_DESC_DACL_DEFAULTED | SEC_DESC_SACL_DEFAULTED |
235                 SEC_DESC_DACL_PRESENT | SEC_DESC_SACL_PRESENT;
236         gpfs_aclflags = control << 8;
237         if (!(control & SEC_DESC_DACL_PRESENT))
238                 gpfs_aclflags |= 0x00800000; /* ACL4_FLAG_NULL_DACL; */
239         if (!(control & SEC_DESC_SACL_PRESENT))
240                 gpfs_aclflags |= 0x01000000; /* ACL4_FLAG_NULL_SACL; */
241         gacl->acl_level = 1; /* GPFS_ACL_LEVEL_V4FLAGS*/
242         /* gacl->v4Level1.acl_flags requires gpfs 3.5 */
243         *(unsigned int *)&gacl->ace_v4 = gpfs_aclflags;
244 }
245
246 static uint16_t gpfs2sd_control(unsigned int gpfs_aclflags)
247 {
248         uint16_t control = gpfs_aclflags >> 8;
249         control &= SEC_DESC_DACL_PROTECTED | SEC_DESC_SACL_PROTECTED |
250                 SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_SACL_AUTO_INHERITED |
251                 SEC_DESC_DACL_DEFAULTED | SEC_DESC_SACL_DEFAULTED |
252                 SEC_DESC_DACL_PRESENT | SEC_DESC_SACL_PRESENT;
253         control |= SEC_DESC_SELF_RELATIVE;
254         return control;
255 }
256
257 static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
258 {
259         gpfs_aclCount_t i;
260         if (gacl==NULL)
261         {
262                 DEBUG(0, ("gpfs acl is NULL\n"));
263                 return;
264         }
265
266         DEBUG(level, ("len: %d, level: %d, version: %d, nace: %d, "
267                       "control: %x\n",
268                       gacl->acl_len, gacl->acl_level, gacl->acl_version,
269                       gacl->acl_nace, gpfs_acl_flags(gacl)));
270
271         for(i=0; i<gacl->acl_nace; i++)
272         {
273                 struct gpfs_ace_v4 *gace = gpfs_ace_ptr(gacl, i);
274                 DEBUG(level, ("\tace[%d]: type:%d, flags:0x%x, mask:0x%x, "
275                               "iflags:0x%x, who:%u\n",
276                               i, gace->aceType, gace->aceFlags, gace->aceMask,
277                               gace->aceIFlags, gace->aceWho));
278         }
279 }
280
281 /*
282  * get the ACL from GPFS, allocated on the specified mem_ctx
283  * internally retries when initial buffer was too small
284  *
285  * caller needs to cast result to either
286  * raw = yes: struct gpfs_opaque_acl
287  * raw = no: struct gpfs_acl
288  *
289  */
290 static void *vfs_gpfs_getacl(TALLOC_CTX *mem_ctx,
291                          const char *fname,
292                          const bool raw,
293                          const gpfs_aclType_t type)
294 {
295
296         void *aclbuf;
297         size_t size = 512;
298         int ret, flags;
299         unsigned int *len;
300         size_t struct_size;
301
302 again:
303
304         aclbuf = talloc_zero_size(mem_ctx, size);
305         if (aclbuf == NULL) {
306                 errno = ENOMEM;
307                 return NULL;
308         }
309
310         if (raw) {
311                 struct gpfs_opaque_acl *buf = (struct gpfs_opaque_acl *) aclbuf;
312                 buf->acl_type = type;
313                 flags = GPFS_GETACL_NATIVE;
314                 len = (unsigned int *) &(buf->acl_buffer_len);
315                 struct_size = sizeof(struct gpfs_opaque_acl);
316         } else {
317                 struct gpfs_acl *buf = (struct gpfs_acl *) aclbuf;
318                 buf->acl_type = type;
319                 buf->acl_level = 1; /* GPFS_ACL_LEVEL_V4FLAGS */
320                 flags = GPFS_GETACL_STRUCT;
321                 len = &(buf->acl_len);
322                 /* reserve space for control flags in gpfs 3.5 and beyond */
323                 struct_size = sizeof(struct gpfs_acl) + sizeof(unsigned int);
324         }
325
326         /* set the length of the buffer as input value */
327         *len = size;
328
329         errno = 0;
330         ret = gpfswrap_getacl(discard_const_p(char, fname), flags, aclbuf);
331         if ((ret != 0) && (errno == ENOSPC)) {
332                 /*
333                  * get the size needed to accommodate the complete buffer
334                  *
335                  * the value returned only applies to the ACL blob in the
336                  * struct so make sure to also have headroom for the first
337                  * struct members by adding room for the complete struct
338                  * (might be a few bytes too much then)
339                  */
340                 size = *len + struct_size;
341                 talloc_free(aclbuf);
342                 DEBUG(10, ("Increasing ACL buffer size to %zu\n", size));
343                 goto again;
344         }
345
346         if (ret != 0) {
347                 DEBUG(5, ("smbd_gpfs_getacl failed with %s\n",
348                           strerror(errno)));
349                 talloc_free(aclbuf);
350                 return NULL;
351         }
352
353         return aclbuf;
354 }
355
356 /* Tries to get nfs4 acls and returns SMB ACL allocated.
357  * On failure returns 1 if it got non-NFSv4 ACL to prompt 
358  * retry with POSIX ACL checks.
359  * On failure returns -1 if there is system (GPFS) error, check errno.
360  * Returns 0 on success
361  */
362 static int gpfs_get_nfs4_acl(TALLOC_CTX *mem_ctx, const char *fname, SMB4ACL_T **ppacl)
363 {
364         gpfs_aclCount_t i;
365         struct gpfs_acl *gacl = NULL;
366         DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
367
368         /* Get the ACL */
369         gacl = (struct gpfs_acl*) vfs_gpfs_getacl(talloc_tos(), fname,
370                                                   false, 0);
371         if (gacl == NULL) {
372                 DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
373                            fname, strerror(errno)));
374                 return -1;
375         }
376
377         if (gacl->acl_type != GPFS_ACL_TYPE_NFS4) {
378                 DEBUG(10, ("Got non-nfsv4 acl\n"));
379                 /* Retry with POSIX ACLs check */
380                 talloc_free(gacl);
381                 return 1;
382         }
383
384         *ppacl = smb_create_smb4acl(mem_ctx);
385
386         if (gacl->acl_level == 1) { /* GPFS_ACL_LEVEL_V4FLAGS */
387                 uint16_t control = gpfs2sd_control(gpfs_acl_flags(gacl));
388                 smbacl4_set_controlflags(*ppacl, control);
389         }
390
391         DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d, control: %x\n",
392                    gacl->acl_len, gacl->acl_level, gacl->acl_version,
393                    gacl->acl_nace, gpfs_acl_flags(gacl)));
394
395         for (i=0; i<gacl->acl_nace; i++) {
396                 struct gpfs_ace_v4 *gace = gpfs_ace_ptr(gacl, i);
397                 SMB_ACE4PROP_T smbace;
398                 DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
399                            "who: %d\n", gace->aceType, gace->aceIFlags,
400                            gace->aceFlags, gace->aceMask, gace->aceWho));
401
402                 ZERO_STRUCT(smbace);
403                 if (gace->aceIFlags & ACE4_IFLAG_SPECIAL_ID) {
404                         smbace.flags |= SMB_ACE4_ID_SPECIAL;
405                         switch (gace->aceWho) {
406                         case ACE4_SPECIAL_OWNER:
407                                 smbace.who.special_id = SMB_ACE4_WHO_OWNER;
408                                 break;
409                         case ACE4_SPECIAL_GROUP:
410                                 smbace.who.special_id = SMB_ACE4_WHO_GROUP;
411                                 break;
412                         case ACE4_SPECIAL_EVERYONE:
413                                 smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
414                                 break;
415                         default:
416                                 DEBUG(8, ("invalid special gpfs id %d "
417                                           "ignored\n", gace->aceWho));
418                                 continue; /* don't add it */
419                         }
420                 } else {
421                         if (gace->aceFlags & ACE4_FLAG_GROUP_ID)
422                                 smbace.who.gid = gace->aceWho;
423                         else
424                                 smbace.who.uid = gace->aceWho;
425                 }
426
427                 /* remove redundant deny entries */
428                 if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
429                         struct gpfs_ace_v4 *prev = gpfs_ace_ptr(gacl, i - 1);
430                         if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
431                             prev->aceFlags == gace->aceFlags &&
432                             prev->aceIFlags == gace->aceIFlags &&
433                             (gace->aceMask & prev->aceMask) == 0 &&
434                             gace->aceWho == prev->aceWho) {
435                                 /* it's redundant - skip it */
436                                 continue;
437                         }
438                 }
439
440                 smbace.aceType = gace->aceType;
441                 smbace.aceFlags = gace->aceFlags;
442                 smbace.aceMask = gace->aceMask;
443                 smb_add_ace4(*ppacl, &smbace);
444         }
445
446         talloc_free(gacl);
447
448         return 0;
449 }
450
451 static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
452         files_struct *fsp, uint32 security_info,
453         TALLOC_CTX *mem_ctx,
454         struct security_descriptor **ppdesc)
455 {
456         SMB4ACL_T *pacl = NULL;
457         int     result;
458         struct gpfs_config_data *config;
459         TALLOC_CTX *frame = talloc_stackframe();
460         NTSTATUS status;
461
462         *ppdesc = NULL;
463
464         SMB_VFS_HANDLE_GET_DATA(handle, config,
465                                 struct gpfs_config_data,
466                                 return NT_STATUS_INTERNAL_ERROR);
467
468         if (!config->acl) {
469                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
470                                                   mem_ctx, ppdesc);
471                 TALLOC_FREE(frame);
472                 return status;
473         }
474
475         result = gpfs_get_nfs4_acl(frame, fsp->fsp_name->base_name, &pacl);
476
477         if (result == 0) {
478                 status = smb_fget_nt_acl_nfs4(fsp, security_info, mem_ctx,
479                                               ppdesc, pacl);
480                 TALLOC_FREE(frame);
481                 return status;
482         }
483
484         if (result > 0) {
485                 DEBUG(10, ("retrying with posix acl...\n"));
486                 status = posix_fget_nt_acl(fsp, security_info,
487                                            mem_ctx, ppdesc);
488                 TALLOC_FREE(frame);
489                 return status;
490         }
491
492         TALLOC_FREE(frame);
493
494         /* GPFS ACL was not read, something wrong happened, error code is set in errno */
495         return map_nt_error_from_unix(errno);
496 }
497
498 static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
499         const char *name,
500         uint32 security_info,
501         TALLOC_CTX *mem_ctx, struct security_descriptor **ppdesc)
502 {
503         SMB4ACL_T *pacl = NULL;
504         int     result;
505         struct gpfs_config_data *config;
506         TALLOC_CTX *frame = talloc_stackframe();
507         NTSTATUS status;
508
509         *ppdesc = NULL;
510
511         SMB_VFS_HANDLE_GET_DATA(handle, config,
512                                 struct gpfs_config_data,
513                                 return NT_STATUS_INTERNAL_ERROR);
514
515         if (!config->acl) {
516                 status = SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info,
517                                                  mem_ctx, ppdesc);
518                 TALLOC_FREE(frame);
519                 return status;
520         }
521
522         result = gpfs_get_nfs4_acl(frame, name, &pacl);
523
524         if (result == 0) {
525                 status = smb_get_nt_acl_nfs4(handle->conn, name, security_info,
526                                            mem_ctx, ppdesc, pacl);
527                 TALLOC_FREE(frame);
528                 return status;
529         }
530
531         if (result > 0) {
532                 DEBUG(10, ("retrying with posix acl...\n"));
533                 status =  posix_get_nt_acl(handle->conn, name, security_info,
534                                            mem_ctx, ppdesc);
535                 TALLOC_FREE(frame);
536                 return status;
537         }
538
539         /* GPFS ACL was not read, something wrong happened, error code is set in errno */
540         TALLOC_FREE(frame);
541         return map_nt_error_from_unix(errno);
542 }
543
544 static struct gpfs_acl *vfs_gpfs_smbacl2gpfsacl(TALLOC_CTX *mem_ctx,
545                                                 files_struct *fsp,
546                                                 SMB4ACL_T *smbacl,
547                                                 bool controlflags)
548 {
549         struct gpfs_acl *gacl;
550         gpfs_aclLen_t gacl_len;
551         SMB4ACE_T *smbace;
552
553         gacl_len = offsetof(gpfs_acl_t, ace_v4) + sizeof(unsigned int)
554                 + smb_get_naces(smbacl) * sizeof(gpfs_ace_v4_t);
555
556         gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len);
557         if (gacl == NULL) {
558                 DEBUG(0, ("talloc failed\n"));
559                 errno = ENOMEM;
560                 return NULL;
561         }
562
563         gacl->acl_level = 0; /* GPFS_ACL_LEVEL_BASE */
564         gacl->acl_version = GPFS_ACL_VERSION_NFS4;
565         gacl->acl_type = GPFS_ACL_TYPE_NFS4;
566         gacl->acl_nace = 0; /* change later... */
567
568         if (controlflags) {
569                 gacl->acl_level = 1; /* GPFS_ACL_LEVEL_V4FLAGS */
570                 sd2gpfs_control(smbacl4_get_controlflags(smbacl), gacl);
571         }
572
573         for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
574                 struct gpfs_ace_v4 *gace = gpfs_ace_ptr(gacl, gacl->acl_nace);
575                 SMB_ACE4PROP_T  *aceprop = smb_get_ace4(smbace);
576
577                 gace->aceType = aceprop->aceType;
578                 gace->aceFlags = aceprop->aceFlags;
579                 gace->aceMask = aceprop->aceMask;
580
581                 /*
582                  * GPFS can't distinguish between WRITE and APPEND on
583                  * files, so one being set without the other is an
584                  * error. Sorry for the many ()'s :-)
585                  */
586
587                 if (!fsp->is_directory
588                     &&
589                     ((((gace->aceMask & ACE4_MASK_WRITE) == 0)
590                       && ((gace->aceMask & ACE4_MASK_APPEND) != 0))
591                      ||
592                      (((gace->aceMask & ACE4_MASK_WRITE) != 0)
593                       && ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
594                     &&
595                     lp_parm_bool(fsp->conn->params->service, "gpfs",
596                                  "merge_writeappend", True)) {
597                         DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
598                                   "WRITE^APPEND, setting WRITE|APPEND\n",
599                                   fsp_str_dbg(fsp)));
600                         gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
601                 }
602
603                 gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;
604
605                 if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
606                 {
607                         switch(aceprop->who.special_id)
608                         {
609                         case SMB_ACE4_WHO_EVERYONE:
610                                 gace->aceWho = ACE4_SPECIAL_EVERYONE;
611                                 break;
612                         case SMB_ACE4_WHO_OWNER:
613                                 gace->aceWho = ACE4_SPECIAL_OWNER;
614                                 break;
615                         case SMB_ACE4_WHO_GROUP:
616                                 gace->aceWho = ACE4_SPECIAL_GROUP;
617                                 break;
618                         default:
619                                 DEBUG(8, ("unsupported special_id %d\n", aceprop->who.special_id));
620                                 continue; /* don't add it !!! */
621                         }
622                 } else {
623                         /* just only for the type safety... */
624                         if (aceprop->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
625                                 gace->aceWho = aceprop->who.gid;
626                         else
627                                 gace->aceWho = aceprop->who.uid;
628                 }
629
630                 gacl->acl_nace++;
631         }
632         gacl->acl_len = (char *)gpfs_ace_ptr(gacl, gacl->acl_nace)
633                 - (char *)gacl;
634         return gacl;
635 }
636
637 static bool gpfsacl_process_smbacl(vfs_handle_struct *handle,
638                                    files_struct *fsp,
639                                    SMB4ACL_T *smbacl)
640 {
641         int ret;
642         struct gpfs_acl *gacl;
643         TALLOC_CTX *mem_ctx = talloc_tos();
644
645         gacl = vfs_gpfs_smbacl2gpfsacl(mem_ctx, fsp, smbacl, true);
646         if (gacl == NULL) { /* out of memory */
647                 return False;
648         }
649         ret = gpfswrap_putacl(fsp->fsp_name->base_name,
650                               GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
651
652         if ((ret != 0) && (errno == EINVAL)) {
653                 DEBUG(10, ("Retry without nfs41 control flags\n"));
654                 talloc_free(gacl);
655                 gacl = vfs_gpfs_smbacl2gpfsacl(mem_ctx, fsp, smbacl, false);
656                 if (gacl == NULL) { /* out of memory */
657                         return False;
658                 }
659                 ret = gpfswrap_putacl(fsp->fsp_name->base_name,
660                                       GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA,
661                                       gacl);
662         }
663
664         if (ret != 0) {
665                 DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
666                 gpfs_dumpacl(8, gacl);
667                 return False;
668         }
669
670         DEBUG(10, ("gpfs_putacl succeeded\n"));
671         return True;
672 }
673
674 static NTSTATUS gpfsacl_set_nt_acl_internal(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
675 {
676         struct gpfs_acl *acl;
677         NTSTATUS result = NT_STATUS_ACCESS_DENIED;
678
679         acl = (struct gpfs_acl*) vfs_gpfs_getacl(talloc_tos(),
680                                                  fsp->fsp_name->base_name,
681                                                  false, 0);
682         if (acl == NULL) {
683                 return map_nt_error_from_unix(errno);
684         }
685
686         if (acl->acl_version == GPFS_ACL_VERSION_NFS4) {
687                 if (lp_parm_bool(fsp->conn->params->service, "gpfs",
688                                  "refuse_dacl_protected", false)
689                     && (psd->type&SEC_DESC_DACL_PROTECTED)) {
690                         DEBUG(2, ("Rejecting unsupported ACL with DACL_PROTECTED bit set\n"));
691                         talloc_free(acl);
692                         return NT_STATUS_NOT_SUPPORTED;
693                 }
694
695                 result = smb_set_nt_acl_nfs4(handle,
696                         fsp, security_info_sent, psd,
697                         gpfsacl_process_smbacl);
698         } else { /* assume POSIX ACL - by default... */
699                 result = set_nt_acl(fsp, security_info_sent, psd);
700         }
701
702         talloc_free(acl);
703         return result;
704 }
705
706 static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
707 {
708         struct gpfs_config_data *config;
709
710         SMB_VFS_HANDLE_GET_DATA(handle, config,
711                                 struct gpfs_config_data,
712                                 return NT_STATUS_INTERNAL_ERROR);
713
714         if (!config->acl) {
715                 return SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
716         }
717
718         return gpfsacl_set_nt_acl_internal(handle, fsp, security_info_sent, psd);
719 }
720
721 static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl, TALLOC_CTX *mem_ctx)
722 {
723         SMB_ACL_T result;
724         gpfs_aclCount_t i;
725
726         result = sys_acl_init(mem_ctx);
727         if (result == NULL) {
728                 errno = ENOMEM;
729                 return NULL;
730         }
731
732         result->count = pacl->acl_nace;
733         result->acl = talloc_realloc(result, result->acl, struct smb_acl_entry,
734                                      result->count);
735         if (result->acl == NULL) {
736                 TALLOC_FREE(result);
737                 errno = ENOMEM;
738                 return NULL;
739         }
740
741         for (i=0; i<pacl->acl_nace; i++) {
742                 struct smb_acl_entry *ace = &result->acl[i];
743                 const struct gpfs_ace_v1 *g_ace = &pacl->ace_v1[i];
744
745                 DEBUG(10, ("Converting type %d id %lu perm %x\n",
746                            (int)g_ace->ace_type, (unsigned long)g_ace->ace_who,
747                            (int)g_ace->ace_perm));
748
749                 switch (g_ace->ace_type) {
750                 case GPFS_ACL_USER:
751                         ace->a_type = SMB_ACL_USER;
752                         ace->info.user.uid = (uid_t)g_ace->ace_who;
753                         break;
754                 case GPFS_ACL_USER_OBJ:
755                         ace->a_type = SMB_ACL_USER_OBJ;
756                         break;
757                 case GPFS_ACL_GROUP:
758                         ace->a_type = SMB_ACL_GROUP;
759                         ace->info.group.gid = (gid_t)g_ace->ace_who;
760                         break;
761                 case GPFS_ACL_GROUP_OBJ:
762                         ace->a_type = SMB_ACL_GROUP_OBJ;
763                         break;
764                 case GPFS_ACL_OTHER:
765                         ace->a_type = SMB_ACL_OTHER;
766                         break;
767                 case GPFS_ACL_MASK:
768                         ace->a_type = SMB_ACL_MASK;
769                         break;
770                 default:
771                         DEBUG(10, ("Got invalid ace_type: %d\n",
772                                    g_ace->ace_type));
773                         TALLOC_FREE(result);
774                         errno = EINVAL;
775                         return NULL;
776                 }
777
778                 ace->a_perm = 0;
779                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_READ) ?
780                         SMB_ACL_READ : 0;
781                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_WRITE) ?
782                         SMB_ACL_WRITE : 0;
783                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_EXECUTE) ?
784                         SMB_ACL_EXECUTE : 0;
785
786                 DEBUGADD(10, ("Converted to %d perm %x\n",
787                               ace->a_type, ace->a_perm));
788         }
789
790         return result;
791 }
792
793 static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type,
794                                        TALLOC_CTX *mem_ctx)
795 {
796         struct gpfs_acl *pacl;
797         SMB_ACL_T result = NULL;
798
799         pacl = vfs_gpfs_getacl(talloc_tos(), path, false, type);
800
801         if (pacl == NULL) {
802                 DEBUG(10, ("vfs_gpfs_getacl failed for %s with %s\n",
803                            path, strerror(errno)));
804                 if (errno == 0) {
805                         errno = EINVAL;
806                 }
807                 goto done;
808         }
809
810         if (pacl->acl_version != GPFS_ACL_VERSION_POSIX) {
811                 DEBUG(10, ("Got acl version %d, expected %d\n",
812                            pacl->acl_version, GPFS_ACL_VERSION_POSIX));
813                 errno = EINVAL;
814                 goto done;
815         }
816
817         DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
818                    pacl->acl_len, pacl->acl_level, pacl->acl_version,
819                    pacl->acl_nace));
820
821         result = gpfs2smb_acl(pacl, mem_ctx);
822         if (result != NULL) {
823                 errno = 0;
824         }
825
826  done:
827
828         if (pacl != NULL) {
829                 talloc_free(pacl);
830         }
831         if (errno != 0) {
832                 TALLOC_FREE(result);
833         }
834         return result;
835 }
836
837 static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
838                                           const char *path_p,
839                                           SMB_ACL_TYPE_T type,
840                                           TALLOC_CTX *mem_ctx)
841 {
842         gpfs_aclType_t gpfs_type;
843         struct gpfs_config_data *config;
844
845         SMB_VFS_HANDLE_GET_DATA(handle, config,
846                                 struct gpfs_config_data,
847                                 return NULL);
848
849         if (!config->acl) {
850                 return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, path_p,
851                                                      type, mem_ctx);
852         }
853
854         switch(type) {
855         case SMB_ACL_TYPE_ACCESS:
856                 gpfs_type = GPFS_ACL_TYPE_ACCESS;
857                 break;
858         case SMB_ACL_TYPE_DEFAULT:
859                 gpfs_type = GPFS_ACL_TYPE_DEFAULT;
860                 break;
861         default:
862                 DEBUG(0, ("Got invalid type: %d\n", type));
863                 smb_panic("exiting");
864         }
865
866         return gpfsacl_get_posix_acl(path_p, gpfs_type, mem_ctx);
867 }
868
869 static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
870                                         files_struct *fsp,
871                                         TALLOC_CTX *mem_ctx)
872 {
873         struct gpfs_config_data *config;
874
875         SMB_VFS_HANDLE_GET_DATA(handle, config,
876                                 struct gpfs_config_data,
877                                 return NULL);
878
879         if (!config->acl) {
880                 return SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, mem_ctx);
881         }
882
883         return gpfsacl_get_posix_acl(fsp->fsp_name->base_name,
884                                      GPFS_ACL_TYPE_ACCESS, mem_ctx);
885 }
886
887 static int gpfsacl_sys_acl_blob_get_file(vfs_handle_struct *handle,
888                                       const char *path_p,
889                                       TALLOC_CTX *mem_ctx,
890                                       char **blob_description,
891                                       DATA_BLOB *blob)
892 {
893         struct gpfs_config_data *config;
894         struct gpfs_opaque_acl *acl = NULL;
895         DATA_BLOB aclblob;
896         int result;
897
898         SMB_VFS_HANDLE_GET_DATA(handle, config,
899                                 struct gpfs_config_data,
900                                 return -1);
901
902         if (!config->acl) {
903                 return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FILE(handle, path_p,
904                                                           mem_ctx,
905                                                           blob_description,
906                                                           blob);
907         }
908
909         errno = 0;
910         acl = (struct gpfs_opaque_acl *)
911                         vfs_gpfs_getacl(mem_ctx,
912                                         path_p,
913                                         true,
914                                         GPFS_ACL_TYPE_NFS4);
915
916         if (errno) {
917                 DEBUG(5, ("vfs_gpfs_getacl finished with errno %d: %s\n",
918                                         errno, strerror(errno)));
919
920                 /* EINVAL means POSIX ACL, bail out on other cases */
921                 if (errno != EINVAL) {
922                         return -1;
923                 }
924         }
925
926         if (acl != NULL) {
927                 /*
928                  * file has NFSv4 ACL
929                  *
930                  * we only need the actual ACL blob here
931                  * acl_version will always be NFS4 because we asked
932                  * for NFS4
933                  * acl_type is only used for POSIX ACLs
934                  */
935                 aclblob.data = (uint8_t*) acl->acl_var_data;
936                 aclblob.length = acl->acl_buffer_len;
937
938                 *blob_description = talloc_strdup(mem_ctx, "gpfs_nfs4_acl");
939                 if (!*blob_description) {
940                         talloc_free(acl);
941                         errno = ENOMEM;
942                         return -1;
943                 }
944
945                 result = non_posix_sys_acl_blob_get_file_helper(handle, path_p,
946                                                                 aclblob,
947                                                                 mem_ctx, blob);
948
949                 talloc_free(acl);
950                 return result;
951         }
952
953         /* fall back to POSIX ACL */
954         return posix_sys_acl_blob_get_file(handle, path_p, mem_ctx,
955                                            blob_description, blob);
956 }
957
958 static int gpfsacl_sys_acl_blob_get_fd(vfs_handle_struct *handle,
959                                       files_struct *fsp,
960                                       TALLOC_CTX *mem_ctx,
961                                       char **blob_description,
962                                       DATA_BLOB *blob)
963 {
964         struct gpfs_config_data *config;
965         struct gpfs_opaque_acl *acl = NULL;
966         DATA_BLOB aclblob;
967         int result;
968
969         SMB_VFS_HANDLE_GET_DATA(handle, config,
970                                 struct gpfs_config_data,
971                                 return -1);
972
973         if (!config->acl) {
974                 return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx,
975                                                         blob_description, blob);
976         }
977
978         errno = 0;
979         acl = (struct gpfs_opaque_acl *) vfs_gpfs_getacl(mem_ctx,
980                                                 fsp->fsp_name->base_name,
981                                                 true,
982                                                 GPFS_ACL_TYPE_NFS4);
983
984         if (errno) {
985                 DEBUG(5, ("vfs_gpfs_getacl finished with errno %d: %s\n",
986                                         errno, strerror(errno)));
987
988                 /* EINVAL means POSIX ACL, bail out on other cases */
989                 if (errno != EINVAL) {
990                         return -1;
991                 }
992         }
993
994         if (acl != NULL) {
995                 /*
996                  * file has NFSv4 ACL
997                  *
998                  * we only need the actual ACL blob here
999                  * acl_version will always be NFS4 because we asked
1000                  * for NFS4
1001                  * acl_type is only used for POSIX ACLs
1002                  */
1003                 aclblob.data = (uint8_t*) acl->acl_var_data;
1004                 aclblob.length = acl->acl_buffer_len;
1005
1006                 *blob_description = talloc_strdup(mem_ctx, "gpfs_nfs4_acl");
1007                 if (!*blob_description) {
1008                         talloc_free(acl);
1009                         errno = ENOMEM;
1010                         return -1;
1011                 }
1012
1013                 result = non_posix_sys_acl_blob_get_fd_helper(handle, fsp,
1014                                                               aclblob, mem_ctx,
1015                                                               blob);
1016
1017                 talloc_free(acl);
1018                 return result;
1019         }
1020
1021         /* fall back to POSIX ACL */
1022         return posix_sys_acl_blob_get_fd(handle, fsp, mem_ctx,
1023                                          blob_description, blob);
1024 }
1025
1026 static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
1027                                      SMB_ACL_TYPE_T type)
1028 {
1029         gpfs_aclLen_t len;
1030         struct gpfs_acl *result;
1031         int i;
1032
1033         DEBUG(10, ("smb2gpfs_acl: Got ACL with %d entries\n", pacl->count));
1034
1035         len = offsetof(gpfs_acl_t, ace_v1) + (pacl->count) *
1036                 sizeof(gpfs_ace_v1_t);
1037
1038         result = (struct gpfs_acl *)SMB_MALLOC(len);
1039         if (result == NULL) {
1040                 errno = ENOMEM;
1041                 return result;
1042         }
1043
1044         result->acl_len = len;
1045         result->acl_level = 0;
1046         result->acl_version = GPFS_ACL_VERSION_POSIX;
1047         result->acl_type = (type == SMB_ACL_TYPE_DEFAULT) ?
1048                 GPFS_ACL_TYPE_DEFAULT : GPFS_ACL_TYPE_ACCESS;
1049         result->acl_nace = pacl->count;
1050
1051         for (i=0; i<pacl->count; i++) {
1052                 const struct smb_acl_entry *ace = &pacl->acl[i];
1053                 struct gpfs_ace_v1 *g_ace = &result->ace_v1[i];
1054
1055                 DEBUG(10, ("Converting type %d perm %x\n",
1056                            (int)ace->a_type, (int)ace->a_perm));
1057
1058                 g_ace->ace_perm = 0;
1059
1060                 switch(ace->a_type) {
1061                 case SMB_ACL_USER:
1062                         g_ace->ace_type = GPFS_ACL_USER;
1063                         g_ace->ace_who = (gpfs_uid_t)ace->info.user.uid;
1064                         break;
1065                 case SMB_ACL_USER_OBJ:
1066                         g_ace->ace_type = GPFS_ACL_USER_OBJ;
1067                         g_ace->ace_perm |= ACL_PERM_CONTROL;
1068                         g_ace->ace_who = 0;
1069                         break;
1070                 case SMB_ACL_GROUP:
1071                         g_ace->ace_type = GPFS_ACL_GROUP;
1072                         g_ace->ace_who = (gpfs_uid_t)ace->info.group.gid;
1073                         break;
1074                 case SMB_ACL_GROUP_OBJ:
1075                         g_ace->ace_type = GPFS_ACL_GROUP_OBJ;
1076                         g_ace->ace_who = 0;
1077                         break;
1078                 case SMB_ACL_MASK:
1079                         g_ace->ace_type = GPFS_ACL_MASK;
1080                         g_ace->ace_perm = 0x8f;
1081                         g_ace->ace_who = 0;
1082                         break;
1083                 case SMB_ACL_OTHER:
1084                         g_ace->ace_type = GPFS_ACL_OTHER;
1085                         g_ace->ace_who = 0;
1086                         break;
1087                 default:
1088                         DEBUG(10, ("Got invalid ace_type: %d\n", ace->a_type));
1089                         errno = EINVAL;
1090                         SAFE_FREE(result);
1091                         return NULL;
1092                 }
1093
1094                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_READ) ?
1095                         ACL_PERM_READ : 0;
1096                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_WRITE) ?
1097                         ACL_PERM_WRITE : 0;
1098                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_EXECUTE) ?
1099                         ACL_PERM_EXECUTE : 0;
1100
1101                 DEBUGADD(10, ("Converted to %d id %d perm %x\n",
1102                               g_ace->ace_type, g_ace->ace_who, g_ace->ace_perm));
1103         }
1104
1105         return result;
1106 }
1107
1108 static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
1109                                     const char *name,
1110                                     SMB_ACL_TYPE_T type,
1111                                     SMB_ACL_T theacl)
1112 {
1113         struct gpfs_acl *gpfs_acl;
1114         int result;
1115         struct gpfs_config_data *config;
1116
1117         SMB_VFS_HANDLE_GET_DATA(handle, config,
1118                                 struct gpfs_config_data,
1119                                 return -1);
1120
1121         if (!config->acl) {
1122                 return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, name, type, theacl);
1123         }
1124
1125         gpfs_acl = smb2gpfs_acl(theacl, type);
1126         if (gpfs_acl == NULL) {
1127                 return -1;
1128         }
1129
1130         result = gpfswrap_putacl(discard_const_p(char, name),
1131                                  GPFS_PUTACL_STRUCT|GPFS_ACL_SAMBA, gpfs_acl);
1132
1133         SAFE_FREE(gpfs_acl);
1134         return result;
1135 }
1136
1137 static int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
1138                                   files_struct *fsp,
1139                                   SMB_ACL_T theacl)
1140 {
1141         struct gpfs_config_data *config;
1142
1143         SMB_VFS_HANDLE_GET_DATA(handle, config,
1144                                 struct gpfs_config_data,
1145                                 return -1);
1146
1147         if (!config->acl) {
1148                 return SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, theacl);
1149         }
1150
1151         return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name->base_name,
1152                                         SMB_ACL_TYPE_ACCESS, theacl);
1153 }
1154
1155 static int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
1156                                            const char *path)
1157 {
1158         struct gpfs_config_data *config;
1159
1160         SMB_VFS_HANDLE_GET_DATA(handle, config,
1161                                 struct gpfs_config_data,
1162                                 return -1);
1163
1164         if (!config->acl) {
1165                 return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, path);
1166         }
1167
1168         errno = ENOTSUP;
1169         return -1;
1170 }
1171
1172 /*
1173  * Assumed: mode bits are shiftable and standard
1174  * Output: the new aceMask field for an smb nfs4 ace
1175  */
1176 static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx)
1177 {
1178         const uint32 posix_nfs4map[3] = {
1179                 SMB_ACE4_EXECUTE, /* execute */
1180                 SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
1181                 SMB_ACE4_READ_DATA /* read */
1182         };
1183         int     i;
1184         uint32_t        posix_mask = 0x01;
1185         uint32_t        posix_bit;
1186         uint32_t        nfs4_bits;
1187
1188         for(i=0; i<3; i++) {
1189                 nfs4_bits = posix_nfs4map[i];
1190                 posix_bit = rwx & posix_mask;
1191
1192                 if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
1193                         if (posix_bit)
1194                                 aceMask |= nfs4_bits;
1195                         else
1196                                 aceMask &= ~nfs4_bits;
1197                 } else {
1198                         /* add deny bits when suitable */
1199                         if (!posix_bit)
1200                                 aceMask |= nfs4_bits;
1201                         else
1202                                 aceMask &= ~nfs4_bits;
1203                 } /* other ace types are unexpected */
1204
1205                 posix_mask <<= 1;
1206         }
1207
1208         return aceMask;
1209 }
1210
1211 static int gpfsacl_emu_chmod(vfs_handle_struct *handle,
1212                              const char *path, mode_t mode)
1213 {
1214         SMB4ACL_T *pacl = NULL;
1215         int     result;
1216         bool    haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
1217         int     i;
1218         files_struct    fake_fsp; /* TODO: rationalize parametrization */
1219         SMB4ACE_T       *smbace;
1220         TALLOC_CTX *frame = talloc_stackframe();
1221
1222         DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
1223
1224         result = gpfs_get_nfs4_acl(frame, path, &pacl);
1225         if (result) {
1226                 TALLOC_FREE(frame);
1227                 return result;
1228         }
1229
1230         if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
1231                 DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
1232         }
1233
1234         for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
1235                 SMB_ACE4PROP_T  *ace = smb_get_ace4(smbace);
1236                 uint32_t        specid = ace->who.special_id;
1237
1238                 if (ace->flags&SMB_ACE4_ID_SPECIAL &&
1239                     ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
1240                     specid <= SMB_ACE4_WHO_EVERYONE) {
1241
1242                         uint32_t newMask;
1243
1244                         if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
1245                                 haveAllowEntry[specid] = True;
1246
1247                         /* mode >> 6 for @owner, mode >> 3 for @group,
1248                          * mode >> 0 for @everyone */
1249                         newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
1250                                                       mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
1251                         if (ace->aceMask!=newMask) {
1252                                 DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
1253                                            path, ace->aceMask, newMask, specid));
1254                         }
1255                         ace->aceMask = newMask;
1256                 }
1257         }
1258
1259         /* make sure we have at least ALLOW entries
1260          * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
1261          * - if necessary
1262          */
1263         for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
1264                 SMB_ACE4PROP_T  ace;
1265
1266                 if (haveAllowEntry[i]==True)
1267                         continue;
1268
1269                 ZERO_STRUCT(ace);
1270                 ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
1271                 ace.flags |= SMB_ACE4_ID_SPECIAL;
1272                 ace.who.special_id = i;
1273
1274                 if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
1275                         ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
1276
1277                 ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
1278                                                   mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
1279
1280                 /* don't add unnecessary aces */
1281                 if (!ace.aceMask)
1282                         continue;
1283
1284                 /* we add it to the END - as windows expects allow aces */
1285                 smb_add_ace4(pacl, &ace);
1286                 DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
1287                            path, mode, i, ace.aceMask));
1288         }
1289
1290         /* don't add complementary DENY ACEs here */
1291         ZERO_STRUCT(fake_fsp);
1292         fake_fsp.fsp_name = synthetic_smb_fname(
1293                 frame, path, NULL, NULL);
1294         if (fake_fsp.fsp_name == NULL) {
1295                 errno = ENOMEM;
1296                 TALLOC_FREE(frame);
1297                 return -1;
1298         }
1299         /* put the acl */
1300         if (gpfsacl_process_smbacl(handle, &fake_fsp, pacl) == False) {
1301                 TALLOC_FREE(frame);
1302                 return -1;
1303         }
1304
1305         TALLOC_FREE(frame);
1306         return 0; /* ok for [f]chmod */
1307 }
1308
1309 static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
1310 {
1311         struct smb_filename *smb_fname_cpath;
1312         int rc;
1313
1314         smb_fname_cpath = synthetic_smb_fname(talloc_tos(), path, NULL, NULL);
1315         if (smb_fname_cpath == NULL) {
1316                 errno = ENOMEM;
1317                 return -1;
1318         }
1319
1320         if (SMB_VFS_NEXT_STAT(handle, smb_fname_cpath) != 0) {
1321                 return -1;
1322         }
1323
1324         /* avoid chmod() if possible, to preserve acls */
1325         if ((smb_fname_cpath->st.st_ex_mode & ~S_IFMT) == mode) {
1326                 return 0;
1327         }
1328
1329         rc = gpfsacl_emu_chmod(handle, path, mode);
1330         if (rc == 1)
1331                 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
1332         return rc;
1333 }
1334
1335 static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
1336 {
1337                  SMB_STRUCT_STAT st;
1338                  int rc;
1339
1340                  if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
1341                          return -1;
1342                  }
1343
1344                  /* avoid chmod() if possible, to preserve acls */
1345                  if ((st.st_ex_mode & ~S_IFMT) == mode) {
1346                          return 0;
1347                  }
1348
1349                  rc = gpfsacl_emu_chmod(handle, fsp->fsp_name->base_name,
1350                                         mode);
1351                  if (rc == 1)
1352                          return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1353                  return rc;
1354 }
1355
1356 static int gpfs_set_xattr(struct vfs_handle_struct *handle,  const char *path,
1357                            const char *name, const void *value, size_t size,  int flags){
1358         struct xattr_DOSATTRIB dosattrib;
1359         enum ndr_err_code ndr_err;
1360         DATA_BLOB blob;
1361         unsigned int dosmode=0;
1362         struct gpfs_winattr attrs;
1363         int ret = 0;
1364         struct gpfs_config_data *config;
1365
1366         SMB_VFS_HANDLE_GET_DATA(handle, config,
1367                                 struct gpfs_config_data,
1368                                 return -1);
1369
1370         if (!config->winattr) {
1371                 DEBUG(10, ("gpfs_set_xattr:name is %s -> next\n",name));
1372                 return SMB_VFS_NEXT_SETXATTR(handle,path,name,value,size,flags);
1373         }
1374
1375         DEBUG(10, ("gpfs_set_xattr: %s \n",path));
1376
1377         /* Only handle DOS Attributes */
1378         if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
1379                 DEBUG(5, ("gpfs_set_xattr:name is %s\n",name));
1380                 return SMB_VFS_NEXT_SETXATTR(handle,path,name,value,size,flags);
1381         }
1382
1383         blob.data = discard_const_p(uint8_t, value);
1384         blob.length = size;
1385
1386         ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
1387                         (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
1388
1389         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1390                 DEBUG(1, ("gpfs_set_xattr: bad ndr decode "
1391                           "from EA on file %s: Error = %s\n",
1392                           path, ndr_errstr(ndr_err)));
1393                 return false;
1394         }
1395
1396         if (dosattrib.version != 3) {
1397                 DEBUG(1, ("gpfs_set_xattr: expected dosattrib version 3, got "
1398                           "%d\n", (int)dosattrib.version));
1399                 return false;
1400         }
1401         if (!(dosattrib.info.info3.valid_flags & XATTR_DOSINFO_ATTRIB)) {
1402                 DEBUG(10, ("gpfs_set_xattr: XATTR_DOSINFO_ATTRIB not "
1403                            "valid, ignoring\n"));
1404                 return true;
1405         }
1406
1407         dosmode = dosattrib.info.info3.attrib;
1408
1409         attrs.winAttrs = 0;
1410         /*Just map RD_ONLY, ARCHIVE, SYSTEM HIDDEN and SPARSE. Ignore the others*/
1411         if (dosmode & FILE_ATTRIBUTE_ARCHIVE){
1412                 attrs.winAttrs |= GPFS_WINATTR_ARCHIVE;
1413         }
1414         if (dosmode & FILE_ATTRIBUTE_HIDDEN){
1415                         attrs.winAttrs |= GPFS_WINATTR_HIDDEN;
1416                 }
1417         if (dosmode & FILE_ATTRIBUTE_SYSTEM){
1418                         attrs.winAttrs |= GPFS_WINATTR_SYSTEM;
1419                 }
1420         if (dosmode & FILE_ATTRIBUTE_READONLY){
1421                         attrs.winAttrs |= GPFS_WINATTR_READONLY;
1422         }
1423         if (dosmode & FILE_ATTRIBUTE_SPARSE) {
1424                 attrs.winAttrs |= GPFS_WINATTR_SPARSE_FILE;
1425         }
1426
1427
1428         ret = gpfswrap_set_winattrs_path(discard_const_p(char, path),
1429                                          GPFS_WINATTR_SET_ATTRS, &attrs);
1430         if ( ret == -1){
1431                 if (errno == ENOSYS) {
1432                         return SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
1433                                                      size, flags);
1434                 }
1435
1436                 DEBUG(1, ("gpfs_set_xattr:Set GPFS attributes failed %d\n",ret));
1437                 return -1;
1438         }
1439
1440         DEBUG(10, ("gpfs_set_xattr:Set attributes: 0x%x\n",attrs.winAttrs));
1441         return 0;
1442 }
1443
1444 static ssize_t gpfs_get_xattr(struct vfs_handle_struct *handle,  const char *path,
1445                               const char *name, void *value, size_t size){
1446         char *attrstr = value;
1447         unsigned int dosmode = 0;
1448         struct gpfs_winattr attrs;
1449         int ret = 0;
1450         struct gpfs_config_data *config;
1451
1452         SMB_VFS_HANDLE_GET_DATA(handle, config,
1453                                 struct gpfs_config_data,
1454                                 return -1);
1455
1456         if (!config->winattr) {
1457                 DEBUG(10, ("gpfs_get_xattr:name is %s -> next\n",name));
1458                 return SMB_VFS_NEXT_GETXATTR(handle,path,name,value,size);
1459         }
1460
1461         DEBUG(10, ("gpfs_get_xattr: %s \n",path));
1462
1463         /* Only handle DOS Attributes */
1464         if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
1465                 DEBUG(5, ("gpfs_get_xattr:name is %s\n",name));
1466                 return SMB_VFS_NEXT_GETXATTR(handle,path,name,value,size);
1467         }
1468
1469         ret = gpfswrap_get_winattrs_path(discard_const_p(char, path), &attrs);
1470         if ( ret == -1){
1471                 int dbg_lvl;
1472
1473                 if (errno == ENOSYS) {
1474                         return SMB_VFS_NEXT_GETXATTR(handle, path, name, value,
1475                                                      size);
1476                 }
1477
1478                 if (errno != EPERM && errno != EACCES) {
1479                         dbg_lvl = 1;
1480                 } else {
1481                         dbg_lvl = 5;
1482                 }
1483                 DEBUG(dbg_lvl, ("gpfs_get_xattr: Get GPFS attributes failed: "
1484                               "%d (%s)\n", ret, strerror(errno)));
1485                 return -1;
1486         }
1487
1488         DEBUG(10, ("gpfs_get_xattr:Got attributes: 0x%x\n",attrs.winAttrs));
1489
1490         /*Just map RD_ONLY, ARCHIVE, SYSTEM, HIDDEN and SPARSE. Ignore the others*/
1491         if (attrs.winAttrs & GPFS_WINATTR_ARCHIVE){
1492                 dosmode |= FILE_ATTRIBUTE_ARCHIVE;
1493         }
1494         if (attrs.winAttrs & GPFS_WINATTR_HIDDEN){
1495                 dosmode |= FILE_ATTRIBUTE_HIDDEN;
1496         }
1497         if (attrs.winAttrs & GPFS_WINATTR_SYSTEM){
1498                 dosmode |= FILE_ATTRIBUTE_SYSTEM;
1499         }
1500         if (attrs.winAttrs & GPFS_WINATTR_READONLY){
1501                 dosmode |= FILE_ATTRIBUTE_READONLY;
1502         }
1503         if (attrs.winAttrs & GPFS_WINATTR_SPARSE_FILE) {
1504                 dosmode |= FILE_ATTRIBUTE_SPARSE;
1505         }
1506
1507         snprintf(attrstr, size, "0x%2.2x",
1508                  (unsigned int)(dosmode & SAMBA_ATTRIBUTES_MASK));
1509         DEBUG(10, ("gpfs_get_xattr: returning %s\n",attrstr));
1510         return 4;
1511 }
1512
1513 #if defined(HAVE_FSTATAT)
1514 static int stat_with_capability(struct vfs_handle_struct *handle,
1515                                 struct smb_filename *smb_fname, int flag)
1516 {
1517         int fd = -1;
1518         bool b;
1519         char *dir_name;
1520         const char *rel_name = NULL;
1521         struct stat st;
1522         int ret = -1;
1523
1524         b = parent_dirname(talloc_tos(), smb_fname->base_name,
1525                            &dir_name, &rel_name);
1526         if (!b) {
1527                 errno = ENOMEM;
1528                 return -1;
1529         }
1530
1531         fd = open(dir_name, O_RDONLY, 0);
1532         TALLOC_FREE(dir_name);
1533         if (fd == -1) {
1534                 return -1;
1535         }
1536
1537         set_effective_capability(DAC_OVERRIDE_CAPABILITY);
1538         ret = fstatat(fd, rel_name, &st, flag);
1539         drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
1540
1541         close(fd);
1542
1543         if (ret == 0) {
1544                 init_stat_ex_from_stat(
1545                         &smb_fname->st, &st,
1546                         lp_fake_directory_create_times(SNUM(handle->conn)));
1547         }
1548
1549         return ret;
1550 }
1551 #endif
1552
1553 static int vfs_gpfs_stat(struct vfs_handle_struct *handle,
1554                          struct smb_filename *smb_fname)
1555 {
1556         struct gpfs_winattr attrs;
1557         char *fname = NULL;
1558         NTSTATUS status;
1559         int ret;
1560         struct gpfs_config_data *config;
1561
1562         SMB_VFS_HANDLE_GET_DATA(handle, config,
1563                                 struct gpfs_config_data,
1564                                 return -1);
1565
1566         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1567 #if defined(HAVE_FSTATAT)
1568         if (ret == -1 && errno == EACCES) {
1569                 DEBUG(10, ("Trying stat with capability for %s\n",
1570                            smb_fname->base_name));
1571                 ret = stat_with_capability(handle, smb_fname, 0);
1572         }
1573 #endif
1574         if (ret == -1) {
1575                 return -1;
1576         }
1577
1578         if (!config->winattr) {
1579                 return 0;
1580         }
1581
1582         status = get_full_smb_filename(talloc_tos(), smb_fname, &fname);
1583         if (!NT_STATUS_IS_OK(status)) {
1584                 errno = map_errno_from_nt_status(status);
1585                 return -1;
1586         }
1587         ret = gpfswrap_get_winattrs_path(discard_const_p(char, fname), &attrs);
1588         TALLOC_FREE(fname);
1589         if (ret == 0) {
1590                 smb_fname->st.st_ex_calculated_birthtime = false;
1591                 smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1592                 smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1593         }
1594         return 0;
1595 }
1596
1597 static int vfs_gpfs_fstat(struct vfs_handle_struct *handle,
1598                           struct files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1599 {
1600         struct gpfs_winattr attrs;
1601         int ret;
1602         struct gpfs_config_data *config;
1603
1604         SMB_VFS_HANDLE_GET_DATA(handle, config,
1605                                 struct gpfs_config_data,
1606                                 return -1);
1607
1608         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1609         if (ret == -1) {
1610                 return -1;
1611         }
1612         if ((fsp->fh == NULL) || (fsp->fh->fd == -1)) {
1613                 return 0;
1614         }
1615         if (!config->winattr) {
1616                 return 0;
1617         }
1618
1619         ret = gpfswrap_get_winattrs(fsp->fh->fd, &attrs);
1620         if (ret == 0) {
1621                 sbuf->st_ex_calculated_birthtime = false;
1622                 sbuf->st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1623                 sbuf->st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1624         }
1625         return 0;
1626 }
1627
1628 static int vfs_gpfs_lstat(struct vfs_handle_struct *handle,
1629                           struct smb_filename *smb_fname)
1630 {
1631         struct gpfs_winattr attrs;
1632         char *path = NULL;
1633         NTSTATUS status;
1634         int ret;
1635         struct gpfs_config_data *config;
1636
1637         SMB_VFS_HANDLE_GET_DATA(handle, config,
1638                                 struct gpfs_config_data,
1639                                 return -1);
1640
1641         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1642 #if defined(HAVE_FSTATAT)
1643         if (ret == -1 && errno == EACCES) {
1644                 DEBUG(10, ("Trying lstat with capability for %s\n",
1645                            smb_fname->base_name));
1646                 ret = stat_with_capability(handle, smb_fname,
1647                                            AT_SYMLINK_NOFOLLOW);
1648         }
1649 #endif
1650
1651         if (ret == -1) {
1652                 return -1;
1653         }
1654         if (!config->winattr) {
1655                 return 0;
1656         }
1657
1658         status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1659         if (!NT_STATUS_IS_OK(status)) {
1660                 errno = map_errno_from_nt_status(status);
1661                 return -1;
1662         }
1663         ret = gpfswrap_get_winattrs_path(discard_const_p(char, path), &attrs);
1664         TALLOC_FREE(path);
1665         if (ret == 0) {
1666                 smb_fname->st.st_ex_calculated_birthtime = false;
1667                 smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1668                 smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1669         }
1670         return 0;
1671 }
1672
1673 static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
1674                         const struct smb_filename *smb_fname,
1675                         struct smb_file_time *ft)
1676 {
1677
1678         struct gpfs_winattr attrs;
1679         int ret;
1680         char *path = NULL;
1681         NTSTATUS status;
1682         struct gpfs_config_data *config;
1683
1684         SMB_VFS_HANDLE_GET_DATA(handle, config,
1685                                 struct gpfs_config_data,
1686                                 return -1);
1687
1688         status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1689         if (!NT_STATUS_IS_OK(status)) {
1690                 errno = map_errno_from_nt_status(status);
1691                 return -1;
1692         }
1693
1694         /* Try to use gpfs_set_times if it is enabled and available */
1695         if (config->settimes) {
1696                 ret = smbd_gpfs_set_times_path(path, ft);
1697
1698                 if (ret == 0 || (ret == -1 && errno != ENOSYS)) {
1699                         return ret;
1700                 }
1701         }
1702
1703         DEBUG(10,("gpfs_set_times() not available or disabled, "
1704                   "use ntimes and winattr\n"));
1705
1706         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1707         if(ret == -1){
1708                 /* don't complain if access was denied */
1709                 if (errno != EPERM && errno != EACCES) {
1710                         DEBUG(1,("vfs_gpfs_ntimes: SMB_VFS_NEXT_NTIMES failed:"
1711                                  "%s", strerror(errno)));
1712                 }
1713                 return -1;
1714         }
1715
1716         if(null_timespec(ft->create_time)){
1717                 DEBUG(10,("vfs_gpfs_ntimes:Create Time is NULL\n"));
1718                 return 0;
1719         }
1720
1721         if (!config->winattr) {
1722                 return 0;
1723         }
1724
1725         attrs.winAttrs = 0;
1726         attrs.creationTime.tv_sec = ft->create_time.tv_sec;
1727         attrs.creationTime.tv_nsec = ft->create_time.tv_nsec;
1728
1729         ret = gpfswrap_set_winattrs_path(discard_const_p(char, path),
1730                                          GPFS_WINATTR_SET_CREATION_TIME,
1731                                          &attrs);
1732         if(ret == -1 && errno != ENOSYS){
1733                 DEBUG(1,("vfs_gpfs_ntimes: set GPFS ntimes failed %d\n",ret));
1734                 return -1;
1735         }
1736         return 0;
1737
1738 }
1739
1740 static int vfs_gpfs_fallocate(struct vfs_handle_struct *handle,
1741                        struct files_struct *fsp, enum vfs_fallocate_mode mode,
1742                        off_t offset, off_t len)
1743 {
1744         int ret;
1745         struct gpfs_config_data *config;
1746
1747         SMB_VFS_HANDLE_GET_DATA(handle, config,
1748                                 struct gpfs_config_data,
1749                                 return -1);
1750
1751         if (!config->prealloc) {
1752                 /* you should better not run fallocate() on GPFS at all */
1753                 errno = ENOTSUP;
1754                 return -1;
1755         }
1756
1757         if (mode == VFS_FALLOCATE_KEEP_SIZE) {
1758                 DEBUG(10, ("Unsupported VFS_FALLOCATE_KEEP_SIZE\n"));
1759                 errno = ENOTSUP;
1760                 return -1;
1761         }
1762
1763         ret = gpfswrap_prealloc(fsp->fh->fd, offset, len);
1764
1765         if (ret == -1 && errno != ENOSYS) {
1766                 DEBUG(0, ("GPFS prealloc failed: %s\n", strerror(errno)));
1767         } else if (ret == -1 && errno == ENOSYS) {
1768                 DEBUG(10, ("GPFS prealloc not supported.\n"));
1769         } else {
1770                 DEBUG(10, ("GPFS prealloc succeeded.\n"));
1771         }
1772
1773         return ret;
1774 }
1775
1776 static int vfs_gpfs_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
1777                                 off_t len)
1778 {
1779         int result;
1780         struct gpfs_config_data *config;
1781
1782         SMB_VFS_HANDLE_GET_DATA(handle, config,
1783                                 struct gpfs_config_data,
1784                                 return -1);
1785
1786         if (!config->ftruncate) {
1787                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
1788         }
1789
1790         result = smbd_gpfs_ftruncate(fsp->fh->fd, len);
1791         if ((result == -1) && (errno == ENOSYS)) {
1792                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
1793         }
1794         return result;
1795 }
1796
1797 static bool vfs_gpfs_is_offline(struct vfs_handle_struct *handle,
1798                                 const struct smb_filename *fname,
1799                                 SMB_STRUCT_STAT *sbuf)
1800 {
1801         struct gpfs_winattr attrs;
1802         char *path = NULL;
1803         NTSTATUS status;
1804         struct gpfs_config_data *config;
1805         int ret;
1806
1807         SMB_VFS_HANDLE_GET_DATA(handle, config,
1808                                 struct gpfs_config_data,
1809                                 return -1);
1810
1811         if (!config->winattr) {
1812                 return SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
1813         }
1814
1815         status = get_full_smb_filename(talloc_tos(), fname, &path);
1816         if (!NT_STATUS_IS_OK(status)) {
1817                 errno = map_errno_from_nt_status(status);
1818                 return -1;
1819         }
1820
1821         ret = gpfswrap_get_winattrs_path(path, &attrs);
1822         if (ret == -1) {
1823                 TALLOC_FREE(path);
1824                 return false;
1825         }
1826
1827         if ((attrs.winAttrs & GPFS_WINATTR_OFFLINE) != 0) {
1828                 DEBUG(10, ("%s is offline\n", path));
1829                 TALLOC_FREE(path);
1830                 return true;
1831         }
1832         DEBUG(10, ("%s is online\n", path));
1833         TALLOC_FREE(path);
1834         return SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
1835 }
1836
1837 static bool vfs_gpfs_aio_force(struct vfs_handle_struct *handle,
1838                                struct files_struct *fsp)
1839 {
1840         return vfs_gpfs_is_offline(handle, fsp->fsp_name, &fsp->fsp_name->st);
1841 }
1842
1843 static ssize_t vfs_gpfs_sendfile(vfs_handle_struct *handle, int tofd,
1844                                  files_struct *fsp, const DATA_BLOB *hdr,
1845                                  off_t offset, size_t n)
1846 {
1847         if (SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name, &fsp->fsp_name->st))
1848         {
1849                 errno = ENOSYS;
1850                 return -1;
1851         }
1852         return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, hdr, offset, n);
1853 }
1854
1855 static int vfs_gpfs_connect(struct vfs_handle_struct *handle,
1856                             const char *service, const char *user)
1857 {
1858         struct gpfs_config_data *config;
1859         int ret;
1860
1861         smbd_gpfs_lib_init();
1862
1863         config = talloc_zero(handle->conn, struct gpfs_config_data);
1864         if (!config) {
1865                 DEBUG(0, ("talloc_zero() failed\n"));
1866                 errno = ENOMEM;
1867                 return -1;
1868         }
1869
1870         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
1871         if (ret < 0) {
1872                 TALLOC_FREE(config);
1873                 return ret;
1874         }
1875
1876         config->sharemodes = lp_parm_bool(SNUM(handle->conn), "gpfs",
1877                                         "sharemodes", true);
1878
1879         config->leases = lp_parm_bool(SNUM(handle->conn), "gpfs",
1880                                         "leases", true);
1881
1882         config->hsm = lp_parm_bool(SNUM(handle->conn), "gpfs",
1883                                    "hsm", false);
1884
1885         config->syncio = lp_parm_bool(SNUM(handle->conn), "gpfs",
1886                                       "syncio", false);
1887
1888         config->winattr = lp_parm_bool(SNUM(handle->conn), "gpfs",
1889                                        "winattr", false);
1890
1891         config->ftruncate = lp_parm_bool(SNUM(handle->conn), "gpfs",
1892                                          "ftruncate", true);
1893
1894         config->getrealfilename = lp_parm_bool(SNUM(handle->conn), "gpfs",
1895                                                "getrealfilename", true);
1896
1897         config->dfreequota = lp_parm_bool(SNUM(handle->conn), "gpfs",
1898                                           "dfreequota", false);
1899
1900         config->prealloc = lp_parm_bool(SNUM(handle->conn), "gpfs",
1901                                    "prealloc", true);
1902
1903         config->acl = lp_parm_bool(SNUM(handle->conn), "gpfs", "acl", true);
1904
1905         config->settimes = lp_parm_bool(SNUM(handle->conn), "gpfs",
1906                                         "settimes", true);
1907         config->recalls = lp_parm_bool(SNUM(handle->conn), "gpfs",
1908                                        "recalls", true);
1909
1910         SMB_VFS_HANDLE_SET_DATA(handle, config,
1911                                 NULL, struct gpfs_config_data,
1912                                 return -1);
1913
1914         if (config->leases) {
1915                 /*
1916                  * GPFS lease code is based on kernel oplock code
1917                  * so make sure it is turned on
1918                  */
1919                 if (!lp_kernel_oplocks(SNUM(handle->conn))) {
1920                         DEBUG(5, ("Enabling kernel oplocks for "
1921                                   "gpfs:leases to work\n"));
1922                         lp_do_parameter(SNUM(handle->conn), "kernel oplocks",
1923                                         "true");
1924                 }
1925
1926                 /*
1927                  * as the kernel does not properly support Level II oplocks
1928                  * and GPFS leases code is based on kernel infrastructure, we
1929                  * need to turn off Level II oplocks if gpfs:leases is enabled
1930                  */
1931                 if (lp_level2_oplocks(SNUM(handle->conn))) {
1932                         DEBUG(5, ("gpfs:leases are enabled, disabling "
1933                                   "Level II oplocks\n"));
1934                         lp_do_parameter(SNUM(handle->conn), "level2 oplocks",
1935                                         "false");
1936                 }
1937         }
1938
1939         return 0;
1940 }
1941
1942 static int vfs_gpfs_get_quotas(const char *path, uid_t uid, gid_t gid,
1943                                int *fset_id,
1944                                struct gpfs_quotaInfo *qi_user,
1945                                struct gpfs_quotaInfo *qi_group,
1946                                struct gpfs_quotaInfo *qi_fset)
1947 {
1948         int err;
1949         char *dir_path;
1950         bool b;
1951
1952         /*
1953          * We want to always use the directory to get the fileset id,
1954          * because files might have a share mode. We also do not want
1955          * to get the parent directory when there is already a
1956          * directory to avoid stepping in a different fileset.  The
1957          * path passed here is currently either "." or a filename, so
1958          * this is ok. The proper solution would be having a way to
1959          * query the fileset id without opening the file.
1960          */
1961         b = parent_dirname(talloc_tos(), path, &dir_path, NULL);
1962         if (!b) {
1963                 errno = ENOMEM;
1964                 return -1;
1965         }
1966
1967         DEBUG(10, ("path %s, directory %s\n", path, dir_path));
1968
1969         err = get_gpfs_fset_id(dir_path, fset_id);
1970         if (err) {
1971                 DEBUG(0, ("Get fset id failed path %s, dir %s, errno %d.\n",
1972                           path, dir_path, errno));
1973                 return err;
1974         }
1975
1976         err = get_gpfs_quota(path, GPFS_USRQUOTA, uid, qi_user);
1977         if (err) {
1978                 return err;
1979         }
1980
1981         err = get_gpfs_quota(path, GPFS_GRPQUOTA, gid, qi_group);
1982         if (err) {
1983                 return err;
1984         }
1985
1986         err = get_gpfs_quota(path, GPFS_FILESETQUOTA, *fset_id, qi_fset);
1987         if (err) {
1988                 return err;
1989         }
1990
1991         return 0;
1992 }
1993
1994 static void vfs_gpfs_disk_free_quota(struct gpfs_quotaInfo qi, time_t cur_time,
1995                                      uint64_t *dfree, uint64_t *dsize)
1996 {
1997         uint64_t usage, limit;
1998
1999         /*
2000          * The quota reporting is done in units of 1024 byte blocks, but
2001          * sys_fsusage uses units of 512 byte blocks, adjust the block number
2002          * accordingly. Also filter possibly negative usage counts from gpfs.
2003          */
2004         usage = qi.blockUsage < 0 ? 0 : (uint64_t)qi.blockUsage * 2;
2005         limit = (uint64_t)qi.blockHardLimit * 2;
2006
2007         /*
2008          * When the grace time for the exceeded soft block quota has been
2009          * exceeded, the soft block quota becomes an additional hard limit.
2010          */
2011         if (qi.blockSoftLimit &&
2012             qi.blockGraceTime && cur_time > qi.blockGraceTime) {
2013                 /* report disk as full */
2014                 *dfree = 0;
2015                 *dsize = MIN(*dsize, usage);
2016         }
2017
2018         if (!qi.blockHardLimit)
2019                 return;
2020
2021         if (usage >= limit) {
2022                 /* report disk as full */
2023                 *dfree = 0;
2024                 *dsize = MIN(*dsize, usage);
2025
2026         } else {
2027                 /* limit has not been reached, determine "free space" */
2028                 *dfree = MIN(*dfree, limit - usage);
2029                 *dsize = MIN(*dsize, limit);
2030         }
2031 }
2032
2033 static uint64_t vfs_gpfs_disk_free(vfs_handle_struct *handle, const char *path,
2034                                    uint64_t *bsize,
2035                                    uint64_t *dfree, uint64_t *dsize)
2036 {
2037         struct security_unix_token *utok;
2038         struct gpfs_quotaInfo qi_user, qi_group, qi_fset;
2039         struct gpfs_config_data *config;
2040         int err, fset_id;
2041         time_t cur_time;
2042
2043         SMB_VFS_HANDLE_GET_DATA(handle, config, struct gpfs_config_data,
2044                                 return (uint64_t)-1);
2045         if (!config->dfreequota) {
2046                 return SMB_VFS_NEXT_DISK_FREE(handle, path,
2047                                               bsize, dfree, dsize);
2048         }
2049
2050         err = sys_fsusage(path, dfree, dsize);
2051         if (err) {
2052                 DEBUG (0, ("Could not get fs usage, errno %d\n", errno));
2053                 return SMB_VFS_NEXT_DISK_FREE(handle, path,
2054                                               bsize, dfree, dsize);
2055         }
2056
2057         /* sys_fsusage returns units of 512 bytes */
2058         *bsize = 512;
2059
2060         DEBUG(10, ("fs dfree %llu, dsize %llu\n",
2061                    (unsigned long long)*dfree, (unsigned long long)*dsize));
2062
2063         utok = handle->conn->session_info->unix_token;
2064         err = vfs_gpfs_get_quotas(path, utok->uid, utok->gid, &fset_id,
2065                                   &qi_user, &qi_group, &qi_fset);
2066         if (err) {
2067                 return SMB_VFS_NEXT_DISK_FREE(handle, path,
2068                                               bsize, dfree, dsize);
2069         }
2070
2071         cur_time = time(NULL);
2072
2073         /* Adjust free space and size according to quota limits. */
2074         vfs_gpfs_disk_free_quota(qi_user, cur_time, dfree, dsize);
2075         vfs_gpfs_disk_free_quota(qi_group, cur_time, dfree, dsize);
2076
2077         /* Id 0 indicates the default quota, not an actual quota */
2078         if (fset_id != 0) {
2079                 vfs_gpfs_disk_free_quota(qi_fset, cur_time, dfree, dsize);
2080         }
2081
2082         disk_norm(bsize, dfree, dsize);
2083         return *dfree;
2084 }
2085
2086 static uint32_t vfs_gpfs_capabilities(struct vfs_handle_struct *handle,
2087                                       enum timestamp_set_resolution *p_ts_res)
2088 {
2089         struct gpfs_config_data *config;
2090         uint32_t next;
2091
2092         next = SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res);
2093
2094         SMB_VFS_HANDLE_GET_DATA(handle, config,
2095                                 struct gpfs_config_data,
2096                                 return next);
2097
2098         if (config->hsm) {
2099                 next |= FILE_SUPPORTS_REMOTE_STORAGE;
2100         }
2101         return next;
2102 }
2103
2104 static int vfs_gpfs_open(struct vfs_handle_struct *handle,
2105                          struct smb_filename *smb_fname, files_struct *fsp,
2106                          int flags, mode_t mode)
2107 {
2108         struct gpfs_config_data *config;
2109
2110         SMB_VFS_HANDLE_GET_DATA(handle, config,
2111                                 struct gpfs_config_data,
2112                                 return -1);
2113
2114         if (config->hsm && !config->recalls) {
2115                 if (SMB_VFS_IS_OFFLINE(handle->conn, smb_fname, &smb_fname->st))
2116                 {
2117                         DEBUG(10, ("Refusing access to offline file %s\n",
2118                                   fsp_str_dbg(fsp)));
2119                         errno = EACCES;
2120                         return -1;
2121                 }
2122         }
2123
2124         if (config->syncio) {
2125                 flags |= O_SYNC;
2126         }
2127         return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
2128 }
2129
2130 static ssize_t vfs_gpfs_pread(vfs_handle_struct *handle, files_struct *fsp,
2131                               void *data, size_t n, off_t offset)
2132 {
2133         ssize_t ret;
2134         bool was_offline;
2135
2136         was_offline = SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name,
2137                                          &fsp->fsp_name->st);
2138
2139         ret = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
2140
2141         if ((ret != -1) && was_offline) {
2142                 notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
2143                              FILE_NOTIFY_CHANGE_ATTRIBUTES,
2144                              fsp->fsp_name->base_name);
2145         }
2146
2147         return ret;
2148 }
2149
2150 struct vfs_gpfs_pread_state {
2151         struct files_struct *fsp;
2152         ssize_t ret;
2153         int err;
2154         bool was_offline;
2155 };
2156
2157 static void vfs_gpfs_pread_done(struct tevent_req *subreq);
2158
2159 static struct tevent_req *vfs_gpfs_pread_send(struct vfs_handle_struct *handle,
2160                                               TALLOC_CTX *mem_ctx,
2161                                               struct tevent_context *ev,
2162                                               struct files_struct *fsp,
2163                                               void *data, size_t n,
2164                                               off_t offset)
2165 {
2166         struct tevent_req *req, *subreq;
2167         struct vfs_gpfs_pread_state *state;
2168
2169         req = tevent_req_create(mem_ctx, &state, struct vfs_gpfs_pread_state);
2170         if (req == NULL) {
2171                 return NULL;
2172         }
2173         state->was_offline = SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name,
2174                                                 &fsp->fsp_name->st);
2175         state->fsp = fsp;
2176         subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
2177                                          n, offset);
2178         if (tevent_req_nomem(subreq, req)) {
2179                 return tevent_req_post(req, ev);
2180         }
2181         tevent_req_set_callback(subreq, vfs_gpfs_pread_done, req);
2182         return req;
2183 }
2184
2185 static void vfs_gpfs_pread_done(struct tevent_req *subreq)
2186 {
2187         struct tevent_req *req = tevent_req_callback_data(
2188                 subreq, struct tevent_req);
2189         struct vfs_gpfs_pread_state *state = tevent_req_data(
2190                 req, struct vfs_gpfs_pread_state);
2191
2192         state->ret = SMB_VFS_PREAD_RECV(subreq, &state->err);
2193         TALLOC_FREE(subreq);
2194         tevent_req_done(req);
2195 }
2196
2197 static ssize_t vfs_gpfs_pread_recv(struct tevent_req *req, int *err)
2198 {
2199         struct vfs_gpfs_pread_state *state = tevent_req_data(
2200                 req, struct vfs_gpfs_pread_state);
2201         struct files_struct *fsp = state->fsp;
2202
2203         if (tevent_req_is_unix_error(req, err)) {
2204                 return -1;
2205         }
2206         *err = state->err;
2207
2208         if ((state->ret != -1) && state->was_offline) {
2209                 DEBUG(10, ("sending notify\n"));
2210                 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
2211                              FILE_NOTIFY_CHANGE_ATTRIBUTES,
2212                              fsp->fsp_name->base_name);
2213         }
2214
2215         return state->ret;
2216 }
2217
2218 static ssize_t vfs_gpfs_pwrite(vfs_handle_struct *handle, files_struct *fsp,
2219                                const void *data, size_t n, off_t offset)
2220 {
2221         ssize_t ret;
2222         bool was_offline;
2223
2224         was_offline = SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name,
2225                                          &fsp->fsp_name->st);
2226
2227         ret = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
2228
2229         if ((ret != -1) && was_offline) {
2230                 notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
2231                              FILE_NOTIFY_CHANGE_ATTRIBUTES,
2232                              fsp->fsp_name->base_name);
2233         }
2234
2235         return ret;
2236 }
2237
2238 struct vfs_gpfs_pwrite_state {
2239         struct files_struct *fsp;
2240         ssize_t ret;
2241         int err;
2242         bool was_offline;
2243 };
2244
2245 static void vfs_gpfs_pwrite_done(struct tevent_req *subreq);
2246
2247 static struct tevent_req *vfs_gpfs_pwrite_send(
2248         struct vfs_handle_struct *handle,
2249         TALLOC_CTX *mem_ctx,
2250         struct tevent_context *ev,
2251         struct files_struct *fsp,
2252         const void *data, size_t n,
2253         off_t offset)
2254 {
2255         struct tevent_req *req, *subreq;
2256         struct vfs_gpfs_pwrite_state *state;
2257
2258         req = tevent_req_create(mem_ctx, &state, struct vfs_gpfs_pwrite_state);
2259         if (req == NULL) {
2260                 return NULL;
2261         }
2262         state->was_offline = SMB_VFS_IS_OFFLINE(handle->conn, fsp->fsp_name,
2263                                                 &fsp->fsp_name->st);
2264         state->fsp = fsp;
2265         subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
2266                                          n, offset);
2267         if (tevent_req_nomem(subreq, req)) {
2268                 return tevent_req_post(req, ev);
2269         }
2270         tevent_req_set_callback(subreq, vfs_gpfs_pwrite_done, req);
2271         return req;
2272 }
2273
2274 static void vfs_gpfs_pwrite_done(struct tevent_req *subreq)
2275 {
2276         struct tevent_req *req = tevent_req_callback_data(
2277                 subreq, struct tevent_req);
2278         struct vfs_gpfs_pwrite_state *state = tevent_req_data(
2279                 req, struct vfs_gpfs_pwrite_state);
2280
2281         state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->err);
2282         TALLOC_FREE(subreq);
2283         tevent_req_done(req);
2284 }
2285
2286 static ssize_t vfs_gpfs_pwrite_recv(struct tevent_req *req, int *err)
2287 {
2288         struct vfs_gpfs_pwrite_state *state = tevent_req_data(
2289                 req, struct vfs_gpfs_pwrite_state);
2290         struct files_struct *fsp = state->fsp;
2291
2292         if (tevent_req_is_unix_error(req, err)) {
2293                 return -1;
2294         }
2295         *err = state->err;
2296
2297         if ((state->ret != -1) && state->was_offline) {
2298                 DEBUG(10, ("sending notify\n"));
2299                 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
2300                              FILE_NOTIFY_CHANGE_ATTRIBUTES,
2301                              fsp->fsp_name->base_name);
2302         }
2303
2304         return state->ret;
2305 }
2306
2307
2308 static struct vfs_fn_pointers vfs_gpfs_fns = {
2309         .connect_fn = vfs_gpfs_connect,
2310         .disk_free_fn = vfs_gpfs_disk_free,
2311         .fs_capabilities_fn = vfs_gpfs_capabilities,
2312         .kernel_flock_fn = vfs_gpfs_kernel_flock,
2313         .linux_setlease_fn = vfs_gpfs_setlease,
2314         .get_real_filename_fn = vfs_gpfs_get_real_filename,
2315         .fget_nt_acl_fn = gpfsacl_fget_nt_acl,
2316         .get_nt_acl_fn = gpfsacl_get_nt_acl,
2317         .fset_nt_acl_fn = gpfsacl_fset_nt_acl,
2318         .sys_acl_get_file_fn = gpfsacl_sys_acl_get_file,
2319         .sys_acl_get_fd_fn = gpfsacl_sys_acl_get_fd,
2320         .sys_acl_blob_get_file_fn = gpfsacl_sys_acl_blob_get_file,
2321         .sys_acl_blob_get_fd_fn = gpfsacl_sys_acl_blob_get_fd,
2322         .sys_acl_set_file_fn = gpfsacl_sys_acl_set_file,
2323         .sys_acl_set_fd_fn = gpfsacl_sys_acl_set_fd,
2324         .sys_acl_delete_def_file_fn = gpfsacl_sys_acl_delete_def_file,
2325         .chmod_fn = vfs_gpfs_chmod,
2326         .fchmod_fn = vfs_gpfs_fchmod,
2327         .close_fn = vfs_gpfs_close,
2328         .setxattr_fn = gpfs_set_xattr,
2329         .getxattr_fn = gpfs_get_xattr,
2330         .stat_fn = vfs_gpfs_stat,
2331         .fstat_fn = vfs_gpfs_fstat,
2332         .lstat_fn = vfs_gpfs_lstat,
2333         .ntimes_fn = vfs_gpfs_ntimes,
2334         .is_offline_fn = vfs_gpfs_is_offline,
2335         .aio_force_fn = vfs_gpfs_aio_force,
2336         .sendfile_fn = vfs_gpfs_sendfile,
2337         .fallocate_fn = vfs_gpfs_fallocate,
2338         .open_fn = vfs_gpfs_open,
2339         .pread_fn = vfs_gpfs_pread,
2340         .pread_send_fn = vfs_gpfs_pread_send,
2341         .pread_recv_fn = vfs_gpfs_pread_recv,
2342         .pwrite_fn = vfs_gpfs_pwrite,
2343         .pwrite_send_fn = vfs_gpfs_pwrite_send,
2344         .pwrite_recv_fn = vfs_gpfs_pwrite_recv,
2345         .ftruncate_fn = vfs_gpfs_ftruncate
2346 };
2347
2348 NTSTATUS vfs_gpfs_init(void);
2349 NTSTATUS vfs_gpfs_init(void)
2350 {
2351         int ret;
2352
2353         ret = gpfswrap_init();
2354         if (ret != 0) {
2355                 DEBUG(1, ("Could not initialize GPFS library wrapper\n"));
2356         }
2357
2358         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs",
2359                                 &vfs_gpfs_fns);
2360 }