Mike808
2000-Dec-08 21:58 UTC
unix chmod not following NTFS/FAT attrib operation [w/patch]
I think I posted from work on the problems I've been having using groups and Samba. It appears that Samba follows unix operation when performing chmod's on a file. Whereas, on a real FAT WinXX host, any user can perform run attrib.exe and change the file's attributes. Not so in Samba-land. On an NTFS host, you need "ChangePermissions" access rights to do this. But, Samba only maps the usual RWHAS attributes. I'll give a quick synopsis of the problem, followed by patch diffs that I think really close this hole in Samba functionality. Scenario: Programmer "abe" and Programmer "bob", both in Group "web" use a Samba share configured as follows: # everybody's in the web group. force group = web # -rw-rw-r-- (allow group write access) force create mode = 0664 # drwxrwsr-x (set-guid on directories) force directory mode = 2775 "abe" creates a file, checks it into VSS (Microsoft's Visual Source Safe). VSS tells Samba to make the file read-only. Since "abe" owns the file, the chmod succeeds. "bob" tries to checkout the file in VSS to edit it. VSS tells Samba to make the file add write permissions. Since "abe" owns the file, but "bob" is the user issuing the chmod, it fails. This doesn't happen with NTFS when the users have "ChangePermissions" access. This doesn't happen with FAT when users use "attrib.exe" to alter permissions. As promised, here's the patches (after a short explanation of the approach). I could have just wired dosmode.c: file_chmod() to go become_root(), but thought that this might be an option the Samba administrator would want to control, like the DOS/Posix file timestamp behavior flag. So, I hacked in a new BOOL bDosChmod option to control this. If FALSE, unix chmod behavior occurs, and only the owner of the file may alter the permissions of the file (notably read/write). If TRUE, my idea of reasonable DOS behavior occurs, which is similar to the filestamp behavior. i.e. 1) you must have write access to the share 2) you are a share administrative user 3) *OR* you are the owner of the file 4) *OR* you are a member of the same group as the file 5) *OR* the file has world-writable permissions. I note that #5 creates a situation whereby you can "lock yourself out" of write permissions if you aren't #2 or #3 or #4, and you use the file's world-writable status to make the file read-only. I can't fix that without making the checks meaningless and letting anybody change anything they want to. Will someone please verify the alignment being adjusted downward by 1 for alignment after adding a new BOOL to the structure? And now the patches: $ diff -c loadparm.c.orig loadparm.c *** loadparm.c.orig Tue Apr 25 18:07:00 2000 --- loadparm.c Wed Dec 6 17:53:27 2000 *************** *** 362,368 **** BOOL bFakeDirCreateTimes; BOOL bBlockingLocks; BOOL bInheritPerms; ! char dummy[3]; /* for alignment */ } service; --- 362,369 ---- BOOL bFakeDirCreateTimes; BOOL bBlockingLocks; BOOL bInheritPerms; ! BOOL bDosChmod; ! char dummy[2]; /* for alignment */ } service; *************** *** 468,473 **** --- 469,475 ---- False, /* bFakeDirCreateTimes */ True, /* bBlockingLocks */ False, /* bInheritPerms */ + False, /* bDosChmod */ "" /* dummy */ }; *************** *** 863,868 **** --- 865,871 ---- {"delete readonly", P_BOOL, P_LOCAL, &sDefault.bDeleteReadonly, 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}, + {"dos chmod", P_BOOL, P_LOCAL, &sDefault.bDosChmod, NULL, NULL, FLAG_SHARE|FLAG_GLOBAL}, {"fake directory create times", P_BOOL,P_LOCAL, &sDefault.bFakeDirCreateTim es, NULL, NULL, FLAG_SHARE|FLAG_GLOBAL}, {"panic action", P_STRING, P_GLOBAL, &Globals.szPanicAction, NULL, NULL, 0}, *************** *** 1406,1411 **** --- 1409,1415 ---- 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_BOOL(lp_dos_chmod,bDosChmod) FN_LOCAL_INTEGER(lp_create_mask,iCreate_mask) FN_LOCAL_INTEGER(lp_force_create_mode,iCreate_force_mode) --------------------------------------------- $ diff -b -c dosmode.c.orig dosmode.c | more *** dosmode.c.orig Tue Apr 25 18:07:10 2000 --- dosmode.c Wed Dec 6 17:32:39 2000 *************** *** 182,191 **** --- 182,193 ---- ********************************************************************/ int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *st) { + 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; *************** *** 225,231 **** --- 227,262 ---- unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)); } + + /* Normal unix chmod semantics */ + if(!lp_dos_chmod(SNUM(conn))) return(dos_chmod(fname,unixmode)); + + /* We have permission (given by the Samba admin) to + break unix chmod semantics and allow a user to change + the permissions on a file they don't own. + (As DOS does and as NT does with ChangePermissions access). + */ + + /* Check if we have write access to the share */ + if (!CAN_WRITE(conn)) return -1; + + if ( + + (st->st_mode & S_IWOTH) || /* the file is world writable */ + conn->admin_user || /* we are an admin user */ + (current_user.uid == st->st_uid) || /* we are the owner */ + /* we are in the same group as the file */ + in_group( + st->st_gid, current_user.gid, current_user.ngroups, current_user.groups + ) + ) { + /* We are allowed to become root and change the permissions. */ + become_root(False); + ret = dos_chmod(fname,unixmode); + unbecome_root(False); + } + return(ret); } --------------------------------------------- I'll see what I can do for adding it into SWAT, the documentation, the example smb.conf, and the smb.conf man pages, but I think I've done the hard part. Is there some other way I should submit these patches? mike808/ -- perl -e "print pack\"H*\",\"596f752063616e277420666978207374757069642e\""