s4-dsdb_schema: Copy info needed for Schema refresh in dsdb_schema_copy_shallow
[Samba.git] / source3 / modules / vfs_gpfs.c
blobffe51c305eada47af406c7a6465303ea83f4ac49
1 /*
2 Unix SMB/CIFS implementation.
3 Wrap gpfs calls in vfs functions.
5 Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006
7 Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com>
8 and Gomati Mohanan <gomati.mohanan@in.ibm.com>
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.
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.
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/>.
24 #include "includes.h"
25 #include "librpc/gen_ndr/ndr_xattr.h"
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_VFS
30 #include <gpfs_gpl.h>
31 #include "nfs4_acls.h"
32 #include "vfs_gpfs.h"
34 struct gpfs_config_data {
35 bool sharemodes;
36 bool leases;
40 static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
41 uint32 share_mode, uint32 access_mask)
44 struct gpfs_config_data *config;
46 SMB_VFS_HANDLE_GET_DATA(handle, config,
47 struct gpfs_config_data,
48 return -1);
50 START_PROFILE(syscall_kernel_flock);
52 kernel_flock(fsp->fh->fd, share_mode, access_mask);
54 if (config->sharemodes
55 && !set_gpfs_sharemode(fsp, access_mask, fsp->share_access)) {
56 return -1;
59 END_PROFILE(syscall_kernel_flock);
61 return 0;
64 static int vfs_gpfs_close(vfs_handle_struct *handle, files_struct *fsp)
67 struct gpfs_config_data *config;
69 SMB_VFS_HANDLE_GET_DATA(handle, config,
70 struct gpfs_config_data,
71 return -1);
73 if (config->sharemodes && (fsp->fh != NULL) && (fsp->fh->fd != -1)) {
74 set_gpfs_sharemode(fsp, 0, 0);
77 return SMB_VFS_NEXT_CLOSE(handle, fsp);
80 static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp,
81 int leasetype)
83 struct gpfs_config_data *config;
84 int ret=0;
86 SMB_VFS_HANDLE_GET_DATA(handle, config,
87 struct gpfs_config_data,
88 return -1);
90 START_PROFILE(syscall_linux_setlease);
92 if (linux_set_lease_sighandler(fsp->fh->fd) == -1)
93 return -1;
95 if (config->leases) {
96 ret = set_gpfs_lease(fsp->fh->fd,leasetype);
99 if (ret < 0) {
100 /* This must have come from GPFS not being available */
101 /* or some other error, hence call the default */
102 ret = linux_setlease(fsp->fh->fd, leasetype);
105 END_PROFILE(syscall_linux_setlease);
107 return ret;
110 static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
111 const char *path,
112 const char *name,
113 TALLOC_CTX *mem_ctx,
114 char **found_name)
116 int result;
117 char *full_path;
118 char real_pathname[PATH_MAX+1];
119 int buflen;
121 full_path = talloc_asprintf(talloc_tos(), "%s/%s", path, name);
122 if (full_path == NULL) {
123 errno = ENOMEM;
124 return -1;
127 buflen = sizeof(real_pathname) - 1;
129 result = smbd_gpfs_get_realfilename_path(full_path, real_pathname,
130 &buflen);
132 TALLOC_FREE(full_path);
134 if ((result == -1) && (errno == ENOSYS)) {
135 return SMB_VFS_NEXT_GET_REAL_FILENAME(
136 handle, path, name, mem_ctx, found_name);
139 if (result == -1) {
140 DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n",
141 strerror(errno)));
142 return -1;
146 * GPFS does not necessarily null-terminate the returned path
147 * but instead returns the buffer length in buflen.
150 if (buflen < sizeof(real_pathname)) {
151 real_pathname[buflen] = '\0';
152 } else {
153 real_pathname[sizeof(real_pathname)-1] = '\0';
156 DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n",
157 path, name, real_pathname));
159 name = strrchr_m(real_pathname, '/');
160 if (name == NULL) {
161 errno = ENOENT;
162 return -1;
165 *found_name = talloc_strdup(mem_ctx, name+1);
166 if (*found_name == NULL) {
167 errno = ENOMEM;
168 return -1;
171 return 0;
174 static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
176 int i;
177 if (gacl==NULL)
179 DEBUG(0, ("gpfs acl is NULL\n"));
180 return;
183 DEBUG(level, ("gpfs acl: nace: %d, type:%d, version:%d, level:%d, len:%d\n",
184 gacl->acl_nace, gacl->acl_type, gacl->acl_version, gacl->acl_level, gacl->acl_len));
185 for(i=0; i<gacl->acl_nace; i++)
187 struct gpfs_ace_v4 *gace = gacl->ace_v4 + i;
188 DEBUG(level, ("\tace[%d]: type:%d, flags:0x%x, mask:0x%x, iflags:0x%x, who:%u\n",
189 i, gace->aceType, gace->aceFlags, gace->aceMask,
190 gace->aceIFlags, gace->aceWho));
194 static struct gpfs_acl *gpfs_getacl_alloc(const char *fname, gpfs_aclType_t type)
196 struct gpfs_acl *acl;
197 size_t len = 200;
198 int ret;
199 TALLOC_CTX *mem_ctx = talloc_tos();
201 acl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, len);
202 if (acl == NULL) {
203 errno = ENOMEM;
204 return NULL;
207 acl->acl_len = len;
208 acl->acl_level = 0;
209 acl->acl_version = 0;
210 acl->acl_type = type;
212 ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
213 if ((ret != 0) && (errno == ENOSPC)) {
214 struct gpfs_acl *new_acl = (struct gpfs_acl *)TALLOC_SIZE(
215 mem_ctx, acl->acl_len + sizeof(struct gpfs_acl));
216 if (new_acl == NULL) {
217 errno = ENOMEM;
218 return NULL;
221 new_acl->acl_len = acl->acl_len;
222 new_acl->acl_level = acl->acl_level;
223 new_acl->acl_version = acl->acl_version;
224 new_acl->acl_type = acl->acl_type;
225 acl = new_acl;
227 ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
229 if (ret != 0)
231 DEBUG(8, ("smbd_gpfs_getacl failed with %s\n",strerror(errno)));
232 return NULL;
235 return acl;
238 /* Tries to get nfs4 acls and returns SMB ACL allocated.
239 * On failure returns 1 if it got non-NFSv4 ACL to prompt
240 * retry with POSIX ACL checks.
241 * On failure returns -1 if there is system (GPFS) error, check errno.
242 * Returns 0 on success
244 static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
246 int i;
247 struct gpfs_acl *gacl = NULL;
248 DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
250 /* First get the real acl length */
251 gacl = gpfs_getacl_alloc(fname, 0);
252 if (gacl == NULL) {
253 DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
254 fname, strerror(errno)));
255 return -1;
258 if (gacl->acl_type != GPFS_ACL_TYPE_NFS4) {
259 DEBUG(10, ("Got non-nfsv4 acl\n"));
260 /* Retry with POSIX ACLs check */
261 return 1;
264 *ppacl = smb_create_smb4acl();
266 DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
267 gacl->acl_len, gacl->acl_level, gacl->acl_version,
268 gacl->acl_nace));
270 for (i=0; i<gacl->acl_nace; i++) {
271 struct gpfs_ace_v4 *gace = &gacl->ace_v4[i];
272 SMB_ACE4PROP_T smbace;
273 DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
274 "who: %d\n", gace->aceType, gace->aceIFlags,
275 gace->aceFlags, gace->aceMask, gace->aceWho));
277 ZERO_STRUCT(smbace);
278 if (gace->aceIFlags & ACE4_IFLAG_SPECIAL_ID) {
279 smbace.flags |= SMB_ACE4_ID_SPECIAL;
280 switch (gace->aceWho) {
281 case ACE4_SPECIAL_OWNER:
282 smbace.who.special_id = SMB_ACE4_WHO_OWNER;
283 break;
284 case ACE4_SPECIAL_GROUP:
285 smbace.who.special_id = SMB_ACE4_WHO_GROUP;
286 break;
287 case ACE4_SPECIAL_EVERYONE:
288 smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
289 break;
290 default:
291 DEBUG(8, ("invalid special gpfs id %d "
292 "ignored\n", gace->aceWho));
293 continue; /* don't add it */
295 } else {
296 if (gace->aceFlags & ACE4_FLAG_GROUP_ID)
297 smbace.who.gid = gace->aceWho;
298 else
299 smbace.who.uid = gace->aceWho;
302 /* remove redundent deny entries */
303 if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
304 struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1];
305 if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
306 prev->aceFlags == gace->aceFlags &&
307 prev->aceIFlags == gace->aceIFlags &&
308 (gace->aceMask & prev->aceMask) == 0 &&
309 gace->aceWho == prev->aceWho) {
310 /* its redundent - skip it */
311 continue;
315 smbace.aceType = gace->aceType;
316 smbace.aceFlags = gace->aceFlags;
317 smbace.aceMask = gace->aceMask;
318 smb_add_ace4(*ppacl, &smbace);
321 return 0;
324 static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
325 files_struct *fsp, uint32 security_info,
326 struct security_descriptor **ppdesc)
328 SMB4ACL_T *pacl = NULL;
329 int result;
331 *ppdesc = NULL;
332 result = gpfs_get_nfs4_acl(fsp->fsp_name->base_name, &pacl);
334 if (result == 0)
335 return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
337 if (result > 0) {
338 DEBUG(10, ("retrying with posix acl...\n"));
339 return posix_fget_nt_acl(fsp, security_info, ppdesc);
342 /* GPFS ACL was not read, something wrong happened, error code is set in errno */
343 return map_nt_error_from_unix(errno);
346 static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
347 const char *name,
348 uint32 security_info, struct security_descriptor **ppdesc)
350 SMB4ACL_T *pacl = NULL;
351 int result;
353 *ppdesc = NULL;
354 result = gpfs_get_nfs4_acl(name, &pacl);
356 if (result == 0)
357 return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl);
359 if (result > 0) {
360 DEBUG(10, ("retrying with posix acl...\n"));
361 return posix_get_nt_acl(handle->conn, name, security_info, ppdesc);
364 /* GPFS ACL was not read, something wrong happened, error code is set in errno */
365 return map_nt_error_from_unix(errno);
368 static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
370 int ret;
371 gpfs_aclLen_t gacl_len;
372 SMB4ACE_T *smbace;
373 struct gpfs_acl *gacl;
374 TALLOC_CTX *mem_ctx = talloc_tos();
376 gacl_len = sizeof(struct gpfs_acl) +
377 (smb_get_naces(smbacl)-1)*sizeof(gpfs_ace_v4_t);
379 gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len);
380 if (gacl == NULL) {
381 DEBUG(0, ("talloc failed\n"));
382 errno = ENOMEM;
383 return False;
386 gacl->acl_len = gacl_len;
387 gacl->acl_level = 0;
388 gacl->acl_version = GPFS_ACL_VERSION_NFS4;
389 gacl->acl_type = GPFS_ACL_TYPE_NFS4;
390 gacl->acl_nace = 0; /* change later... */
392 for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
393 struct gpfs_ace_v4 *gace = &gacl->ace_v4[gacl->acl_nace];
394 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
396 gace->aceType = aceprop->aceType;
397 gace->aceFlags = aceprop->aceFlags;
398 gace->aceMask = aceprop->aceMask;
401 * GPFS can't distinguish between WRITE and APPEND on
402 * files, so one being set without the other is an
403 * error. Sorry for the many ()'s :-)
406 if (!fsp->is_directory
408 ((((gace->aceMask & ACE4_MASK_WRITE) == 0)
409 && ((gace->aceMask & ACE4_MASK_APPEND) != 0))
411 (((gace->aceMask & ACE4_MASK_WRITE) != 0)
412 && ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
414 lp_parm_bool(fsp->conn->params->service, "gpfs",
415 "merge_writeappend", True)) {
416 DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
417 "WRITE^APPEND, setting WRITE|APPEND\n",
418 fsp_str_dbg(fsp)));
419 gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
422 gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;
424 if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
426 switch(aceprop->who.special_id)
428 case SMB_ACE4_WHO_EVERYONE:
429 gace->aceWho = ACE4_SPECIAL_EVERYONE;
430 break;
431 case SMB_ACE4_WHO_OWNER:
432 gace->aceWho = ACE4_SPECIAL_OWNER;
433 break;
434 case SMB_ACE4_WHO_GROUP:
435 gace->aceWho = ACE4_SPECIAL_GROUP;
436 break;
437 default:
438 DEBUG(8, ("unsupported special_id %d\n", aceprop->who.special_id));
439 continue; /* don't add it !!! */
441 } else {
442 /* just only for the type safety... */
443 if (aceprop->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
444 gace->aceWho = aceprop->who.gid;
445 else
446 gace->aceWho = aceprop->who.uid;
449 gacl->acl_nace++;
452 ret = smbd_gpfs_putacl(fsp->fsp_name->base_name,
453 GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
454 if (ret != 0) {
455 DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
456 gpfs_dumpacl(8, gacl);
457 return False;
460 DEBUG(10, ("gpfs_putacl succeeded\n"));
461 return True;
464 static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
466 struct gpfs_acl *acl;
467 NTSTATUS result = NT_STATUS_ACCESS_DENIED;
469 acl = gpfs_getacl_alloc(fsp->fsp_name->base_name, 0);
470 if (acl == NULL)
471 return result;
473 if (acl->acl_version&GPFS_ACL_VERSION_NFS4)
475 if (lp_parm_bool(fsp->conn->params->service, "gpfs",
476 "refuse_dacl_protected", false)
477 && (psd->type&SEC_DESC_DACL_PROTECTED)) {
478 DEBUG(2, ("Rejecting unsupported ACL with DACL_PROTECTED bit set\n"));
479 return NT_STATUS_NOT_SUPPORTED;
482 result = smb_set_nt_acl_nfs4(
483 fsp, security_info_sent, psd,
484 gpfsacl_process_smbacl);
485 } else { /* assume POSIX ACL - by default... */
486 result = set_nt_acl(fsp, security_info_sent, psd);
489 return result;
492 static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
494 return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd);
497 static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl)
499 SMB_ACL_T result;
500 int i;
502 result = sys_acl_init(pacl->acl_nace);
503 if (result == NULL) {
504 errno = ENOMEM;
505 return NULL;
508 result->count = pacl->acl_nace;
510 for (i=0; i<pacl->acl_nace; i++) {
511 struct smb_acl_entry *ace = &result->acl[i];
512 const struct gpfs_ace_v1 *g_ace = &pacl->ace_v1[i];
514 DEBUG(10, ("Converting type %d id %lu perm %x\n",
515 (int)g_ace->ace_type, (unsigned long)g_ace->ace_who,
516 (int)g_ace->ace_perm));
518 switch (g_ace->ace_type) {
519 case GPFS_ACL_USER:
520 ace->a_type = SMB_ACL_USER;
521 ace->uid = (uid_t)g_ace->ace_who;
522 break;
523 case GPFS_ACL_USER_OBJ:
524 ace->a_type = SMB_ACL_USER_OBJ;
525 break;
526 case GPFS_ACL_GROUP:
527 ace->a_type = SMB_ACL_GROUP;
528 ace->gid = (gid_t)g_ace->ace_who;
529 break;
530 case GPFS_ACL_GROUP_OBJ:
531 ace->a_type = SMB_ACL_GROUP_OBJ;
532 break;
533 case GPFS_ACL_OTHER:
534 ace->a_type = SMB_ACL_OTHER;
535 break;
536 case GPFS_ACL_MASK:
537 ace->a_type = SMB_ACL_MASK;
538 break;
539 default:
540 DEBUG(10, ("Got invalid ace_type: %d\n",
541 g_ace->ace_type));
542 errno = EINVAL;
543 SAFE_FREE(result);
544 return NULL;
547 ace->a_perm = 0;
548 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_READ) ?
549 SMB_ACL_READ : 0;
550 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_WRITE) ?
551 SMB_ACL_WRITE : 0;
552 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_EXECUTE) ?
553 SMB_ACL_EXECUTE : 0;
555 DEBUGADD(10, ("Converted to %d perm %x\n",
556 ace->a_type, ace->a_perm));
559 return result;
562 static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type)
564 struct gpfs_acl *pacl;
565 SMB_ACL_T result = NULL;
567 pacl = gpfs_getacl_alloc(path, type);
569 if (pacl == NULL) {
570 DEBUG(10, ("gpfs_getacl failed for %s with %s\n",
571 path, strerror(errno)));
572 if (errno == 0) {
573 errno = EINVAL;
575 goto done;
578 if (pacl->acl_version != GPFS_ACL_VERSION_POSIX) {
579 DEBUG(10, ("Got acl version %d, expected %d\n",
580 pacl->acl_version, GPFS_ACL_VERSION_POSIX));
581 errno = EINVAL;
582 goto done;
585 DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
586 pacl->acl_len, pacl->acl_level, pacl->acl_version,
587 pacl->acl_nace));
589 result = gpfs2smb_acl(pacl);
590 if (result == NULL) {
591 goto done;
594 done:
596 if (errno != 0) {
597 SAFE_FREE(result);
599 return result;
602 static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
603 const char *path_p,
604 SMB_ACL_TYPE_T type)
606 gpfs_aclType_t gpfs_type;
608 switch(type) {
609 case SMB_ACL_TYPE_ACCESS:
610 gpfs_type = GPFS_ACL_TYPE_ACCESS;
611 break;
612 case SMB_ACL_TYPE_DEFAULT:
613 gpfs_type = GPFS_ACL_TYPE_DEFAULT;
614 break;
615 default:
616 DEBUG(0, ("Got invalid type: %d\n", type));
617 smb_panic("exiting");
620 return gpfsacl_get_posix_acl(path_p, gpfs_type);
623 static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
624 files_struct *fsp)
626 return gpfsacl_get_posix_acl(fsp->fsp_name->base_name,
627 GPFS_ACL_TYPE_ACCESS);
630 static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
631 SMB_ACL_TYPE_T type)
633 gpfs_aclLen_t len;
634 struct gpfs_acl *result;
635 int i;
636 union gpfs_ace_union
638 gpfs_ace_v1_t ace_v1[1]; /* when GPFS_ACL_VERSION_POSIX */
639 gpfs_ace_v4_t ace_v4[1]; /* when GPFS_ACL_VERSION_NFS4 */
642 DEBUG(10, ("smb2gpfs_acl: Got ACL with %d entries\n", pacl->count));
644 len = sizeof(struct gpfs_acl) - sizeof(union gpfs_ace_union) +
645 (pacl->count)*sizeof(gpfs_ace_v1_t);
647 result = (struct gpfs_acl *)SMB_MALLOC(len);
648 if (result == NULL) {
649 errno = ENOMEM;
650 return result;
653 result->acl_len = len;
654 result->acl_level = 0;
655 result->acl_version = GPFS_ACL_VERSION_POSIX;
656 result->acl_type = (type == SMB_ACL_TYPE_DEFAULT) ?
657 GPFS_ACL_TYPE_DEFAULT : GPFS_ACL_TYPE_ACCESS;
658 result->acl_nace = pacl->count;
660 for (i=0; i<pacl->count; i++) {
661 const struct smb_acl_entry *ace = &pacl->acl[i];
662 struct gpfs_ace_v1 *g_ace = &result->ace_v1[i];
664 DEBUG(10, ("Converting type %d perm %x\n",
665 (int)ace->a_type, (int)ace->a_perm));
667 g_ace->ace_perm = 0;
669 switch(ace->a_type) {
670 case SMB_ACL_USER:
671 g_ace->ace_type = GPFS_ACL_USER;
672 g_ace->ace_who = (gpfs_uid_t)ace->uid;
673 break;
674 case SMB_ACL_USER_OBJ:
675 g_ace->ace_type = GPFS_ACL_USER_OBJ;
676 g_ace->ace_perm |= ACL_PERM_CONTROL;
677 g_ace->ace_who = 0;
678 break;
679 case SMB_ACL_GROUP:
680 g_ace->ace_type = GPFS_ACL_GROUP;
681 g_ace->ace_who = (gpfs_uid_t)ace->gid;
682 break;
683 case SMB_ACL_GROUP_OBJ:
684 g_ace->ace_type = GPFS_ACL_GROUP_OBJ;
685 g_ace->ace_who = 0;
686 break;
687 case SMB_ACL_MASK:
688 g_ace->ace_type = GPFS_ACL_MASK;
689 g_ace->ace_perm = 0x8f;
690 g_ace->ace_who = 0;
691 break;
692 case SMB_ACL_OTHER:
693 g_ace->ace_type = GPFS_ACL_OTHER;
694 g_ace->ace_who = 0;
695 break;
696 default:
697 DEBUG(10, ("Got invalid ace_type: %d\n", ace->a_type));
698 errno = EINVAL;
699 SAFE_FREE(result);
700 return NULL;
703 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_READ) ?
704 ACL_PERM_READ : 0;
705 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_WRITE) ?
706 ACL_PERM_WRITE : 0;
707 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_EXECUTE) ?
708 ACL_PERM_EXECUTE : 0;
710 DEBUGADD(10, ("Converted to %d id %d perm %x\n",
711 g_ace->ace_type, g_ace->ace_who, g_ace->ace_perm));
714 return result;
717 static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
718 const char *name,
719 SMB_ACL_TYPE_T type,
720 SMB_ACL_T theacl)
722 struct gpfs_acl *gpfs_acl;
723 int result;
725 gpfs_acl = smb2gpfs_acl(theacl, type);
726 if (gpfs_acl == NULL) {
727 return -1;
730 result = smbd_gpfs_putacl((char *)name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gpfs_acl);
732 SAFE_FREE(gpfs_acl);
733 return result;
736 static int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
737 files_struct *fsp,
738 SMB_ACL_T theacl)
740 return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name->base_name,
741 SMB_ACL_TYPE_ACCESS, theacl);
744 static int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
745 const char *path)
747 errno = ENOTSUP;
748 return -1;
752 * Assumed: mode bits are shiftable and standard
753 * Output: the new aceMask field for an smb nfs4 ace
755 static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx)
757 const uint32 posix_nfs4map[3] = {
758 SMB_ACE4_EXECUTE, /* execute */
759 SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
760 SMB_ACE4_READ_DATA /* read */
762 int i;
763 uint32_t posix_mask = 0x01;
764 uint32_t posix_bit;
765 uint32_t nfs4_bits;
767 for(i=0; i<3; i++) {
768 nfs4_bits = posix_nfs4map[i];
769 posix_bit = rwx & posix_mask;
771 if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
772 if (posix_bit)
773 aceMask |= nfs4_bits;
774 else
775 aceMask &= ~nfs4_bits;
776 } else {
777 /* add deny bits when suitable */
778 if (!posix_bit)
779 aceMask |= nfs4_bits;
780 else
781 aceMask &= ~nfs4_bits;
782 } /* other ace types are unexpected */
784 posix_mask <<= 1;
787 return aceMask;
790 static int gpfsacl_emu_chmod(const char *path, mode_t mode)
792 SMB4ACL_T *pacl = NULL;
793 int result;
794 bool haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
795 int i;
796 files_struct fake_fsp; /* TODO: rationalize parametrization */
797 SMB4ACE_T *smbace;
798 NTSTATUS status;
800 DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
802 result = gpfs_get_nfs4_acl(path, &pacl);
803 if (result)
804 return result;
806 if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
807 DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
810 for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
811 SMB_ACE4PROP_T *ace = smb_get_ace4(smbace);
812 uint32_t specid = ace->who.special_id;
814 if (ace->flags&SMB_ACE4_ID_SPECIAL &&
815 ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
816 specid <= SMB_ACE4_WHO_EVERYONE) {
818 uint32_t newMask;
820 if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
821 haveAllowEntry[specid] = True;
823 /* mode >> 6 for @owner, mode >> 3 for @group,
824 * mode >> 0 for @everyone */
825 newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
826 mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
827 if (ace->aceMask!=newMask) {
828 DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
829 path, ace->aceMask, newMask, specid));
831 ace->aceMask = newMask;
835 /* make sure we have at least ALLOW entries
836 * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
837 * - if necessary
839 for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
840 SMB_ACE4PROP_T ace;
842 if (haveAllowEntry[i]==True)
843 continue;
845 ZERO_STRUCT(ace);
846 ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
847 ace.flags |= SMB_ACE4_ID_SPECIAL;
848 ace.who.special_id = i;
850 if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
851 ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
853 ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
854 mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
856 /* don't add unnecessary aces */
857 if (!ace.aceMask)
858 continue;
860 /* we add it to the END - as windows expects allow aces */
861 smb_add_ace4(pacl, &ace);
862 DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
863 path, mode, i, ace.aceMask));
866 /* don't add complementary DENY ACEs here */
867 ZERO_STRUCT(fake_fsp);
868 status = create_synthetic_smb_fname(talloc_tos(), path, NULL, NULL,
869 &fake_fsp.fsp_name);
870 if (!NT_STATUS_IS_OK(status)) {
871 errno = map_errno_from_nt_status(status);
872 return -1;
874 /* put the acl */
875 if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False) {
876 TALLOC_FREE(fake_fsp.fsp_name);
877 return -1;
880 TALLOC_FREE(fake_fsp.fsp_name);
881 return 0; /* ok for [f]chmod */
884 static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
886 struct smb_filename *smb_fname_cpath;
887 int rc;
888 NTSTATUS status;
890 status = create_synthetic_smb_fname(
891 talloc_tos(), path, NULL, NULL, &smb_fname_cpath);
893 if (SMB_VFS_NEXT_STAT(handle, smb_fname_cpath) != 0) {
894 return -1;
897 /* avoid chmod() if possible, to preserve acls */
898 if ((smb_fname_cpath->st.st_ex_mode & ~S_IFMT) == mode) {
899 return 0;
902 rc = gpfsacl_emu_chmod(path, mode);
903 if (rc == 1)
904 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
905 return rc;
908 static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
910 SMB_STRUCT_STAT st;
911 int rc;
913 if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
914 return -1;
917 /* avoid chmod() if possible, to preserve acls */
918 if ((st.st_ex_mode & ~S_IFMT) == mode) {
919 return 0;
922 rc = gpfsacl_emu_chmod(fsp->fsp_name->base_name, mode);
923 if (rc == 1)
924 return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
925 return rc;
928 static int gpfs_set_xattr(struct vfs_handle_struct *handle, const char *path,
929 const char *name, const void *value, size_t size, int flags){
930 struct xattr_DOSATTRIB dosattrib;
931 enum ndr_err_code ndr_err;
932 DATA_BLOB blob;
933 const char *attrstr = value;
934 unsigned int dosmode=0;
935 struct gpfs_winattr attrs;
936 int ret = 0;
938 DEBUG(10, ("gpfs_set_xattr: %s \n",path));
940 /* Only handle DOS Attributes */
941 if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
942 DEBUG(1, ("gpfs_set_xattr:name is %s\n",name));
943 return SMB_VFS_NEXT_SETXATTR(handle,path,name,value,size,flags);
946 blob.data = (uint8_t *)attrstr;
947 blob.length = size;
949 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
950 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
952 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
953 DEBUG(1, ("gpfs_set_xattr: bad ndr decode "
954 "from EA on file %s: Error = %s\n",
955 path, ndr_errstr(ndr_err)));
956 return false;
959 if (dosattrib.version != 3) {
960 DEBUG(1, ("gpfs_set_xattr: expected dosattrib version 3, got "
961 "%d\n", (int)dosattrib.version));
962 return false;
964 if (!(dosattrib.info.info3.valid_flags & XATTR_DOSINFO_ATTRIB)) {
965 DEBUG(10, ("gpfs_set_xattr: XATTR_DOSINFO_ATTRIB not "
966 "valid, ignoring\n"));
967 return true;
970 dosmode = dosattrib.info.info3.attrib;
972 attrs.winAttrs = 0;
973 /*Just map RD_ONLY, ARCHIVE, SYSTEM HIDDEN and SPARSE. Ignore the others*/
974 if (dosmode & FILE_ATTRIBUTE_ARCHIVE){
975 attrs.winAttrs |= GPFS_WINATTR_ARCHIVE;
977 if (dosmode & FILE_ATTRIBUTE_HIDDEN){
978 attrs.winAttrs |= GPFS_WINATTR_HIDDEN;
980 if (dosmode & FILE_ATTRIBUTE_SYSTEM){
981 attrs.winAttrs |= GPFS_WINATTR_SYSTEM;
983 if (dosmode & FILE_ATTRIBUTE_READONLY){
984 attrs.winAttrs |= GPFS_WINATTR_READONLY;
986 if (dosmode & FILE_ATTRIBUTE_SPARSE) {
987 attrs.winAttrs |= GPFS_WINATTR_SPARSE_FILE;
991 ret = set_gpfs_winattrs(CONST_DISCARD(char *, path),
992 GPFS_WINATTR_SET_ATTRS, &attrs);
993 if ( ret == -1){
994 DEBUG(1, ("gpfs_set_xattr:Set GPFS attributes failed %d\n",ret));
995 return -1;
998 DEBUG(10, ("gpfs_set_xattr:Set attributes: 0x%x\n",attrs.winAttrs));
999 return 0;
1002 static ssize_t gpfs_get_xattr(struct vfs_handle_struct *handle, const char *path,
1003 const char *name, void *value, size_t size){
1004 char *attrstr = value;
1005 unsigned int dosmode = 0;
1006 struct gpfs_winattr attrs;
1007 int ret = 0;
1009 DEBUG(10, ("gpfs_get_xattr: %s \n",path));
1011 /* Only handle DOS Attributes */
1012 if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
1013 DEBUG(1, ("gpfs_get_xattr:name is %s\n",name));
1014 return SMB_VFS_NEXT_GETXATTR(handle,path,name,value,size);
1017 ret = get_gpfs_winattrs(CONST_DISCARD(char *, path), &attrs);
1018 if ( ret == -1){
1019 DEBUG(1, ("gpfs_get_xattr: Get GPFS attributes failed: %d\n",ret));
1020 return -1;
1023 DEBUG(10, ("gpfs_get_xattr:Got attributes: 0x%x\n",attrs.winAttrs));
1025 /*Just map RD_ONLY, ARCHIVE, SYSTEM, HIDDEN and SPARSE. Ignore the others*/
1026 if (attrs.winAttrs & GPFS_WINATTR_ARCHIVE){
1027 dosmode |= FILE_ATTRIBUTE_ARCHIVE;
1029 if (attrs.winAttrs & GPFS_WINATTR_HIDDEN){
1030 dosmode |= FILE_ATTRIBUTE_HIDDEN;
1032 if (attrs.winAttrs & GPFS_WINATTR_SYSTEM){
1033 dosmode |= FILE_ATTRIBUTE_SYSTEM;
1035 if (attrs.winAttrs & GPFS_WINATTR_READONLY){
1036 dosmode |= FILE_ATTRIBUTE_READONLY;
1038 if (attrs.winAttrs & GPFS_WINATTR_SPARSE_FILE) {
1039 dosmode |= FILE_ATTRIBUTE_SPARSE;
1042 snprintf(attrstr, size, "0x%2.2x", dosmode & SAMBA_ATTRIBUTES_MASK);
1043 DEBUG(10, ("gpfs_get_xattr: returning %s\n",attrstr));
1044 return 4;
1047 static int vfs_gpfs_stat(struct vfs_handle_struct *handle,
1048 struct smb_filename *smb_fname)
1050 struct gpfs_winattr attrs;
1051 char *fname = NULL;
1052 NTSTATUS status;
1053 int ret;
1055 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1056 if (ret == -1) {
1057 return -1;
1059 status = get_full_smb_filename(talloc_tos(), smb_fname, &fname);
1060 if (!NT_STATUS_IS_OK(status)) {
1061 errno = map_errno_from_nt_status(status);
1062 return -1;
1064 ret = get_gpfs_winattrs(CONST_DISCARD(char *, fname), &attrs);
1065 TALLOC_FREE(fname);
1066 if (ret == 0) {
1067 smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1068 smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1070 return 0;
1073 static int vfs_gpfs_fstat(struct vfs_handle_struct *handle,
1074 struct files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1076 struct gpfs_winattr attrs;
1077 int ret;
1079 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1080 if (ret == -1) {
1081 return -1;
1083 if ((fsp->fh == NULL) || (fsp->fh->fd == -1)) {
1084 return 0;
1086 ret = smbd_fget_gpfs_winattrs(fsp->fh->fd, &attrs);
1087 if (ret == 0) {
1088 sbuf->st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1089 sbuf->st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1091 return 0;
1094 static int vfs_gpfs_lstat(struct vfs_handle_struct *handle,
1095 struct smb_filename *smb_fname)
1097 struct gpfs_winattr attrs;
1098 char *path = NULL;
1099 NTSTATUS status;
1100 int ret;
1102 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1103 if (ret == -1) {
1104 return -1;
1106 status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1107 if (!NT_STATUS_IS_OK(status)) {
1108 errno = map_errno_from_nt_status(status);
1109 return -1;
1111 ret = get_gpfs_winattrs(CONST_DISCARD(char *, path), &attrs);
1112 TALLOC_FREE(path);
1113 if (ret == 0) {
1114 smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1115 smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1117 return 0;
1120 static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
1121 const struct smb_filename *smb_fname,
1122 struct smb_file_time *ft)
1125 struct gpfs_winattr attrs;
1126 int ret;
1127 char *path = NULL;
1128 NTSTATUS status;
1130 ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1131 if(ret == -1){
1132 DEBUG(1,("vfs_gpfs_ntimes: SMB_VFS_NEXT_NTIMES failed\n"));
1133 return -1;
1136 if(null_timespec(ft->create_time)){
1137 DEBUG(10,("vfs_gpfs_ntimes:Create Time is NULL\n"));
1138 return 0;
1141 status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1142 if (!NT_STATUS_IS_OK(status)) {
1143 errno = map_errno_from_nt_status(status);
1144 return -1;
1147 attrs.winAttrs = 0;
1148 attrs.creationTime.tv_sec = ft->create_time.tv_sec;
1149 attrs.creationTime.tv_nsec = ft->create_time.tv_nsec;
1151 ret = set_gpfs_winattrs(CONST_DISCARD(char *, path),
1152 GPFS_WINATTR_SET_CREATION_TIME, &attrs);
1153 if(ret == -1){
1154 DEBUG(1,("vfs_gpfs_ntimes: set GPFS ntimes failed %d\n",ret));
1155 return -1;
1157 return 0;
1161 static int vfs_gpfs_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
1162 SMB_OFF_T len)
1164 int result;
1166 result = smbd_gpfs_ftruncate(fsp->fh->fd, len);
1167 if ((result == -1) && (errno == ENOSYS)) {
1168 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
1170 return result;
1173 int vfs_gpfs_connect(struct vfs_handle_struct *handle, const char *service,
1174 const char *user)
1176 struct gpfs_config_data *config;
1177 int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
1179 if (ret < 0) {
1180 return ret;
1183 config = talloc_zero(handle->conn, struct gpfs_config_data);
1184 if (!config) {
1185 SMB_VFS_NEXT_DISCONNECT(handle);
1186 DEBUG(0, ("talloc_zero() failed\n")); return -1;
1189 config->sharemodes = lp_parm_bool(SNUM(handle->conn), "gpfs",
1190 "sharemodes", true);
1192 config->leases = lp_parm_bool(SNUM(handle->conn), "gpfs",
1193 "leases", true);
1195 SMB_VFS_HANDLE_SET_DATA(handle, config,
1196 NULL, struct syncops_config_data,
1197 return -1);
1199 return 0;
1203 static struct vfs_fn_pointers vfs_gpfs_fns = {
1204 .connect_fn = vfs_gpfs_connect,
1205 .kernel_flock = vfs_gpfs_kernel_flock,
1206 .linux_setlease = vfs_gpfs_setlease,
1207 .get_real_filename = vfs_gpfs_get_real_filename,
1208 .fget_nt_acl = gpfsacl_fget_nt_acl,
1209 .get_nt_acl = gpfsacl_get_nt_acl,
1210 .fset_nt_acl = gpfsacl_fset_nt_acl,
1211 .sys_acl_get_file = gpfsacl_sys_acl_get_file,
1212 .sys_acl_get_fd = gpfsacl_sys_acl_get_fd,
1213 .sys_acl_set_file = gpfsacl_sys_acl_set_file,
1214 .sys_acl_set_fd = gpfsacl_sys_acl_set_fd,
1215 .sys_acl_delete_def_file = gpfsacl_sys_acl_delete_def_file,
1216 .chmod = vfs_gpfs_chmod,
1217 .fchmod = vfs_gpfs_fchmod,
1218 .close_fn = vfs_gpfs_close,
1219 .setxattr = gpfs_set_xattr,
1220 .getxattr = gpfs_get_xattr,
1221 .stat = vfs_gpfs_stat,
1222 .fstat = vfs_gpfs_fstat,
1223 .lstat = vfs_gpfs_lstat,
1224 .ntimes = vfs_gpfs_ntimes,
1225 .ftruncate = vfs_gpfs_ftruncate
1228 NTSTATUS vfs_gpfs_init(void);
1229 NTSTATUS vfs_gpfs_init(void)
1231 init_gpfs();
1233 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs",
1234 &vfs_gpfs_fns);