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