Merge latest fixes to vfs_gpfs and NFS4 ACLs from Samba 3.0 CTDB branch (from http...
authorAlexander Bokovoy <ab@samba.org>
Wed, 16 Jan 2008 09:18:57 +0000 (12:18 +0300)
committerAlexander Bokovoy <ab@samba.org>
Wed, 16 Jan 2008 09:18:57 +0000 (12:18 +0300)
Signed-off-by: Alexander Bokovoy <ab@samba.org>(This used to be commit 1daad835cbfb4615a8fe7a241f4d578f7e69f214)
source3/modules/gpfs.c
source3/modules/nfs4_acls.c
source3/modules/vfs_gpfs.c
source3/modules/vfs_gpfs.h [new file with mode: 0644]
source3/smbd/posix_acls.c

index 300e90fa697c7daa0ccea27a12135c307cd48d3b..590dbac26fe41c42108e4ef6717d7cd45519b116 100644 (file)
 #ifdef HAVE_GPFS
 
 #include "gpfs_gpl.h"
+#include "vfs_gpfs.h"
 
 static void *libgpfs_handle = NULL;
 static bool gpfs_share_modes;
+static bool gpfs_leases;
 
 static int (*gpfs_set_share_fn)(int fd, unsigned int allow, unsigned int deny);
 static int (*gpfs_set_lease_fn)(int fd, unsigned int leaseType);
@@ -42,7 +44,7 @@ bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask,
        if (!gpfs_share_modes) {
                return True;
        }
-
+       
        if (gpfs_set_share_fn == NULL) {
                return False;
        }
@@ -88,7 +90,7 @@ int set_gpfs_lease(int fd, int leasetype)
 {
        int gpfs_type = GPFS_LEASE_NONE;
 
-       if (!gpfs_share_modes) {
+       if (!gpfs_leases) {
                return True;
        }
 
@@ -103,6 +105,13 @@ int set_gpfs_lease(int fd, int leasetype)
        if (leasetype == F_WRLCK) {
                gpfs_type = GPFS_LEASE_WRITE;
        }
+       
+       /* we unconditionally set CAP_LEASE, rather than looking for
+          -1/EACCES as there is a bug in some versions of
+          libgpfs_gpl.so which results in a leaked fd on /dev/ss0
+          each time we try this with the wrong capabilities set
+       */
+       linux_set_lease_capability();
        return gpfs_set_lease_fn(fd, gpfs_type);
 }
 
@@ -172,11 +181,8 @@ void init_gpfs(void)
                goto failed;
        }
 
-       if (lp_parm_bool(-1, "gpfs", "sharemodes", True)) {
-               gpfs_share_modes = True;
-       } else {
-               gpfs_share_modes = False;
-       }
+       gpfs_share_modes = lp_parm_bool(-1, "gpfs", "sharemodes", True);
+       gpfs_leases      = lp_parm_bool(-1, "gpfs", "leases", True);
 
        return;
 
index 52d3983fff7ee43239b5742b16fe98dfe67ede78..0c3d010dcde64553487648b50ef23dc6e46d619f 100644 (file)
@@ -20,6 +20,9 @@
 #include "includes.h"
 #include "nfs4_acls.h"
 
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ACLS
+
 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
 
 #define SMB_ACE4_INT_MAGIC 0x76F8A967
@@ -352,6 +355,7 @@ typedef struct _smbacl4_vfs_params {
        enum smbacl4_mode_enum mode;
        bool do_chown;
        enum smbacl4_acedup_enum acedup;
+       struct db_context *sid_mapping_table;
 } smbacl4_vfs_params;
 
 /*
@@ -451,8 +455,65 @@ static SMB_ACE4PROP_T *smbacl4_find_equal_special(
        return NULL;
 }
 
-static int smbacl4_fill_ace4(
+static bool nfs4_map_sid(smbacl4_vfs_params *params, const DOM_SID *src,
+                        DOM_SID *dst)
+{
+       static struct db_context *mapping_db = NULL;
+       TDB_DATA data;
+       
+       if (mapping_db == NULL) {
+               const char *dbname = lp_parm_const_string(
+                       -1, SMBACL4_PARAM_TYPE_NAME, "sidmap", NULL);
+               
+               if (dbname == NULL) {
+                       DEBUG(10, ("%s:sidmap not defined\n",
+                                  SMBACL4_PARAM_TYPE_NAME));
+                       return False;
+               }
+               
+               become_root();
+               mapping_db = db_open(NULL, dbname, 0, TDB_DEFAULT,
+                                    O_RDONLY, 0600);
+               unbecome_root();
+               
+               if (mapping_db == NULL) {
+                       DEBUG(1, ("could not open sidmap: %s\n",
+                                 strerror(errno)));
+                       return False;
+               }
+       }
+       
+       if (mapping_db->fetch(mapping_db, NULL,
+                             string_term_tdb_data(sid_string_tos(src)),
+                             &data) == -1) {
+               DEBUG(10, ("could not find mapping for SID %s\n",
+                          sid_string_dbg(src)));
+               return False;
+       }
+       
+       if ((data.dptr == NULL) || (data.dsize <= 0)
+           || (data.dptr[data.dsize-1] != '\0')) {
+               DEBUG(5, ("invalid mapping for SID %s\n",
+                         sid_string_dbg(src)));
+               TALLOC_FREE(data.dptr);
+               return False;
+       }
+       
+       if (!string_to_sid(dst, (char *)data.dptr)) {
+               DEBUG(1, ("invalid mapping %s for SID %s\n",
+                         (char *)data.dptr, sid_string_dbg(src)));
+               TALLOC_FREE(data.dptr);
+               return False;
+       }
+
+       TALLOC_FREE(data.dptr);
+       
+       return True;
+}
+
+static bool smbacl4_fill_ace4(
        TALLOC_CTX *mem_ctx,
+       const char *filename,
        smbacl4_vfs_params *params,
        uid_t ownerUID,
        gid_t ownerGID,
@@ -460,11 +521,6 @@ static int smbacl4_fill_ace4(
        SMB_ACE4PROP_T *ace_v4 /* output */
 )
 {
-       const char *dom, *name;
-       enum lsa_SidType type;
-       uid_t uid;
-       gid_t gid;
-
        DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
 
        memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
@@ -485,18 +541,46 @@ static int smbacl4_fill_ace4(
                ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
                ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
        } else {
-               if (!lookup_sid(mem_ctx, &ace_nt->trustee, &dom, &name, &type)) {
-                       DEBUG(8, ("Could not find %s' type\n",
-                                 sid_string_dbg(&ace_nt->trustee)));
-                       errno = EINVAL;
-                       return -1;
+               const char *dom, *name;
+               enum lsa_SidType type;
+               uid_t uid;
+               gid_t gid;
+               DOM_SID sid;
+               
+               sid_copy(&sid, &ace_nt->trustee);
+               
+               if (!lookup_sid(mem_ctx, &sid, &dom, &name, &type)) {
+                       
+                       DOM_SID mapped;
+                       
+                       if (!nfs4_map_sid(params, &sid, &mapped)) {
+                               DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
+                                         "unknown\n", filename, sid_string_dbg(&sid)));
+                               errno = EINVAL;
+                               return False;
+                       }
+                       
+                       DEBUG(2, ("nfs4_acls.c: file [%s]: mapped SID %s "
+                                 "to %s\n", filename, sid_string_dbg(&sid), sid_string_dbg(&mapped)));
+                       
+                       if (!lookup_sid(mem_ctx, &mapped, &dom,
+                                       &name, &type)) {
+                               DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
+                                         "mapped from %s is unknown\n",
+                                         filename, sid_string_dbg(&mapped), sid_string_dbg(&sid)));
+                               errno = EINVAL;
+                               return False;
+                       }
+                       
+                       sid_copy(&sid, &mapped);
                }
-
+               
                if (type == SID_NAME_USER) {
-                       if (!sid_to_uid(&ace_nt->trustee, &uid)) {
-                               DEBUG(2, ("Could not convert %s to uid\n",
-                                         sid_string_dbg(&ace_nt->trustee)));
-                               return -1;
+                       if (!sid_to_uid(&sid, &uid)) {
+                               DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
+                                         "convert %s to uid\n", filename,
+                                         sid_string_dbg(&sid)));
+                               return False;
                        }
 
                        if (params->mode==e_special && uid==ownerUID) {
@@ -506,11 +590,13 @@ static int smbacl4_fill_ace4(
                                ace_v4->who.uid = uid;
                        }
                } else { /* else group? - TODO check it... */
-                       if (!sid_to_gid(&ace_nt->trustee, &gid)) {
-                               DEBUG(2, ("Could not convert %s to gid\n",
-                                         sid_string_dbg(&ace_nt->trustee)));
-                               return -1;
+                       if (!sid_to_gid(&sid, &gid)) {
+                               DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
+                                         "convert %s to gid\n", filename,
+                                         sid_string_dbg(&sid)));
+                               return False;
                        }
+                               
                        ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
 
                        if (params->mode==e_special && gid==ownerGID) {
@@ -522,7 +608,7 @@ static int smbacl4_fill_ace4(
                }
        }
 
-       return 0; /* OK */
+       return True; /* OK */
 }
 
 static int smbacl4_MergeIgnoreReject(
@@ -560,6 +646,7 @@ static int smbacl4_MergeIgnoreReject(
 }
 
 static SMB4ACL_T *smbacl4_win2nfs4(
+       const char *filename,
        SEC_ACL *dacl,
        smbacl4_vfs_params *pparams,
        uid_t ownerUID,
@@ -580,9 +667,14 @@ static SMB4ACL_T *smbacl4_win2nfs4(
                SMB_ACE4PROP_T  ace_v4;
                bool    addNewACE = True;
 
-               if (smbacl4_fill_ace4(mem_ctx, pparams, ownerUID, ownerGID,
-                       dacl->aces + i, &ace_v4))
-                       return NULL;
+               if (!smbacl4_fill_ace4(mem_ctx, filename, pparams,
+                                      ownerUID, ownerGID,
+                                      dacl->aces + i, &ace_v4)) {
+                       DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
+                                 filename,
+                                 sid_string_dbg(&((dacl->aces+i)->trustee))));
+                       continue;
+               }
 
                if (pparams->acedup!=e_dontcare) {
                        if (smbacl4_MergeIgnoreReject(pparams->acedup, acl,
@@ -607,6 +699,7 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
        bool    result;
 
        SMB_STRUCT_STAT sbuf;
+       bool need_chown = False;
        uid_t newUID = (uid_t)-1;
        gid_t newGID = (gid_t)-1;
 
@@ -635,25 +728,33 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
                        return status;
                }
                if (((newUID != (uid_t)-1) && (sbuf.st_uid != newUID)) ||
-                               ((newGID != (gid_t)-1) && (sbuf.st_gid != newGID))) {
-                       if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
-                               DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n",
-                                       fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID, strerror(errno) ));
-                               if (errno == EPERM) {
-                                       return NT_STATUS_INVALID_OWNER;
+                   ((newGID != (gid_t)-1) && (sbuf.st_gid != newGID))) {
+                       need_chown = True;
+               }
+               if (need_chown) {
+                       if ((newUID == (uid_t)-1 || newUID == current_user.ut.uid)) {
+                               if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
+                                       DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n",
+                                                fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID, 
+                                                strerror(errno)));
+                                       return map_nt_error_from_unix(errno);
                                }
-                               return map_nt_error_from_unix(errno);
+
+                               DEBUG(10,("chown %s, %u, %u succeeded.\n",
+                                         fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
+                               if (smbacl4_GetFileOwner(fsp->conn, fsp->fsp_name, &sbuf))
+                                       return map_nt_error_from_unix(errno);
+                               need_chown = False;
+                       } else { /* chown is needed, but _after_ changing acl */
+                               sbuf.st_uid = newUID; /* OWNER@ in case of e_special */
+                               sbuf.st_gid = newGID; /* GROUP@ in case of e_special */
                        }
-                       DEBUG(10,("chown %s, %u, %u succeeded.\n",
-                               fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
-                       if (smbacl4_fGetFileOwner(fsp, &sbuf))
-                               return map_nt_error_from_unix(errno);
                }
        }
 
        if ((security_info_sent & DACL_SECURITY_INFORMATION)!=0 && psd->dacl!=NULL)
        {
-               acl = smbacl4_win2nfs4(psd->dacl, &params, sbuf.st_uid, sbuf.st_gid);
+               acl = smbacl4_win2nfs4(fsp->fsp_name, psd->dacl, &params, sbuf.st_uid, sbuf.st_gid);
                if (!acl)
                        return map_nt_error_from_unix(errno);
 
@@ -668,6 +769,20 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
        } else
                DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n", security_info_sent));
 
+       /* Any chown pending? */
+       if (need_chown) {
+               DEBUG(3,("chown#2 %s. uid = %u, gid = %u.\n",
+                        fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
+               if (try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
+                       DEBUG(2,("chown#2 %s, %u, %u failed. Error = %s.\n",
+                                fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID,
+                                strerror(errno)));
+                       return map_nt_error_from_unix(errno);
+               }
+               DEBUG(10,("chown#2 %s, %u, %u succeeded.\n",
+                         fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
+       }
+
        DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
        return NT_STATUS_OK;
 }
index bcf61f3bc75f6a49ef91e7ddb853a5c68998458a..d10906dfb1e07da32a85d06f92dab0d2f322ff05 100644 (file)
@@ -30,7 +30,7 @@
 
 #include <gpfs_gpl.h>
 #include "nfs4_acls.h"
-
+#include "vfs_gpfs.h"
 
 static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, 
                                 uint32 share_mode)
@@ -153,7 +153,7 @@ static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
        DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
 
        /* First get the real acl length */
-       gacl = gpfs_getacl_alloc(fname, GPFS_ACL_TYPE_NFS4);
+       gacl = gpfs_getacl_alloc(fname, 0);
        if (gacl == NULL) {
                DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
                           fname, strerror(errno)));
@@ -208,10 +208,10 @@ static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
                if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
                        struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1];
                        if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
-                                       prev->aceFlags == gace->aceFlags &&
-                                       prev->aceIFlags == gace->aceIFlags &&
-                                       (gace->aceMask & prev->aceMask) == 0 &&
-                                       gace->aceWho == prev->aceWho) {
+                           prev->aceFlags == gace->aceFlags &&
+                           prev->aceIFlags == gace->aceIFlags &&
+                           (gace->aceMask & prev->aceMask) == 0 &&
+                           gace->aceWho == prev->aceWho) {
                                /* its redundent - skip it */
                                continue;
                        }                                                
@@ -256,7 +256,7 @@ static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
        int     result;
 
        *ppdesc = NULL;
-       result = gpfs_get_nfs4_acl(fsp->fsp_name, &pacl);
+       result = gpfs_get_nfs4_acl(name, &pacl);
 
        if (result == 0)
                return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl);
@@ -301,8 +301,31 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
                gace->aceType = aceprop->aceType;
                gace->aceFlags = aceprop->aceFlags;
                gace->aceMask = aceprop->aceMask;
+               
+               /*
+                * GPFS can't distinguish between WRITE and APPEND on
+                * files, so one being set without the other is an
+                * error. Sorry for the many ()'s :-)
+                */
+               
+               if (!fsp->is_directory
+                   &&
+                   ((((gace->aceMask & ACE4_MASK_WRITE) == 0)
+                     && ((gace->aceMask & ACE4_MASK_APPEND) != 0))
+                    ||
+                    (((gace->aceMask & ACE4_MASK_WRITE) != 0)
+                     && ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
+                   &&
+                   lp_parm_bool(fsp->conn->params->service, "gpfs",
+                                "merge_writeappend", True)) {
+                       DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
+                                 "WRITE^APPEND, setting WRITE|APPEND\n",
+                                 fsp->fsp_name));
+                       gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
+               }
+               
                gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;
-
+               
                if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
                {
                        switch(aceprop->who.special_id)
@@ -347,7 +370,7 @@ static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_i
        struct gpfs_acl *acl;
        NTSTATUS result = NT_STATUS_ACCESS_DENIED;
 
-       acl = gpfs_getacl_alloc(fsp->fsp_name, GPFS_ACL_TYPE_ACCESS);
+       acl = gpfs_getacl_alloc(fsp->fsp_name, 0);
        if (acl == NULL)
                return result;
 
@@ -628,75 +651,225 @@ int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
        return -1;
 }
 
+/*
+ * Assumed: mode bits are shiftable and standard
+ * Output: the new aceMask field for an smb nfs4 ace
+ */
+static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx)
+{
+       const uint32 posix_nfs4map[3] = {
+                SMB_ACE4_EXECUTE, /* execute */
+               SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
+                SMB_ACE4_READ_DATA /* read */
+       };
+       int     i;
+       uint32_t        posix_mask = 0x01;
+       uint32_t        posix_bit;
+       uint32_t        nfs4_bits;
+       
+       for(i=0; i<3; i++) {
+               nfs4_bits = posix_nfs4map[i];
+               posix_bit = rwx & posix_mask;
+               
+               if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
+                       if (posix_bit)
+                               aceMask |= nfs4_bits;
+                       else
+                               aceMask &= ~nfs4_bits;
+               } else {
+                       /* add deny bits when suitable */
+                       if (!posix_bit)
+                               aceMask |= nfs4_bits;
+                       else
+                               aceMask &= ~nfs4_bits;
+               } /* other ace types are unexpected */
+               
+               posix_mask <<= 1;
+       }
+       
+       return aceMask;
+}
+
+static int gpfsacl_emu_chmod(const char *path, mode_t mode)
+{
+       SMB4ACL_T *pacl = NULL;
+       int     result;
+       bool    haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
+       int     i;
+       files_struct    fake_fsp; /* TODO: rationalize parametrization */
+       SMB4ACE_T       *smbace;
+       
+       DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
+       
+       result = gpfs_get_nfs4_acl(path, &pacl);
+       if (result)
+               return result;
+       
+       if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
+               DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
+       }
+       
+       for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
+               SMB_ACE4PROP_T  *ace = smb_get_ace4(smbace);
+               uint32_t        specid = ace->who.special_id;
+               
+               if (ace->flags&SMB_ACE4_ID_SPECIAL &&
+                   ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
+                   specid <= SMB_ACE4_WHO_EVERYONE) {
+                       
+                       uint32_t newMask;
+                       
+                       if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
+                               haveAllowEntry[specid] = True;
+                       
+                       /* mode >> 6 for @owner, mode >> 3 for @group,
+                        * mode >> 0 for @everyone */
+                       newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
+                                                     mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
+                       if (ace->aceMask!=newMask) {
+                               DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
+                                          path, ace->aceMask, newMask, specid));
+                       }
+                       ace->aceMask = newMask;
+               }
+       }
+
+       /* make sure we have at least ALLOW entries
+        * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
+        * - if necessary
+        */
+       for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
+               SMB_ACE4PROP_T  ace;
+               
+               if (haveAllowEntry[i]==True)
+                       continue;
+               
+               memset(&ace, 0, sizeof(SMB_ACE4PROP_T));
+               ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
+               ace.flags |= SMB_ACE4_ID_SPECIAL;
+               ace.who.special_id = i;
+               
+               if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
+                       ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
+               
+               ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
+                                                 mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
+               
+               /* don't add unnecessary aces */
+               if (!ace.aceMask)
+                       continue;
+               
+               /* we add it to the END - as windows expects allow aces */
+               smb_add_ace4(pacl, &ace);
+               DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
+                          path, mode, i, ace.aceMask));
+       }
+       
+       /* don't add complementary DENY ACEs here */
+       memset(&fake_fsp, 0, sizeof(struct files_struct));
+       fake_fsp.fsp_name = (char *)path; /* no file_new is needed here */
+       
+       /* put the acl */
+       if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False)
+               return -1;
+       return 0; /* ok for [f]chmod */
+}
+
 static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
 {
                 SMB_STRUCT_STAT st;
+                int rc;
+                
                 if (SMB_VFS_NEXT_STAT(handle, path, &st) != 0) {
-                                return -1;
+                        return -1;
                 }
+                
                 /* avoid chmod() if possible, to preserve acls */
                 if ((st.st_mode & ~S_IFMT) == mode) {
-                                return 0;
+                        return 0;
                 }
-                return SMB_VFS_NEXT_CHMOD(handle, path, mode);
+
+                rc = gpfsacl_emu_chmod(path, mode);
+                if (rc == 1)
+                        return SMB_VFS_NEXT_CHMOD(handle, path, mode);
+                return rc;
 }
 
 static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
 {
                 SMB_STRUCT_STAT st;
+                int rc;
+                
                 if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
-                                return -1;
+                        return -1;
                 }
+
                 /* avoid chmod() if possible, to preserve acls */
                 if ((st.st_mode & ~S_IFMT) == mode) {
-                                return 0;
+                        return 0;
                 }
-                return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
+
+                rc = gpfsacl_emu_chmod(fsp->fsp_name, mode);
+                if (rc == 1)
+                        return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
+                return rc;
 }
 
 /* VFS operations structure */
 
 static vfs_op_tuple gpfs_op_tuples[] = {
-
-               { SMB_VFS_OP(vfs_gpfs_kernel_flock), SMB_VFS_OP_KERNEL_FLOCK,
-                               SMB_VFS_LAYER_OPAQUE },
-
-        { SMB_VFS_OP(vfs_gpfs_setlease), SMB_VFS_OP_LINUX_SETLEASE,
-                       SMB_VFS_LAYER_OPAQUE },
-
-        { SMB_VFS_OP(gpfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL,
-                       SMB_VFS_LAYER_TRANSPARENT },
-
-        { SMB_VFS_OP(gpfsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL,
-                       SMB_VFS_LAYER_TRANSPARENT },
-
-        { SMB_VFS_OP(gpfsacl_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL,
-                       SMB_VFS_LAYER_TRANSPARENT },
-
-        { SMB_VFS_OP(gpfsacl_set_nt_acl), SMB_VFS_OP_SET_NT_ACL,
-                       SMB_VFS_LAYER_TRANSPARENT },
-
-        { SMB_VFS_OP(gpfsacl_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE,
-                       SMB_VFS_LAYER_TRANSPARENT },
-
-        { SMB_VFS_OP(gpfsacl_sys_acl_get_fd), SMB_VFS_OP_SYS_ACL_GET_FD,
-                       SMB_VFS_LAYER_TRANSPARENT },
-
-        { SMB_VFS_OP(gpfsacl_sys_acl_set_file), SMB_VFS_OP_SYS_ACL_SET_FILE,
-                       SMB_VFS_LAYER_TRANSPARENT },
-
-        { SMB_VFS_OP(gpfsacl_sys_acl_set_fd), SMB_VFS_OP_SYS_ACL_SET_FD,
-                       SMB_VFS_LAYER_TRANSPARENT },
-
+       
+       { SMB_VFS_OP(vfs_gpfs_kernel_flock), 
+         SMB_VFS_OP_KERNEL_FLOCK,
+         SMB_VFS_LAYER_OPAQUE },
+       
+        { SMB_VFS_OP(vfs_gpfs_setlease), 
+         SMB_VFS_OP_LINUX_SETLEASE,
+         SMB_VFS_LAYER_OPAQUE },
+       
+        { SMB_VFS_OP(gpfsacl_fget_nt_acl), 
+         SMB_VFS_OP_FGET_NT_ACL,
+         SMB_VFS_LAYER_TRANSPARENT },
+       
+        { SMB_VFS_OP(gpfsacl_get_nt_acl), 
+         SMB_VFS_OP_GET_NT_ACL,
+         SMB_VFS_LAYER_TRANSPARENT },
+       
+        { SMB_VFS_OP(gpfsacl_fset_nt_acl), 
+         SMB_VFS_OP_FSET_NT_ACL,
+         SMB_VFS_LAYER_TRANSPARENT },
+       
+        { SMB_VFS_OP(gpfsacl_set_nt_acl), 
+         SMB_VFS_OP_SET_NT_ACL,
+         SMB_VFS_LAYER_TRANSPARENT },
+       
+        { SMB_VFS_OP(gpfsacl_sys_acl_get_file), 
+         SMB_VFS_OP_SYS_ACL_GET_FILE,
+         SMB_VFS_LAYER_TRANSPARENT },
+       
+        { SMB_VFS_OP(gpfsacl_sys_acl_get_fd), 
+         SMB_VFS_OP_SYS_ACL_GET_FD,
+         SMB_VFS_LAYER_TRANSPARENT },
+       
+        { SMB_VFS_OP(gpfsacl_sys_acl_set_file), 
+         SMB_VFS_OP_SYS_ACL_SET_FILE,
+         SMB_VFS_LAYER_TRANSPARENT },
+       
+        { SMB_VFS_OP(gpfsacl_sys_acl_set_fd), 
+         SMB_VFS_OP_SYS_ACL_SET_FD,
+         SMB_VFS_LAYER_TRANSPARENT },
+       
         { SMB_VFS_OP(gpfsacl_sys_acl_delete_def_file),
-                SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
-                SMB_VFS_LAYER_TRANSPARENT },
-
-        { SMB_VFS_OP(vfs_gpfs_chmod), SMB_VFS_OP_CHMOD,
-                SMB_VFS_LAYER_TRANSPARENT },
-
-        { SMB_VFS_OP(vfs_gpfs_fchmod), SMB_VFS_OP_FCHMOD,
-                SMB_VFS_LAYER_TRANSPARENT },
+         SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+         SMB_VFS_LAYER_TRANSPARENT },
+       
+        { SMB_VFS_OP(vfs_gpfs_chmod), 
+         SMB_VFS_OP_CHMOD,
+         SMB_VFS_LAYER_TRANSPARENT },
+       
+        { SMB_VFS_OP(vfs_gpfs_fchmod), 
+         SMB_VFS_OP_FCHMOD,
+         SMB_VFS_LAYER_TRANSPARENT },
 
         { SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP }
 
diff --git a/source3/modules/vfs_gpfs.h b/source3/modules/vfs_gpfs.h
new file mode 100644 (file)
index 0000000..3c499b0
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+   Unix SMB/CIFS implementation.
+   Wrap gpfs calls in vfs functions.
+   Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006
+   
+   Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com>
+                            and Gomati Mohanan <gomati.mohanan@in.ibm.com>
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  
+
+*/
+
+bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask,
+                       uint32 share_access);
+int set_gpfs_lease(int fd, int leasetype);
+int smbd_gpfs_getacl(char *pathname, int flags, void *acl);
+int smbd_gpfs_putacl(char *pathname, int flags, void *acl);
+void init_gpfs(void);
index 5f18615f6651e731219efff2cd65e0c2d80f6d22..6cec39f9c0103b96d62c87da42035664af47cc83 100644 (file)
@@ -3413,6 +3413,9 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
        bool acl_perms = False;
        mode_t orig_mode = (mode_t)0;
        NTSTATUS status;
+       uid_t orig_uid;
+       gid_t orig_gid;
+       bool need_chown = False;
 
        DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
 
@@ -3435,6 +3438,8 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
 
        /* Save the original elements we check against. */
        orig_mode = sbuf.st_mode;
+       orig_uid = sbuf.st_uid;
+       orig_gid = sbuf.st_gid;
 
        /*
         * Unpack the user/group/world id's.
@@ -3449,7 +3454,11 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
         * Do we need to chown ?
         */
 
-       if (((user != (uid_t)-1) && (sbuf.st_uid != user)) || (( grp != (gid_t)-1) && (sbuf.st_gid != grp))) {
+       if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp))) {
+               need_chown = True;
+       }
+
+       if (need_chown && (user == (uid_t)-1 || user == current_user.ut.uid)) {
 
                DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
                                fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
@@ -3487,6 +3496,11 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
 
                /* Save the original elements we check against. */
                orig_mode = sbuf.st_mode;
+               orig_uid = sbuf.st_uid;
+               orig_gid = sbuf.st_gid;
+
+               /* We did chown already, drop the flag */
+               need_chown = False;
        }
 
        create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
@@ -3630,6 +3644,21 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
                free_canon_ace_list(dir_ace_list); 
        }
 
+       /* Any chown pending? */
+       if (need_chown) {
+               DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
+                        fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
+               
+               if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
+                       DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
+                                fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
+                       if (errno == EPERM) {
+                               return NT_STATUS_INVALID_OWNER;
+                       }
+                       return map_nt_error_from_unix(errno);
+               }
+       }
+       
        return NT_STATUS_OK;
 }