Fix from "B.V.Dean" <B.V.Dean@ukc.ac.uk> to add "dos filemode" parameter
authorJeremy Allison <jra@samba.org>
Tue, 9 Jan 2001 20:34:37 +0000 (20:34 +0000)
committerJeremy Allison <jra@samba.org>
Tue, 9 Jan 2001 20:34:37 +0000 (20:34 +0000)
to allow a chmod to be done if the user has write access to a file, just
like Windows allows. Off by default (compare with "dos filetimes" parameter).
Jeremy.
(This used to be commit 8abdf0e29fdb02a7929aa4395947b5023a7194a0)

source3/include/proto.h
source3/param/loadparm.c
source3/smbd/dosmode.c

index 8c0ff6f86cbd777af2c41f06c0c2e1ddfff06c5c..9cd9296c413c128afd6cf5c47b70429b418e1042 100644 (file)
@@ -1609,6 +1609,7 @@ BOOL lp_map_system(int );
 BOOL lp_delete_readonly(int );
 BOOL lp_fake_oplocks(int );
 BOOL lp_recursive_veto_delete(int );
+BOOL lp_dos_filemode(int );
 BOOL lp_dos_filetimes(int );
 BOOL lp_dos_filetime_resolution(int );
 BOOL lp_fake_dir_create_times(int );
index d5a032c26bec956b34669fbc50ca5ce53d7a1a8d..716511cb8b71ce88fbb2f4bdf9d3116dc8aaf087 100644 (file)
@@ -375,6 +375,7 @@ typedef struct
        BOOL bDeleteReadonly;
        BOOL bFakeOplocks;
        BOOL bDeleteVetoFiles;
+       BOOL bDosFilemode;
        BOOL bDosFiletimes;
        BOOL bDosFiletimeResolution;
        BOOL bFakeDirCreateTimes;
@@ -489,6 +490,7 @@ static service sDefault = {
        False,                  /* bDeleteReadonly */
        False,                  /* bFakeOplocks */
        False,                  /* bDeleteVetoFiles */
+       False,                  /* bDosFilemode */
        False,                  /* bDosFiletimes */
        False,                  /* bDosFiletimeResolution */
        False,                  /* bFakeDirCreateTimes */
@@ -984,6 +986,7 @@ static struct parm_struct parm_table[] = {
        {"magic script", P_STRING, P_LOCAL, &sDefault.szMagicScript, NULL, NULL, FLAG_SHARE},
        {"magic output", P_STRING, P_LOCAL, &sDefault.szMagicOutput, NULL, NULL, FLAG_SHARE},
        {"delete readonly", P_BOOL, P_LOCAL, &sDefault.bDeleteReadonly, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
+       {"dos filemode", P_BOOL, P_LOCAL, &sDefault.bDosFilemode, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
        {"dos filetimes", P_BOOL, P_LOCAL, &sDefault.bDosFiletimes, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
        {"dos filetime resolution", P_BOOL, P_LOCAL, &sDefault.bDosFiletimeResolution, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL},
 
@@ -1603,6 +1606,7 @@ FN_LOCAL_BOOL(lp_map_system, bMap_system)
 FN_LOCAL_BOOL(lp_delete_readonly, bDeleteReadonly)
 FN_LOCAL_BOOL(lp_fake_oplocks, bFakeOplocks)
 FN_LOCAL_BOOL(lp_recursive_veto_delete, bDeleteVetoFiles)
+FN_LOCAL_BOOL(lp_dos_filemode, bDosFilemode)
 FN_LOCAL_BOOL(lp_dos_filetimes, bDosFiletimes)
 FN_LOCAL_BOOL(lp_dos_filetime_resolution, bDosFiletimeResolution)
 FN_LOCAL_BOOL(lp_fake_dir_create_times, bFakeDirCreateTimes)
index 377cfbb7cfdee4ce21f30b261fdd09cc121853a5..89e7c6b766de25fcbd746fe806b58557b7482567 100644 (file)
@@ -184,50 +184,84 @@ chmod a file - but preserve some bits
 ********************************************************************/
 int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *st)
 {
-  SMB_STRUCT_STAT st1;
-  int mask=0;
-  mode_t tmp;
-  mode_t unixmode;
-
-  if (!st) {
-    st = &st1;
-    if (vfs_stat(conn,fname,st)) return(-1);
-  }
+       extern struct current_user current_user;
+       SMB_STRUCT_STAT st1;
+       int mask=0;
+       mode_t tmp;
+       mode_t unixmode;
+       int ret = -1;
+
+       if (!st) {
+               st = &st1;
+               if (vfs_stat(conn,fname,st))
+                       return(-1);
+       }
 
-  if (S_ISDIR(st->st_mode)) dosmode |= aDIR;
+       if (S_ISDIR(st->st_mode))
+               dosmode |= aDIR;
 
-  if (dos_mode(conn,fname,st) == dosmode) return(0);
+       if (dos_mode(conn,fname,st) == dosmode)
+               return(0);
 
-  unixmode = unix_mode(conn,dosmode,fname);
+       unixmode = unix_mode(conn,dosmode,fname);
 
-  /* preserve the s bits */
-  mask |= (S_ISUID | S_ISGID);
+       /* preserve the s bits */
+       mask |= (S_ISUID | S_ISGID);
 
-  /* preserve the t bit */
+       /* preserve the t bit */
 #ifdef S_ISVTX
-  mask |= S_ISVTX;
+       mask |= S_ISVTX;
 #endif
 
-  /* possibly preserve the x bits */
-  if (!MAP_ARCHIVE(conn)) mask |= S_IXUSR;
-  if (!MAP_SYSTEM(conn)) mask |= S_IXGRP;
-  if (!MAP_HIDDEN(conn)) mask |= S_IXOTH;
-
-  unixmode |= (st->st_mode & mask);
-
-  /* if we previously had any r bits set then leave them alone */
-  if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
-    unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
-    unixmode |= tmp;
-  }
-
-  /* if we previously had any w bits set then leave them alone 
-   whilst adding in the new w bits, if the new mode is not rdonly */
-  if (!IS_DOS_READONLY(dosmode)) {
-    unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
-  }
-
-  return(vfs_chmod(conn,fname,unixmode));
+       /* possibly preserve the x bits */
+       if (!MAP_ARCHIVE(conn))
+               mask |= S_IXUSR;
+       if (!MAP_SYSTEM(conn))
+               mask |= S_IXGRP;
+       if (!MAP_HIDDEN(conn))
+               mask |= S_IXOTH;
+
+       unixmode |= (st->st_mode & mask);
+
+       /* if we previously had any r bits set then leave them alone */
+       if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
+               unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
+               unixmode |= tmp;
+       }
+
+       /* if we previously had any w bits set then leave them alone 
+               whilst adding in the new w bits, if the new mode is not rdonly */
+       if (!IS_DOS_READONLY(dosmode)) {
+               unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
+       }
+
+       ret = vfs_chmod(conn,fname,unixmode);
+
+       if((errno != EPERM) && (errno != EACCES))
+               return -1;
+
+       if(!lp_dos_filemode(SNUM(conn)))
+               return -1;
+
+       /* We want DOS semantics, ie allow non owner with write permission to change the
+               bits on a file. Just like file_utime below.
+       */
+
+       /* Check if we have write access. */
+       if (CAN_WRITE(conn)) {
+               if (((st->st_mode & S_IWOTH) ||
+                               conn->admin_user ||
+                               ((st->st_mode & S_IWUSR) && current_user.uid==st->st_uid) ||
+                               ((st->st_mode & S_IWGRP) &&
+                               in_group(st->st_gid,current_user.gid, current_user.ngroups,current_user.groups)))) {
+                                       /* We are allowed to become root and change the file mode. */
+                                       become_root();
+                                       ret = vfs_chmod(conn,fname,unixmode);
+                                       unbecome_root();
+               }
+       }
+
+       return( ret );
 }