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