Added "inherit permissions" patch.
authorJeremy Allison <jra@samba.org>
Fri, 14 Jan 2000 01:41:04 +0000 (01:41 +0000)
committerJeremy Allison <jra@samba.org>
Fri, 14 Jan 2000 01:41:04 +0000 (01:41 +0000)
Fixed locking bug found by Andrew.
Jeremy.

source/include/proto.h
source/lib/interfaces.c
source/lib/util.c
source/param/loadparm.c
source/smbd/blocking.c
source/smbd/dosmode.c
source/smbd/nttrans.c
source/smbd/open.c
source/smbd/reply.c
source/smbd/trans2.c

index e2d6c2e5d4462ea2ff561f0826e148a1f82ae0f0..c3bbb505a2e5c3379ecc9d943f9021a62bfcaa32 100644 (file)
@@ -347,6 +347,7 @@ char *smbd_mktemp(char *template);
 void *memdup(void *p, size_t size);
 char *myhostname(void);
 char *lock_path(char *name);
+char *parent_dirname(const char *path);
 
 /*The following definitions come from  lib/util_array.c  */
 
@@ -1336,6 +1337,7 @@ BOOL lp_dos_filetimes(int );
 BOOL lp_dos_filetime_resolution(int );
 BOOL lp_fake_dir_create_times(int );
 BOOL lp_blocking_locks(int );
+BOOL lp_inherit_perms(int );
 int lp_create_mask(int );
 int lp_force_create_mode(int );
 int _lp_security_mask(int );
@@ -2612,7 +2614,7 @@ void DirCacheFlush(int snum);
 
 /*The following definitions come from  smbd/dosmode.c  */
 
-mode_t unix_mode(connection_struct *conn,int dosmode);
+mode_t unix_mode(connection_struct *conn,int dosmode,const char *fname);
 int dos_mode(connection_struct *conn,char *path,SMB_STRUCT_STAT *sbuf);
 int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *st);
 int file_utime(connection_struct *conn, char *fname, struct utimbuf *times);
index 29181c394a94e370c8893a6d0fc261570b240a5e..e7b9efa1f0adad49584325c1f64c43c1da723035 100644 (file)
@@ -39,6 +39,9 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <sys/ioctl.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
 #include <net/if.h>
 
 #ifndef SIOCGIFCONF
index a39dc1a516e8c7987522e573bd78029f2c5cfb98..001baa0e3e333b3c13d668dcf428541dbbcb2b15 100644 (file)
@@ -3280,3 +3280,31 @@ char *lock_path(char *name)
 
        return fname;
 }
+
+/*******************************************************************
+ Given a filename - get its directory name
+ NB: Returned in static storage.  Caveats:
+ o  Not safe in thread environment.
+ o  Caller must not free.
+ o  If caller wishes to preserve, they should copy.
+********************************************************************/
+
+char *parent_dirname(const char *path)
+{
+       static pstring dirpath;
+       char *p;
+
+       if (!path)
+               return(NULL);
+
+       pstrcpy(dirpath, path);
+       p = strrchr(dirpath, '/');  /* Find final '/', if any */
+       if (!p) {
+               pstrcpy(dirpath, ".");    /* No final "/", so dir is "." */
+       } else {
+               if (p == dirpath)
+                       ++p;    /* For root "/", leave "/" in place */
+               *p = '\0';
+       }
+       return dirpath;
+}
index 3ac6d78f04a7febc6416c8f8dd654a2ed362b861..eb981fb5d24ed53d247e19e37bdb99978b88fdd6 100644 (file)
@@ -357,6 +357,7 @@ typedef struct
   BOOL bDosFiletimeResolution;
   BOOL bFakeDirCreateTimes;
   BOOL bBlockingLocks;
+  BOOL bInheritPerms; 
   char dummy[3]; /* for alignment */
 } service;
 
@@ -462,6 +463,7 @@ static service sDefault =
   False, /* bDosFiletimeResolution */
   False, /* bFakeDirCreateTimes */
   True,  /* bBlockingLocks */
+  False, /* bInheritPerms */
   ""     /* dummy */
 };
 
@@ -609,6 +611,7 @@ static struct parm_struct parm_table[] =
   {"force directory mode",   P_OCTAL,P_LOCAL,&sDefault.iDir_force_mode, NULL,   NULL,  FLAG_GLOBAL|FLAG_SHARE},
   {"directory security mask",P_OCTAL,P_LOCAL,&sDefault.iDir_Security_mask,NULL, NULL,  FLAG_GLOBAL|FLAG_SHARE},
   {"force directory security mode",P_OCTAL, P_LOCAL,  &sDefault.iDir_Security_force_mode,NULL,NULL,FLAG_GLOBAL|FLAG_SHARE},
+  {"inherit permissions",P_BOOL,  P_LOCAL,  &sDefault.bInheritPerms,    NULL,   NULL,  FLAG_SHARE},
   {"guest only",       P_BOOL,    P_LOCAL,  &sDefault.bGuest_only,      NULL,   NULL,  FLAG_SHARE},
   {"only guest",       P_BOOL,    P_LOCAL,  &sDefault.bGuest_only,      NULL,   NULL,  0},
   {"guest ok",         P_BOOL,    P_LOCAL,  &sDefault.bGuest_ok,        NULL,   NULL,  FLAG_BASIC|FLAG_SHARE|FLAG_PRINT},
@@ -1397,6 +1400,7 @@ FN_LOCAL_BOOL(lp_dos_filetimes,bDosFiletimes)
 FN_LOCAL_BOOL(lp_dos_filetime_resolution,bDosFiletimeResolution)
 FN_LOCAL_BOOL(lp_fake_dir_create_times,bFakeDirCreateTimes)
 FN_LOCAL_BOOL(lp_blocking_locks,bBlockingLocks)
+FN_LOCAL_BOOL(lp_inherit_perms,bInheritPerms)
 
 FN_LOCAL_INTEGER(lp_create_mask,iCreate_mask)
 FN_LOCAL_INTEGER(lp_force_create_mode,iCreate_force_mode)
index 5e7d4a0c879f916a88421fa8c900fe287944d024..292eb2455eb2f32ac1a5f2b5a5389f5415842bc9 100644 (file)
@@ -208,7 +208,13 @@ static void reply_lockingX_error(blocking_lock_record *blr, int eclass, int32 ec
    * of smb_lkrng structs.
    */
 
-  for(i = blr->lock_num; i >= 0; i--) {
+  /*
+   * Ensure we don't do a remove on the lock that just failed,
+   * as under POSIX rules, if we have a lock already there, we
+   * will delete it (and we shouldn't) .....
+   */
+
+  for(i = blr->lock_num - 1; i >= 0; i--) {
     int dummy1;
     uint32 dummy2;
     BOOL err;
index 27393fe1c6c9b452ca7229d41ffa63058dc73b58..9690f115c444e2701803bc05fd505855da7aa000 100644 (file)
@@ -26,33 +26,68 @@ extern int DEBUGLEVEL;
 /****************************************************************************
   change a dos mode to a unix mode
     base permission for files:
-         everybody gets read bit set
+         if inheriting
+           apply read/write bits from parent directory.
+         else   
+           everybody gets read bit set
          dos readonly is represented in unix by removing everyone's write bit
          dos archive is represented in unix by the user's execute bit
          dos system is represented in unix by the group's execute bit
          dos hidden is represented in unix by the other's execute bit
-         Then apply create mask,
-         then add force bits.
+         if !inheriting {
+           Then apply create mask,
+           then add force bits.
+         }
     base permission for directories:
          dos directory is represented in unix by unix's dir bit and the exec bit
-         Then apply create mask,
-         then add force bits.
+         if !inheriting {
+           Then apply create mask,
+           then add force bits.
+         }
 ****************************************************************************/
-mode_t unix_mode(connection_struct *conn,int dosmode)
+mode_t unix_mode(connection_struct *conn,int dosmode,const char *fname)
 {
   mode_t result = (S_IRUSR | S_IRGRP | S_IROTH);
+  mode_t dir_mode = 0; /* Mode of the parent directory if inheriting. */
 
   if ( !IS_DOS_READONLY(dosmode) )
     result |= (S_IWUSR | S_IWGRP | S_IWOTH);
+
+  if (fname && lp_inherit_perms(SNUM(conn))) {
+    char *dname;
+    SMB_STRUCT_STAT sbuf;
+
+    dname = parent_dirname(fname);
+    DEBUG(2,("unix_mode(%s) inheriting from %s\n",fname,dname));
+    if (dos_stat(dname,&sbuf) != 0) {
+      DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",fname,dname,strerror(errno)));
+      return(0);      /* *** shouldn't happen! *** */
+    }
+
+    /* Save for later - but explicitly remove setuid bit for safety. */
+    dir_mode = sbuf.st_mode & ~S_ISUID;
+    DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
+    /* Clear "result" */
+    result = 0;
+  } 
+
   if (IS_DOS_DIR(dosmode)) {
     /* We never make directories read only for the owner as under DOS a user
        can always create a file in a read-only directory. */
-    result |= (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR);
-    /* Apply directory mask */
-    result &= lp_dir_mask(SNUM(conn));
-    /* Add in force bits */
-    result |= lp_force_dir_mode(SNUM(conn));
+    result |= (S_IFDIR | S_IWUSR);
+
+    if (dir_mode) {
+      /* Inherit mode of parent directory. */
+      result |= dir_mode;
+    } else {
+      /* Provisionally add all 'x' bits */
+      result |= (S_IXUSR | S_IXGRP | S_IXOTH);                 
+
+      /* Apply directory mask */
+      result &= lp_dir_mask(SNUM(conn));
+      /* Add in force bits */
+      result |= lp_force_dir_mode(SNUM(conn));
+    }
   } else { 
     if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
       result |= S_IXUSR;
@@ -62,11 +97,17 @@ mode_t unix_mode(connection_struct *conn,int dosmode)
  
     if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
       result |= S_IXOTH;  
-    /* Apply mode mask */
-    result &= lp_create_mask(SNUM(conn));
-    /* Add in force bits */
-    result |= lp_force_create_mode(SNUM(conn));
+
+    if (dir_mode) {
+      /* Inherit 666 component of parent directory mode */
+      result |= dir_mode
+        &  (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
+    } else {
+      /* Apply mode mask */
+      result &= lp_create_mask(SNUM(conn));
+      /* Add in force bits */
+      result |= lp_force_create_mode(SNUM(conn));
+    }
   }
   return(result);
 }
@@ -155,7 +196,7 @@ int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *
 
   if (dos_mode(conn,fname,st) == dosmode) return(0);
 
-  unixmode = unix_mode(conn,dosmode);
+  unixmode = unix_mode(conn,dosmode,fname);
 
   /* preserve the s bits */
   mask |= (S_ISUID | S_ISGID);
index 9615c5ada25afb7ab68cb38ae4f8edb3624ff4ee..81536156e54e03de50848d2a1951de8929948f67 100644 (file)
@@ -726,7 +726,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
                return(UNIXERROR(ERRDOS,ERRnoaccess));
        } 
                
-       unixmode = unix_mode(conn,smb_attr | aARCH);
+       unixmode = unix_mode(conn,smb_attr | aARCH, fname);
     
        /* 
         * If it's a request for a directory open, deal with it separately.
@@ -1073,7 +1073,7 @@ static int call_nt_transact_create(connection_struct *conn,
       return(UNIXERROR(ERRDOS,ERRnoaccess));
     } 
   
-    unixmode = unix_mode(conn,smb_attr | aARCH);
+    unixmode = unix_mode(conn,smb_attr | aARCH, fname);
     
     /*
      * If it's a request for a directory open, deal with it separately.
@@ -1834,7 +1834,7 @@ static size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
        * ACE entries. These are the permissions a file would get when
        * being created in the directory.
        */
-      mode_t mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE);
+      mode_t mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name);
 
       owner_access = map_unix_perms(&owner_acl_type, mode,
                             S_IRUSR, S_IWUSR, S_IXUSR, fsp->is_directory);
index 88de1db151d4beaef094b6a49ee4a58278525369..ad208005a016282e75ec2fda116c63a47a91ec0e 100644 (file)
@@ -1147,7 +1147,7 @@ int open_directory(files_struct *fsp,connection_struct *conn,
                                return -1;
                        }
 
-                       if(dos_mkdir(fname, unix_mode(conn,aDIR)) < 0) {
+                       if(dos_mkdir(fname, unix_mode(conn,aDIR, fname)) < 0) {
                                DEBUG(0,("open_directory: unable to create %s. Error was %s\n",
                                         fname, strerror(errno) ));
                                return -1;
index 1e90ff4c4f1f074a65d125684b95ac29d46bdea2..d15a26b20ce2257192bdc51f359ee36876c3e2c4 100644 (file)
@@ -1547,7 +1547,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
  
-  unixmode = unix_mode(conn,aARCH);
+  unixmode = unix_mode(conn,aARCH,fname);
       
   open_file_shared(fsp,conn,fname,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
                    unixmode, oplock_request,&rmode,NULL);
@@ -1649,7 +1649,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
-  unixmode = unix_mode(conn,smb_attr | aARCH);
+  unixmode = unix_mode(conn,smb_attr | aARCH, fname);
       
   open_file_shared(fsp,conn,fname,smb_mode,smb_ofun,unixmode,
                       oplock_request, &rmode,&smb_action);
@@ -1773,7 +1773,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
       DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
     }
   
-  unixmode = unix_mode(conn,createmode);
+  unixmode = unix_mode(conn,createmode,fname);
   
   fsp = file_new();
   if (!fsp)
@@ -1853,7 +1853,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   pstrcat(fname,"/TMXXXXXX");
   unix_convert(fname,conn,0,&bad_path,NULL);
   
-  unixmode = unix_mode(conn,createmode);
+  unixmode = unix_mode(conn,createmode,fname);
   
   fsp = file_new();
   if (fsp)
@@ -3076,7 +3076,7 @@ int reply_printopen(connection_struct *conn,
 
        /* Open for exclusive use, write only. */
        open_file_shared(fsp,conn,fname2, SET_DENY_MODE(DENY_ALL)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
-                     (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL), unix_mode(conn,0), 0, NULL, NULL);
+                     (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL), unix_mode(conn,0,fname2), 0, NULL, NULL);
 
        if (!fsp->open) {
                file_free(fsp);
@@ -3235,7 +3235,7 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   unix_convert(directory,conn,0,&bad_path,NULL);
   
   if (check_name(directory, conn))
-    ret = dos_mkdir(directory,unix_mode(conn,aDIR));
+    ret = dos_mkdir(directory,unix_mode(conn,aDIR,directory));
   
   if (ret < 0)
   {
@@ -4291,7 +4291,12 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
   /* If any of the above locks failed, then we must unlock
      all of the previous locks (X/Open spec). */
   if(i != num_locks && num_locks != 0) {
-    for(; i >= 0; i--) {
+    /*
+     * Ensure we don't do a remove on the lock that just failed,
+     * as under POSIX rules, if we have a lock already there, we
+     * will delete it (and we shouldn't) .....
+     */
+    for(i--; i >= 0; i--) {
       count = get_lock_count( data, i, large_file_format, &err1);
       offset = get_lock_offset( data, i, large_file_format, &err2);
 
index 9811a9ff0116e2ada17838db174fc5be0dd5f7cc..896200059fc78a23f64a84334dbbe8e0a0a4afcc 100644 (file)
@@ -232,7 +232,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf,
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
-  unixmode = unix_mode(conn,open_attr | aARCH);
+  unixmode = unix_mode(conn,open_attr | aARCH, fname);
       
   open_file_shared(fsp,conn,fname,open_mode,open_ofun,unixmode,
                   oplock_request, &rmode,&smb_action);
@@ -2014,7 +2014,7 @@ static int call_trans2mkdir(connection_struct *conn,
 
   unix_convert(directory,conn,0,&bad_path,NULL);
   if (check_name(directory,conn))
-    ret = dos_mkdir(directory,unix_mode(conn,aDIR));
+    ret = dos_mkdir(directory,unix_mode(conn,aDIR,directory));
   
   if(ret < 0)
     {