ATTRIB.EXE +r doesn't work when inheriting permissions

Buck Huppmann cjh at frb.gov
Fri Feb 1 12:44:04 GMT 2002


I'm still unclear on how ``inherit permissions'' is supposed to work, but
i'd think that it wouldn't contravene an explicit user request to make a
file read-only (or change the permissions on an existing file just b/c a
user writes to it, as previously lamented in
http://lists.samba.org/pipermail/samba-technical/2001-December/033396.html
). This would seemingly be ``force [directory] security mode'''s job

So i can't make a file read-only via the NT explorer ``General'' property
sheet check box or the ATTRIB.EXE command, although using the ACL-tweak-
ing interface allows me to override inherited writability just fine. The
problem seems to be that smbd/dosmode.c:file_chmod() calls :unix_mode()
with an IS_DOS_READONLY(dosmode) but gets back a mode that's writable if
the parent's mode is. I guess the easiest ``fix'', if you consider this a
bug, is as follows

--- patch ---

--- samba-2.2.2/source/smbd/dosmode.c.orig	Fri Apr 13 19:24:46 2001
+++ samba-2.2.2/source/smbd/dosmode.c	Fri Feb  1 15:08:18 2002
@@ -47,12 +47,9 @@
 ****************************************************************************/
 mode_t unix_mode(connection_struct *conn,int dosmode,const char *fname)
 {
-  mode_t result = (S_IRUSR | S_IRGRP | S_IROTH);
+  mode_t result;
   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;
@@ -67,9 +64,22 @@
     /* 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;
+    /* initialize result with parent mode as template */
+    result = dir_mode;
+    /* for files, the only bits we inherit are the rw's */
+    if (!IS_DOS_DIR(dosmode))
+      result &= S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH;
   } 
+  else {
+    /* initialize result with rw-rw-rw- as template. all -x bits are
+     * picked up below, both for directories and for file x-bit hacks */
+    result = S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH;
+  }
+
+  /* if the user asks for read-only, give her/him read-only (subject to
+   * any force_..._mode()'s applied later) */
+  if (IS_DOS_READONLY(dosmode))
+    result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
 
   if (IS_DOS_DIR(dosmode)) {
     /* We never make directories read only for the owner as under DOS a user
@@ -77,8 +87,7 @@
     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);                 
@@ -99,9 +108,7 @@
       result |= S_IXOTH;  
 
     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));
@@ -228,9 +235,17 @@
 		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 the new mode is not aRONLY, reset write bits (presumably
+	 * including owner-write, but maybe not) per the config IFF the
+	 * current UNIX mode doesn't already grant owner write access.
+	 * this is the conservative heuristic for not resetting write bits
+	 * on files if we're called and the desired change is only from
+	 * non-archive to archive, say, and not a change in writability,
+	 * as it accords with dos_mode()'s mapping of S_IWUSR to DOS
+	 * ~aRONLY, at present */
 	if (!IS_DOS_READONLY(dosmode)) {
+		if (st->st_mode & S_IWUSR)
+			unixmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
 		unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
 	}

--- end of patch ---

The last hunk is my previously proffered patch from the above-referenced
message. More prudent might be to separate out the initial-permission-set-
ting aspect of file_chmod() from the, well, changing aspect, somewhat as
follows, but you're probably not going to do this

At any rate, best of luck to 2.2.3, and keep up the good work

--buck

/* chmod() for the times you want to set the mode */
int file_initmod(...)
{
	/* old file_chmod() */
}

/* chmod() for the times you only want to change some mappings */
int file_altermod(...)
{
	mode_t mask = 0, unixmode;
	int dosmode_diff;
	if (!st) { ... }
	dosmode_diff = dosmode ^ dos_mode(...);
	if (!dosmode_diff)
		return 0;
	if (IS_DOS_DIR(dosmode_diff))
		drop_dead_laughing();
	/* we don't touch any r bits, since that doesn't correspond
	 * to any change of a DOS attribute */
	if (IS_DOS_READONLY(dosmode_diff))
		mask |= S_IWUSR | S_IWGRP | S_IWOTH;
	if (MAP_ARCHIVE(conn) && IS_DOS_ARCHIVE(dosmode_diff))
		mask |= S_IXUSR;
	if (MAP_SYSTEM(conn) && IS_DOS_SYSTEM(dosmode_diff))
		mask |= S_IXGRP;
	if (MAP_SYSTEM(conn) && IS_DOS_HIDDEN(dosmode_diff))
		mask |= S_IXOTH;
	/* any more ? */
	unixmode = st->st_mode & ~mask | unix_mode(...) & mask;

	/* actual chmod(), perhaps calling into a common sub factored out
	   from the original file_chmod() */
}




More information about the samba-technical mailing list