root/source3/modules/vfs_gpfs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vfs_gpfs_kernel_flock
  2. vfs_gpfs_close
  3. vfs_gpfs_setlease
  4. vfs_gpfs_get_real_filename
  5. gpfs_dumpacl
  6. gpfs_getacl_alloc
  7. gpfs_get_nfs4_acl
  8. gpfsacl_fget_nt_acl
  9. gpfsacl_get_nt_acl
  10. gpfsacl_process_smbacl
  11. gpfsacl_set_nt_acl_internal
  12. gpfsacl_fset_nt_acl
  13. gpfs2smb_acl
  14. gpfsacl_get_posix_acl
  15. gpfsacl_sys_acl_get_file
  16. gpfsacl_sys_acl_get_fd
  17. smb2gpfs_acl
  18. gpfsacl_sys_acl_set_file
  19. gpfsacl_sys_acl_set_fd
  20. gpfsacl_sys_acl_delete_def_file
  21. gpfsacl_mask_filter
  22. gpfsacl_emu_chmod
  23. vfs_gpfs_chmod
  24. vfs_gpfs_fchmod
  25. vfs_gpfs_init

   1 /*
   2    Unix SMB/CIFS implementation.
   3    Wrap gpfs calls in vfs functions.
   4 
   5    Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006
   6 
   7    Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com>
   8                             and Gomati Mohanan <gomati.mohanan@in.ibm.com>
   9 
  10    This program is free software; you can redistribute it and/or modify
  11    it under the terms of the GNU General Public License as published by
  12    the Free Software Foundation; either version 3 of the License, or
  13    (at your option) any later version.
  14 
  15    This program is distributed in the hope that it will be useful,
  16    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18    GNU General Public License for more details.
  19 
  20    You should have received a copy of the GNU General Public License
  21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  22 */
  23 
  24 #include "includes.h"
  25 
  26 #undef DBGC_CLASS
  27 #define DBGC_CLASS DBGC_VFS
  28 
  29 #include <gpfs_gpl.h>
  30 #include "nfs4_acls.h"
  31 #include "vfs_gpfs.h"
  32 
  33 static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, 
     /* [<][>][^][v][top][bottom][index][help] */
  34                                  uint32 share_mode)
  35 {
  36 
  37         START_PROFILE(syscall_kernel_flock);
  38 
  39         kernel_flock(fsp->fh->fd, share_mode);
  40 
  41         if (!set_gpfs_sharemode(fsp, fsp->access_mask, fsp->share_access)) {
  42 
  43                 return -1;
  44 
  45         }
  46 
  47         END_PROFILE(syscall_kernel_flock);
  48 
  49         return 0;
  50 }
  51 
  52 static int vfs_gpfs_close(vfs_handle_struct *handle, files_struct *fsp)
     /* [<][>][^][v][top][bottom][index][help] */
  53 {
  54         if ((fsp->fh != NULL) && (fsp->fh->fd != -1)) {
  55                 set_gpfs_sharemode(fsp, 0, 0);
  56         }
  57 
  58         return SMB_VFS_NEXT_CLOSE(handle, fsp);
  59 }
  60 
  61 static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, 
     /* [<][>][^][v][top][bottom][index][help] */
  62                              int leasetype)
  63 {
  64         int ret;
  65 
  66         START_PROFILE(syscall_linux_setlease);
  67 
  68         if ( linux_set_lease_sighandler(fsp->fh->fd) == -1)
  69                 return -1;
  70 
  71         ret = set_gpfs_lease(fsp->fh->fd,leasetype);
  72 
  73         if ( ret < 0 ) {
  74                 /* This must have come from GPFS not being available */
  75                 /* or some other error, hence call the default */
  76                 ret = linux_setlease(fsp->fh->fd, leasetype);
  77         }
  78 
  79         END_PROFILE(syscall_linux_setlease);
  80 
  81         return ret;
  82 }
  83 
  84 static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
  85                                       const char *path,
  86                                       const char *name,
  87                                       TALLOC_CTX *mem_ctx,
  88                                       char **found_name)
  89 {
  90         int result;
  91         char *full_path;
  92         char real_pathname[PATH_MAX+1];
  93         int buflen;
  94 
  95         full_path = talloc_asprintf(talloc_tos(), "%s/%s", path, name);
  96         if (full_path == NULL) {
  97                 errno = ENOMEM;
  98                 return -1;
  99         }
 100 
 101         buflen = sizeof(real_pathname) - 1;
 102 
 103         result = smbd_gpfs_get_realfilename_path(full_path, real_pathname,
 104                                                  &buflen);
 105 
 106         TALLOC_FREE(full_path);
 107 
 108         if ((result == -1) && (errno == ENOSYS)) {
 109                 return SMB_VFS_NEXT_GET_REAL_FILENAME(
 110                         handle, path, name, mem_ctx, found_name);
 111         }
 112 
 113         if (result == -1) {
 114                 DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n",
 115                            strerror(errno)));
 116                 return -1;
 117         }
 118 
 119         /*
 120          * GPFS does not necessarily null-terminate the returned path
 121          * but instead returns the buffer length in buflen.
 122          */
 123 
 124         if (buflen < sizeof(real_pathname)) {
 125                 real_pathname[buflen] = '\0';
 126         } else {
 127                 real_pathname[sizeof(real_pathname)-1] = '\0';
 128         }
 129 
 130         DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n",
 131                    path, name, real_pathname));
 132 
 133         name = strrchr_m(real_pathname, '/');
 134         if (name == NULL) {
 135                 errno = ENOENT;
 136                 return -1;
 137         }
 138 
 139         *found_name = talloc_strdup(mem_ctx, name+1);
 140         if (*found_name == NULL) {
 141                 errno = ENOMEM;
 142                 return -1;
 143         }
 144 
 145         return 0;
 146 }
 147 
 148 static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
     /* [<][>][^][v][top][bottom][index][help] */
 149 {
 150         int     i;
 151         if (gacl==NULL)
 152         {
 153                 DEBUG(0, ("gpfs acl is NULL\n"));
 154                 return;
 155         }
 156 
 157         DEBUG(level, ("gpfs acl: nace: %d, type:%d, version:%d, level:%d, len:%d\n",
 158                 gacl->acl_nace, gacl->acl_type, gacl->acl_version, gacl->acl_level, gacl->acl_len));
 159         for(i=0; i<gacl->acl_nace; i++)
 160         {
 161                 struct gpfs_ace_v4 *gace = gacl->ace_v4 + i;
 162                 DEBUG(level, ("\tace[%d]: type:%d, flags:0x%x, mask:0x%x, iflags:0x%x, who:%u\n",
 163                         i, gace->aceType, gace->aceFlags, gace->aceMask,
 164                         gace->aceIFlags, gace->aceWho));
 165         }
 166 }
 167 
 168 static struct gpfs_acl *gpfs_getacl_alloc(const char *fname, gpfs_aclType_t type)
     /* [<][>][^][v][top][bottom][index][help] */
 169 {
 170         struct gpfs_acl *acl;
 171         size_t len = 200;
 172         int ret;
 173         TALLOC_CTX *mem_ctx = talloc_tos();
 174 
 175         acl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, len);
 176         if (acl == NULL) {
 177                 errno = ENOMEM;
 178                 return NULL;
 179         }
 180 
 181         acl->acl_len = len;
 182         acl->acl_level = 0;
 183         acl->acl_version = 0;
 184         acl->acl_type = type;
 185 
 186         ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
 187         if ((ret != 0) && (errno == ENOSPC)) {
 188                 struct gpfs_acl *new_acl = (struct gpfs_acl *)TALLOC_SIZE(
 189                         mem_ctx, acl->acl_len + sizeof(struct gpfs_acl));
 190                 if (new_acl == NULL) {
 191                         errno = ENOMEM;
 192                         return NULL;
 193                 }
 194 
 195                 new_acl->acl_len = acl->acl_len;
 196                 new_acl->acl_level = acl->acl_level;
 197                 new_acl->acl_version = acl->acl_version;
 198                 new_acl->acl_type = acl->acl_type;
 199                 acl = new_acl;
 200 
 201                 ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
 202         }
 203         if (ret != 0)
 204         {
 205                 DEBUG(8, ("smbd_gpfs_getacl failed with %s\n",strerror(errno)));
 206                 return NULL;
 207         }
 208 
 209         return acl;
 210 }
 211 
 212 /* Tries to get nfs4 acls and returns SMB ACL allocated.
 213  * On failure returns 1 if it got non-NFSv4 ACL to prompt 
 214  * retry with POSIX ACL checks.
 215  * On failure returns -1 if there is system (GPFS) error, check errno.
 216  * Returns 0 on success
 217  */
 218 static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
     /* [<][>][^][v][top][bottom][index][help] */
 219 {
 220         int i;
 221         struct gpfs_acl *gacl = NULL;
 222         DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
 223 
 224         /* First get the real acl length */
 225         gacl = gpfs_getacl_alloc(fname, 0);
 226         if (gacl == NULL) {
 227                 DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
 228                            fname, strerror(errno)));
 229                 return -1;
 230         }
 231 
 232         if (gacl->acl_type != GPFS_ACL_TYPE_NFS4) {
 233                 DEBUG(10, ("Got non-nfsv4 acl\n"));
 234                 /* Retry with POSIX ACLs check */
 235                 return 1;
 236         }
 237 
 238         *ppacl = smb_create_smb4acl();
 239 
 240         DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
 241                    gacl->acl_len, gacl->acl_level, gacl->acl_version,
 242                    gacl->acl_nace));
 243 
 244         for (i=0; i<gacl->acl_nace; i++) {
 245                 struct gpfs_ace_v4 *gace = &gacl->ace_v4[i];
 246                 SMB_ACE4PROP_T smbace;
 247                 DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
 248                            "who: %d\n", gace->aceType, gace->aceIFlags,
 249                            gace->aceFlags, gace->aceMask, gace->aceWho));
 250 
 251                 ZERO_STRUCT(smbace);
 252                 if (gace->aceIFlags & ACE4_IFLAG_SPECIAL_ID) {
 253                         smbace.flags |= SMB_ACE4_ID_SPECIAL;
 254                         switch (gace->aceWho) {
 255                         case ACE4_SPECIAL_OWNER:
 256                                 smbace.who.special_id = SMB_ACE4_WHO_OWNER;
 257                                 break;
 258                         case ACE4_SPECIAL_GROUP:
 259                                 smbace.who.special_id = SMB_ACE4_WHO_GROUP;
 260                                 break;
 261                         case ACE4_SPECIAL_EVERYONE:
 262                                 smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
 263                                 break;
 264                         default:
 265                                 DEBUG(8, ("invalid special gpfs id %d "
 266                                           "ignored\n", gace->aceWho));
 267                                 continue; /* don't add it */
 268                         }
 269                 } else {
 270                         if (gace->aceFlags & ACE4_FLAG_GROUP_ID)
 271                                 smbace.who.gid = gace->aceWho;
 272                         else
 273                                 smbace.who.uid = gace->aceWho;
 274                 }
 275 
 276                 /* remove redundent deny entries */
 277                 if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
 278                         struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1];
 279                         if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
 280                             prev->aceFlags == gace->aceFlags &&
 281                             prev->aceIFlags == gace->aceIFlags &&
 282                             (gace->aceMask & prev->aceMask) == 0 &&
 283                             gace->aceWho == prev->aceWho) {
 284                                 /* its redundent - skip it */
 285                                 continue;
 286                         }                                                
 287                 }
 288 
 289                 smbace.aceType = gace->aceType;
 290                 smbace.aceFlags = gace->aceFlags;
 291                 smbace.aceMask = gace->aceMask;
 292                 smb_add_ace4(*ppacl, &smbace);
 293         }
 294 
 295         return 0;
 296 }
 297 
 298 static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 299         files_struct *fsp, uint32 security_info,
 300         SEC_DESC **ppdesc)
 301 {
 302         SMB4ACL_T *pacl = NULL;
 303         int     result;
 304 
 305         *ppdesc = NULL;
 306         result = gpfs_get_nfs4_acl(fsp->fsp_name, &pacl);
 307 
 308         if (result == 0)
 309                 return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
 310 
 311         if (result > 0) {
 312                 DEBUG(10, ("retrying with posix acl...\n"));
 313                 return posix_fget_nt_acl(fsp, security_info, ppdesc);
 314         }
 315 
 316         /* GPFS ACL was not read, something wrong happened, error code is set in errno */
 317         return map_nt_error_from_unix(errno);
 318 }
 319 
 320 static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 321         const char *name,
 322         uint32 security_info, SEC_DESC **ppdesc)
 323 {
 324         SMB4ACL_T *pacl = NULL;
 325         int     result;
 326 
 327         *ppdesc = NULL;
 328         result = gpfs_get_nfs4_acl(name, &pacl);
 329 
 330         if (result == 0)
 331                 return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl);
 332 
 333         if (result > 0) {
 334                 DEBUG(10, ("retrying with posix acl...\n"));
 335                 return posix_get_nt_acl(handle->conn, name, security_info, ppdesc);
 336         }
 337 
 338         /* GPFS ACL was not read, something wrong happened, error code is set in errno */
 339         return map_nt_error_from_unix(errno);
 340 }
 341 
 342 static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
     /* [<][>][^][v][top][bottom][index][help] */
 343 {
 344         int ret;
 345         gpfs_aclLen_t gacl_len;
 346         SMB4ACE_T       *smbace;
 347         struct gpfs_acl *gacl;
 348         TALLOC_CTX *mem_ctx  = talloc_tos();
 349 
 350         gacl_len = sizeof(struct gpfs_acl) +
 351                 (smb_get_naces(smbacl)-1)*sizeof(gpfs_ace_v4_t);
 352 
 353         gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len);
 354         if (gacl == NULL) {
 355                 DEBUG(0, ("talloc failed\n"));
 356                 errno = ENOMEM;
 357                 return False;
 358         }
 359 
 360         gacl->acl_len = gacl_len;
 361         gacl->acl_level = 0;
 362         gacl->acl_version = GPFS_ACL_VERSION_NFS4;
 363         gacl->acl_type = GPFS_ACL_TYPE_NFS4;
 364         gacl->acl_nace = 0; /* change later... */
 365 
 366         for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
 367                 struct gpfs_ace_v4 *gace = &gacl->ace_v4[gacl->acl_nace];
 368                 SMB_ACE4PROP_T  *aceprop = smb_get_ace4(smbace);
 369 
 370                 gace->aceType = aceprop->aceType;
 371                 gace->aceFlags = aceprop->aceFlags;
 372                 gace->aceMask = aceprop->aceMask;
 373 
 374                 /*
 375                  * GPFS can't distinguish between WRITE and APPEND on
 376                  * files, so one being set without the other is an
 377                  * error. Sorry for the many ()'s :-)
 378                  */
 379 
 380                 if (!fsp->is_directory
 381                     &&
 382                     ((((gace->aceMask & ACE4_MASK_WRITE) == 0)
 383                       && ((gace->aceMask & ACE4_MASK_APPEND) != 0))
 384                      ||
 385                      (((gace->aceMask & ACE4_MASK_WRITE) != 0)
 386                       && ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
 387                     &&
 388                     lp_parm_bool(fsp->conn->params->service, "gpfs",
 389                                  "merge_writeappend", True)) {
 390                         DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
 391                                   "WRITE^APPEND, setting WRITE|APPEND\n",
 392                                   fsp->fsp_name));
 393                         gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
 394                 }
 395 
 396                 gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;
 397 
 398                 if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
 399                 {
 400                         switch(aceprop->who.special_id)
 401                         {
 402                         case SMB_ACE4_WHO_EVERYONE:
 403                                 gace->aceWho = ACE4_SPECIAL_EVERYONE;
 404                                 break;
 405                         case SMB_ACE4_WHO_OWNER:
 406                                 gace->aceWho = ACE4_SPECIAL_OWNER;
 407                                 break;
 408                         case SMB_ACE4_WHO_GROUP:
 409                                 gace->aceWho = ACE4_SPECIAL_GROUP;
 410                                 break;
 411                         default:
 412                                 DEBUG(8, ("unsupported special_id %d\n", aceprop->who.special_id));
 413                                 continue; /* don't add it !!! */
 414                         }
 415                 } else {
 416                         /* just only for the type safety... */
 417                         if (aceprop->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
 418                                 gace->aceWho = aceprop->who.gid;
 419                         else
 420                                 gace->aceWho = aceprop->who.uid;
 421                 }
 422 
 423                 gacl->acl_nace++;
 424         }
 425 
 426         ret = smbd_gpfs_putacl(fsp->fsp_name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
 427         if (ret != 0) {
 428                 DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
 429                 gpfs_dumpacl(8, gacl);
 430                 return False;
 431         }
 432 
 433         DEBUG(10, ("gpfs_putacl succeeded\n"));
 434         return True;
 435 }
 436 
 437 static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd)
     /* [<][>][^][v][top][bottom][index][help] */
 438 {
 439         struct gpfs_acl *acl;
 440         NTSTATUS result = NT_STATUS_ACCESS_DENIED;
 441 
 442         acl = gpfs_getacl_alloc(fsp->fsp_name, 0);
 443         if (acl == NULL)
 444                 return result;
 445 
 446         if (acl->acl_version&GPFS_ACL_VERSION_NFS4)
 447         {
 448                 result = smb_set_nt_acl_nfs4(
 449                         fsp, security_info_sent, psd,
 450                         gpfsacl_process_smbacl);
 451         } else { /* assume POSIX ACL - by default... */
 452                 result = set_nt_acl(fsp, security_info_sent, psd);
 453         }
 454 
 455         return result;
 456 }
 457 
 458 static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd)
     /* [<][>][^][v][top][bottom][index][help] */
 459 {
 460         return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd);
 461 }
 462 
 463 static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl)
     /* [<][>][^][v][top][bottom][index][help] */
 464 {
 465         SMB_ACL_T result;
 466         int i;
 467 
 468         result = sys_acl_init(pacl->acl_nace);
 469         if (result == NULL) {
 470                 errno = ENOMEM;
 471                 return NULL;
 472         }
 473 
 474         result->count = pacl->acl_nace;
 475 
 476         for (i=0; i<pacl->acl_nace; i++) {
 477                 struct smb_acl_entry *ace = &result->acl[i];
 478                 const struct gpfs_ace_v1 *g_ace = &pacl->ace_v1[i];
 479 
 480                 DEBUG(10, ("Converting type %d id %lu perm %x\n",
 481                            (int)g_ace->ace_type, (unsigned long)g_ace->ace_who,
 482                            (int)g_ace->ace_perm));
 483 
 484                 switch (g_ace->ace_type) {
 485                 case GPFS_ACL_USER:
 486                         ace->a_type = SMB_ACL_USER;
 487                         ace->uid = (uid_t)g_ace->ace_who;
 488                         break;
 489                 case GPFS_ACL_USER_OBJ:
 490                         ace->a_type = SMB_ACL_USER_OBJ;
 491                         break;
 492                 case GPFS_ACL_GROUP:
 493                         ace->a_type = SMB_ACL_GROUP;
 494                         ace->gid = (gid_t)g_ace->ace_who;
 495                         break;
 496                 case GPFS_ACL_GROUP_OBJ:
 497                         ace->a_type = SMB_ACL_GROUP_OBJ;
 498                         break;
 499                 case GPFS_ACL_OTHER:
 500                         ace->a_type = SMB_ACL_OTHER;
 501                         break;
 502                 case GPFS_ACL_MASK:
 503                         ace->a_type = SMB_ACL_MASK;
 504                         break;
 505                 default:
 506                         DEBUG(10, ("Got invalid ace_type: %d\n",
 507                                    g_ace->ace_type));
 508                         errno = EINVAL;
 509                         SAFE_FREE(result);
 510                         return NULL;
 511                 }
 512 
 513                 ace->a_perm = 0;
 514                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_READ) ?
 515                         SMB_ACL_READ : 0;
 516                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_WRITE) ?
 517                         SMB_ACL_WRITE : 0;
 518                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_EXECUTE) ?
 519                         SMB_ACL_EXECUTE : 0;
 520 
 521                 DEBUGADD(10, ("Converted to %d perm %x\n",
 522                               ace->a_type, ace->a_perm));
 523         }
 524 
 525         return result;
 526 }
 527 
 528 static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type)
     /* [<][>][^][v][top][bottom][index][help] */
 529 {
 530         struct gpfs_acl *pacl;
 531         SMB_ACL_T result = NULL;
 532 
 533         pacl = gpfs_getacl_alloc(path, type);
 534 
 535         if (pacl == NULL) {
 536                 DEBUG(10, ("gpfs_getacl failed for %s with %s\n",
 537                            path, strerror(errno)));
 538                 if (errno == 0) {
 539                         errno = EINVAL;
 540                 }
 541                 goto done;
 542         }
 543 
 544         if (pacl->acl_version != GPFS_ACL_VERSION_POSIX) {
 545                 DEBUG(10, ("Got acl version %d, expected %d\n",
 546                            pacl->acl_version, GPFS_ACL_VERSION_POSIX));
 547                 errno = EINVAL;
 548                 goto done;
 549         }
 550 
 551         DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
 552                    pacl->acl_len, pacl->acl_level, pacl->acl_version,
 553                    pacl->acl_nace));
 554 
 555         result = gpfs2smb_acl(pacl);
 556         if (result == NULL) {
 557                 goto done;
 558         }
 559 
 560  done:
 561 
 562         if (errno != 0) {
 563                 SAFE_FREE(result);
 564         }
 565         return result;  
 566 }
 567 
 568 static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 569                                           const char *path_p,
 570                                           SMB_ACL_TYPE_T type)
 571 {
 572         gpfs_aclType_t gpfs_type;
 573 
 574         switch(type) {
 575         case SMB_ACL_TYPE_ACCESS:
 576                 gpfs_type = GPFS_ACL_TYPE_ACCESS;
 577                 break;
 578         case SMB_ACL_TYPE_DEFAULT:
 579                 gpfs_type = GPFS_ACL_TYPE_DEFAULT;
 580                 break;
 581         default:
 582                 DEBUG(0, ("Got invalid type: %d\n", type));
 583                 smb_panic("exiting");
 584         }
 585 
 586         return gpfsacl_get_posix_acl(path_p, gpfs_type);
 587 }
 588 
 589 static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 590                                         files_struct *fsp)
 591 {
 592         return gpfsacl_get_posix_acl(fsp->fsp_name, GPFS_ACL_TYPE_ACCESS);
 593 }
 594 
 595 static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
     /* [<][>][^][v][top][bottom][index][help] */
 596                                      SMB_ACL_TYPE_T type)
 597 {
 598         gpfs_aclLen_t len;
 599         struct gpfs_acl *result;
 600         int i;
 601         union gpfs_ace_union
 602         {
 603                 gpfs_ace_v1_t  ace_v1[1]; /* when GPFS_ACL_VERSION_POSIX */
 604                 gpfs_ace_v4_t  ace_v4[1]; /* when GPFS_ACL_VERSION_NFS4  */
 605         };
 606 
 607         DEBUG(10, ("smb2gpfs_acl: Got ACL with %d entries\n", pacl->count));
 608 
 609         len = sizeof(struct gpfs_acl) - sizeof(union gpfs_ace_union) +
 610                 (pacl->count)*sizeof(gpfs_ace_v1_t);
 611 
 612         result = (struct gpfs_acl *)SMB_MALLOC(len);
 613         if (result == NULL) {
 614                 errno = ENOMEM;
 615                 return result;
 616         }
 617 
 618         result->acl_len = len;
 619         result->acl_level = 0;
 620         result->acl_version = GPFS_ACL_VERSION_POSIX;
 621         result->acl_type = (type == SMB_ACL_TYPE_DEFAULT) ?
 622                 GPFS_ACL_TYPE_DEFAULT : GPFS_ACL_TYPE_ACCESS;
 623         result->acl_nace = pacl->count;
 624 
 625         for (i=0; i<pacl->count; i++) {
 626                 const struct smb_acl_entry *ace = &pacl->acl[i];
 627                 struct gpfs_ace_v1 *g_ace = &result->ace_v1[i];
 628 
 629                 DEBUG(10, ("Converting type %d perm %x\n",
 630                            (int)ace->a_type, (int)ace->a_perm));
 631 
 632                 g_ace->ace_perm = 0;
 633 
 634                 switch(ace->a_type) {
 635                 case SMB_ACL_USER:
 636                         g_ace->ace_type = GPFS_ACL_USER;
 637                         g_ace->ace_who = (gpfs_uid_t)ace->uid;
 638                         break;
 639                 case SMB_ACL_USER_OBJ:
 640                         g_ace->ace_type = GPFS_ACL_USER_OBJ;
 641                         g_ace->ace_perm |= ACL_PERM_CONTROL;
 642                         g_ace->ace_who = 0;
 643                         break;
 644                 case SMB_ACL_GROUP:
 645                         g_ace->ace_type = GPFS_ACL_GROUP;
 646                         g_ace->ace_who = (gpfs_uid_t)ace->gid;
 647                         break;
 648                 case SMB_ACL_GROUP_OBJ:
 649                         g_ace->ace_type = GPFS_ACL_GROUP_OBJ;
 650                         g_ace->ace_who = 0;
 651                         break;
 652                 case SMB_ACL_MASK:
 653                         g_ace->ace_type = GPFS_ACL_MASK;
 654                         g_ace->ace_perm = 0x8f;
 655                         g_ace->ace_who = 0;
 656                         break;
 657                 case SMB_ACL_OTHER:
 658                         g_ace->ace_type = GPFS_ACL_OTHER;
 659                         g_ace->ace_who = 0;
 660                         break;
 661                 default:
 662                         DEBUG(10, ("Got invalid ace_type: %d\n", ace->a_type));
 663                         errno = EINVAL;
 664                         SAFE_FREE(result);
 665                         return NULL;
 666                 }
 667 
 668                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_READ) ?
 669                         ACL_PERM_READ : 0;
 670                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_WRITE) ?
 671                         ACL_PERM_WRITE : 0;
 672                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_EXECUTE) ?
 673                         ACL_PERM_EXECUTE : 0;
 674 
 675                 DEBUGADD(10, ("Converted to %d id %d perm %x\n",
 676                               g_ace->ace_type, g_ace->ace_who, g_ace->ace_perm));
 677         }
 678 
 679         return result;
 680 }
 681 
 682 static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 683                                     const char *name,
 684                                     SMB_ACL_TYPE_T type,
 685                                     SMB_ACL_T theacl)
 686 {
 687         struct gpfs_acl *gpfs_acl;
 688         int result;
 689 
 690         gpfs_acl = smb2gpfs_acl(theacl, type);
 691         if (gpfs_acl == NULL) {
 692                 return -1;
 693         }
 694 
 695         result = smbd_gpfs_putacl((char *)name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gpfs_acl);
 696 
 697         SAFE_FREE(gpfs_acl);
 698         return result;
 699 }
 700 
 701 static int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 702                                   files_struct *fsp,
 703                                   SMB_ACL_T theacl)
 704 {
 705         return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name, SMB_ACL_TYPE_ACCESS, theacl);
 706 }
 707 
 708 static int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 709                                            const char *path)
 710 {
 711         errno = ENOTSUP;
 712         return -1;
 713 }
 714 
 715 /*
 716  * Assumed: mode bits are shiftable and standard
 717  * Output: the new aceMask field for an smb nfs4 ace
 718  */
 719 static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx)
     /* [<][>][^][v][top][bottom][index][help] */
 720 {
 721         const uint32 posix_nfs4map[3] = {
 722                 SMB_ACE4_EXECUTE, /* execute */
 723                 SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
 724                 SMB_ACE4_READ_DATA /* read */
 725         };
 726         int     i;
 727         uint32_t        posix_mask = 0x01;
 728         uint32_t        posix_bit;
 729         uint32_t        nfs4_bits;
 730 
 731         for(i=0; i<3; i++) {
 732                 nfs4_bits = posix_nfs4map[i];
 733                 posix_bit = rwx & posix_mask;
 734 
 735                 if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
 736                         if (posix_bit)
 737                                 aceMask |= nfs4_bits;
 738                         else
 739                                 aceMask &= ~nfs4_bits;
 740                 } else {
 741                         /* add deny bits when suitable */
 742                         if (!posix_bit)
 743                                 aceMask |= nfs4_bits;
 744                         else
 745                                 aceMask &= ~nfs4_bits;
 746                 } /* other ace types are unexpected */
 747 
 748                 posix_mask <<= 1;
 749         }
 750 
 751         return aceMask;
 752 }
 753 
 754 static int gpfsacl_emu_chmod(const char *path, mode_t mode)
     /* [<][>][^][v][top][bottom][index][help] */
 755 {
 756         SMB4ACL_T *pacl = NULL;
 757         int     result;
 758         bool    haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
 759         int     i;
 760         files_struct    fake_fsp; /* TODO: rationalize parametrization */
 761         SMB4ACE_T       *smbace;
 762 
 763         DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
 764 
 765         result = gpfs_get_nfs4_acl(path, &pacl);
 766         if (result)
 767                 return result;
 768 
 769         if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
 770                 DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
 771         }
 772 
 773         for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
 774                 SMB_ACE4PROP_T  *ace = smb_get_ace4(smbace);
 775                 uint32_t        specid = ace->who.special_id;
 776 
 777                 if (ace->flags&SMB_ACE4_ID_SPECIAL &&
 778                     ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
 779                     specid <= SMB_ACE4_WHO_EVERYONE) {
 780 
 781                         uint32_t newMask;
 782 
 783                         if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
 784                                 haveAllowEntry[specid] = True;
 785 
 786                         /* mode >> 6 for @owner, mode >> 3 for @group,
 787                          * mode >> 0 for @everyone */
 788                         newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
 789                                                       mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
 790                         if (ace->aceMask!=newMask) {
 791                                 DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
 792                                            path, ace->aceMask, newMask, specid));
 793                         }
 794                         ace->aceMask = newMask;
 795                 }
 796         }
 797 
 798         /* make sure we have at least ALLOW entries
 799          * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
 800          * - if necessary
 801          */
 802         for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
 803                 SMB_ACE4PROP_T  ace;
 804 
 805                 if (haveAllowEntry[i]==True)
 806                         continue;
 807 
 808                 ZERO_STRUCT(ace);
 809                 ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
 810                 ace.flags |= SMB_ACE4_ID_SPECIAL;
 811                 ace.who.special_id = i;
 812 
 813                 if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
 814                         ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
 815 
 816                 ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
 817                                                   mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
 818 
 819                 /* don't add unnecessary aces */
 820                 if (!ace.aceMask)
 821                         continue;
 822 
 823                 /* we add it to the END - as windows expects allow aces */
 824                 smb_add_ace4(pacl, &ace);
 825                 DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
 826                            path, mode, i, ace.aceMask));
 827         }
 828 
 829         /* don't add complementary DENY ACEs here */
 830         ZERO_STRUCT(fake_fsp);
 831         fake_fsp.fsp_name = (char *)path; /* no file_new is needed here */
 832 
 833         /* put the acl */
 834         if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False)
 835                 return -1;
 836         return 0; /* ok for [f]chmod */
 837 }
 838 
 839 static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
     /* [<][>][^][v][top][bottom][index][help] */
 840 {
 841                  SMB_STRUCT_STAT st;
 842                  int rc;
 843 
 844                  if (SMB_VFS_NEXT_STAT(handle, path, &st) != 0) {
 845                          return -1;
 846                  }
 847 
 848                  /* avoid chmod() if possible, to preserve acls */
 849                  if ((st.st_mode & ~S_IFMT) == mode) {
 850                          return 0;
 851                  }
 852 
 853                  rc = gpfsacl_emu_chmod(path, mode);
 854                  if (rc == 1)
 855                          return SMB_VFS_NEXT_CHMOD(handle, path, mode);
 856                  return rc;
 857 }
 858 
 859 static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
     /* [<][>][^][v][top][bottom][index][help] */
 860 {
 861                  SMB_STRUCT_STAT st;
 862                  int rc;
 863 
 864                  if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
 865                          return -1;
 866                  }
 867 
 868                  /* avoid chmod() if possible, to preserve acls */
 869                  if ((st.st_mode & ~S_IFMT) == mode) {
 870                          return 0;
 871                  }
 872 
 873                  rc = gpfsacl_emu_chmod(fsp->fsp_name, mode);
 874                  if (rc == 1)
 875                          return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
 876                  return rc;
 877 }
 878 
 879 /* VFS operations structure */
 880 
 881 static vfs_op_tuple gpfs_op_tuples[] = {
 882 
 883         { SMB_VFS_OP(vfs_gpfs_kernel_flock), 
 884           SMB_VFS_OP_KERNEL_FLOCK,
 885           SMB_VFS_LAYER_OPAQUE },
 886 
 887         { SMB_VFS_OP(vfs_gpfs_setlease), 
 888           SMB_VFS_OP_LINUX_SETLEASE,
 889           SMB_VFS_LAYER_OPAQUE },
 890 
 891         { SMB_VFS_OP(vfs_gpfs_get_real_filename),
 892           SMB_VFS_OP_GET_REAL_FILENAME,
 893           SMB_VFS_LAYER_OPAQUE },
 894 
 895         { SMB_VFS_OP(gpfsacl_fget_nt_acl), 
 896           SMB_VFS_OP_FGET_NT_ACL,
 897           SMB_VFS_LAYER_TRANSPARENT },
 898 
 899         { SMB_VFS_OP(gpfsacl_get_nt_acl), 
 900           SMB_VFS_OP_GET_NT_ACL,
 901           SMB_VFS_LAYER_TRANSPARENT },
 902 
 903         { SMB_VFS_OP(gpfsacl_fset_nt_acl), 
 904           SMB_VFS_OP_FSET_NT_ACL,
 905           SMB_VFS_LAYER_TRANSPARENT },
 906 
 907         { SMB_VFS_OP(gpfsacl_sys_acl_get_file), 
 908           SMB_VFS_OP_SYS_ACL_GET_FILE,
 909           SMB_VFS_LAYER_TRANSPARENT },
 910 
 911         { SMB_VFS_OP(gpfsacl_sys_acl_get_fd), 
 912           SMB_VFS_OP_SYS_ACL_GET_FD,
 913           SMB_VFS_LAYER_TRANSPARENT },
 914 
 915         { SMB_VFS_OP(gpfsacl_sys_acl_set_file), 
 916           SMB_VFS_OP_SYS_ACL_SET_FILE,
 917           SMB_VFS_LAYER_TRANSPARENT },
 918 
 919         { SMB_VFS_OP(gpfsacl_sys_acl_set_fd), 
 920           SMB_VFS_OP_SYS_ACL_SET_FD,
 921           SMB_VFS_LAYER_TRANSPARENT },
 922 
 923         { SMB_VFS_OP(gpfsacl_sys_acl_delete_def_file),
 924           SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
 925           SMB_VFS_LAYER_TRANSPARENT },
 926 
 927         { SMB_VFS_OP(vfs_gpfs_chmod), 
 928           SMB_VFS_OP_CHMOD,
 929           SMB_VFS_LAYER_TRANSPARENT },
 930 
 931         { SMB_VFS_OP(vfs_gpfs_fchmod), 
 932           SMB_VFS_OP_FCHMOD,
 933           SMB_VFS_LAYER_TRANSPARENT },
 934 
 935         { SMB_VFS_OP(vfs_gpfs_close),
 936           SMB_VFS_OP_CLOSE,
 937           SMB_VFS_LAYER_TRANSPARENT },
 938 
 939         { SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP }
 940 
 941 };
 942 
 943 
 944 NTSTATUS vfs_gpfs_init(void);
 945 NTSTATUS vfs_gpfs_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 946 {
 947         init_gpfs();
 948 
 949         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs",
 950                                 gpfs_op_tuples);
 951 }

/* [<][>][^][v][top][bottom][index][help] */