Where to submit patches?

David Lee T.D.Lee at durham.ac.uk
Wed Aug 25 09:59:23 GMT 1999


On Wed, 25 Aug 1999, Jeremy Allison wrote:

> David Lee wrote:
> > 
> > 3. Allow UNIX file permissions of new files/directroies to be inherited
> >    from parent directory.  (Very un-UNIX-y, I know, for us techno-geeks,
> >    but an exceedingly useful and intuitive option for our user population
> >    which will soon number several thousand.)

Patch attached... (including smb.conf.5.yo documentation!).
Fuller writeup also attached ...

> Ok - this is an interesting one. I just had a long chat with
> Andrew about this at the O'Reilly Open Source conference in
> Monterey.
> 
> I'd like to throw out the following proposal to the group for
> discussion. Neither Andrew nor I like the idea of 'dot' meta
> files in directories to control this behaviour.

That had also been my first idea, including allowing dot files in
subdirectories which successively override parents.  But it felt far too
complicated (one of those gut feelings).  Also, what happens when the same
object is accessed via different routes, such as with symbolic links?

So I, too, went off the dot-file idea.

> Currently, setting the setgid bit on a directory causes the
> primary group to be inherited from the directory, not the
> owner. Our idea was to add (another:-) new parameter on a
> per-share basis :
> 
> "inherit permissions"
> 
> which would be a boolean with the following effect. If this
> is set on a share and the directory within which the file or
> directory is being created has the setgid bit set then the
> permissions of the file or directory are inherited from that
> of the directory.
> 
> This would allow feature to be used on a per-directory basis,
> and would also propagate into created directories.

Sounds very like my "inherit mode"!  (Had you seen its writeup??)
Briefly, if the share has "inherit mode" in smb.conf then:
1. files inherit read/write bits from the directory;
2. subdirectories inherit all bits;
3. the setgid bit has *no* samba-specific meaning; it is allowed to
   operate as per its host UNIX system.
Point (2) gives propagation into subdirectories.  Our proposals differ on
point (3).  Naturally, I prefer mine...

It has double virtues: (1) it was simple to implement (2) is intuitive to,
and easy to explain to, users.


--

:  David Lee                                I.T. Service          :
:  Systems Programmer                       Computer Centre       :
:                                           University of Durham  :
:  Phone:    +44 191 374 2882 (ddi)         South Road            :
:  Fax:      +44 191 374 7759               Durham                :
:  Internet: T.D.Lee at durham.ac.uk           U.K.                  :
-------------- next part --------------
*** docs/yodldocs/smb.conf.5.yo.orig	Sat May 15 02:20:48 1999
--- docs/yodldocs/smb.conf.5.yo	Thu May 20 10:07:58 1999
***************
*** 859,864 ****
--- 859,866 ----
  
  it() link(bf(include))(include)
  
+ it() link(bf(inherit mode))(inheritmode)
+ 
  it() link(bf(invalid users))(invalidusers)
  
  it() link(bf(locking))(locking)
***************
*** 2486,2491 ****
--- 2488,2526 ----
  It takes the standard substitutions, except link(bf(%u))(percentu),
  link(bf(%P))(percentP) and link(bf(%S))(percentS).
  
+ label(inheritmode)
+ dit(bf(inherit mode (S)))
+ 
+ The permissions on new files and directories are normally governed by
+ link(bf("create mask"))(createmask),
+ link(bf("directory mask"))(directorymask),
+ link(bf("force create mode"))(forcecreatemode) and
+ link(bf("force directory mode"))(forcedirectorymode)
+ but inherit mode overrides this.
+ 
+ New directories inherit the mode of the parent directory,
+ including bits such as setgid.
+ 
+ New files inherit their read/write bits from the parent directory.
+ Their execute bits continue to be determined by
+ link(bf("map archive"))(maparchive),
+ link(bf("map hidden"))(maphidden) and
+ link(bf("map system"))(mapsystem) as usual.
+ 
+ This can be particularly useful on large systems with many users,
+ perhaps several thousand,
+ to allow a single bf([homes]) share to be used flexibly by each user.
+ 
+ See the separate tt(INHERIT_MODE.txt) document.
+ 
+ See also link(bf("create mask"))(createmask) etc.
+ 
+   bf(Default)
+ tt(	inherit mode = no)
+ 
+   bf(Example)
+ tt(	inherit mode = yes)
+ 
  label(interfaces)
  dit(bf(interfaces (G)))
  
*** source/include/proto.h.orig	Tue May 18 00:27:59 1999
--- source/include/proto.h	Tue May 18 16:09:34 1999
***************
*** 1150,1155 ****
--- 1150,1156 ----
  BOOL lp_fake_dir_create_times(int );
  BOOL lp_blocking_locks(int );
  BOOL lp_mangle_locks(int );
+ BOOL lp_inherit_mode(int );
  int lp_create_mode(int );
  int lp_force_create_mode(int );
  int lp_dir_mode(int );
***************
*** 2364,2370 ****
  
  /*The following definitions come from  smbd/dosmode.c  */
  
! mode_t unix_mode(connection_struct *conn,int dosmode);
  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);
--- 2365,2371 ----
  
  /*The following definitions come from  smbd/dosmode.c  */
  
! mode_t unix_mode(connection_struct *conn,int dosmode,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);
*** source/param/loadparm.c.orig	Tue May 18 00:37:43 1999
--- source/param/loadparm.c	Tue May 18 16:09:35 1999
***************
*** 339,345 ****
    BOOL bFakeDirCreateTimes;
    BOOL bBlockingLocks;
    BOOL bMangleLocks;
!   char dummy[3]; /* for alignment */
  } service;
  
  
--- 339,346 ----
    BOOL bFakeDirCreateTimes;
    BOOL bBlockingLocks;
    BOOL bMangleLocks;
!   BOOL bInheritMode;
!   char dummy[2]; /* for alignment */
  } service;
  
  
***************
*** 434,439 ****
--- 435,441 ----
    False, /* bFakeDirCreateTimes */
    True,  /* bBlockingLocks */
    True,  /* bMangleLocks */
+   False, /* bInheritMode */
    ""     /* dummy */
  };
  
***************
*** 740,745 ****
--- 742,748 ----
  
    {"Locking Options", P_SEP, P_SEPARATOR},
    {"blocking locks",   P_BOOL,    P_LOCAL,  &sDefault.bBlockingLocks,    NULL,   NULL,  FLAG_SHARE|FLAG_GLOBAL},
+   {"inherit mode",     P_BOOL,    P_LOCAL,  &sDefault.bInheritMode,     NULL,   NULL,  FLAG_SHARE},
    {"fake oplocks",     P_BOOL,    P_LOCAL,  &sDefault.bFakeOplocks,     NULL,   NULL,  FLAG_SHARE},
    {"kernel oplocks",   P_BOOL,    P_GLOBAL, &Globals.bKernelOplocks,    NULL,   NULL,  FLAG_GLOBAL},
    {"locking",          P_BOOL,    P_LOCAL,  &sDefault.bLocking,         NULL,   NULL,  FLAG_SHARE|FLAG_GLOBAL},
***************
*** 1334,1339 ****
--- 1337,1343 ----
  FN_LOCAL_BOOL(lp_fake_dir_create_times,bFakeDirCreateTimes)
  FN_LOCAL_BOOL(lp_blocking_locks,bBlockingLocks)
  FN_LOCAL_BOOL(lp_mangle_locks,bMangleLocks)
+ FN_LOCAL_BOOL(lp_inherit_mode,bInheritMode)
  
  FN_LOCAL_INTEGER(lp_create_mode,iCreate_mask)
  FN_LOCAL_INTEGER(lp_force_create_mode,iCreate_force_mode)
*** source/smbd/dosmode.c.orig	Sat Feb 27 22:09:09 1999
--- source/smbd/dosmode.c	Tue May 18 16:09:36 1999
***************
*** 23,58 ****
  
  extern int DEBUGLEVEL;
  
  /****************************************************************************
    change a dos mode to a unix mode
      base permission for files:
!          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.
      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.
  ****************************************************************************/
! mode_t unix_mode(connection_struct *conn,int dosmode)
  {
    mode_t result = (S_IRUSR | S_IRGRP | S_IROTH);
  
    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
         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_mode(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;
--- 23,122 ----
  
  extern int DEBUGLEVEL;
  
+ /*******************************************************************
+ 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.
+ *******************************************************************/
+ /*******************************************************************
+ This should probably be elsewhere, and more generally available.
+ *******************************************************************/
+ static char *parent_dirname(char *path)
+ {
+   static char dirpath[MAXPATHLEN + 1];
+   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);
+ }
+ 
  /****************************************************************************
    change a dos mode to a unix mode
      base permission for files:
!          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
!          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
!          if !inheriting {
!            Then apply create mask,
!            then add force bits.
!          }
  ****************************************************************************/
! mode_t unix_mode(connection_struct *conn,int dosmode,char *fname)
  {
    mode_t result = (S_IRUSR | S_IRGRP | S_IROTH);
+   mode_t dir_mode;
  
    if ( !IS_DOS_READONLY(dosmode) )
      result |= (S_IWUSR | S_IWGRP | S_IWOTH);
+ 
+   if (lp_inherit_mode(SNUM(conn))) {
+     char *dname;
+     SMB_STRUCT_STAT sbuf;
+ 
+     dname = parent_dirname(dos_to_unix(fname, False));
+     DEBUG(2,("unix_mode(%s) inheriting from %s\n",fname,dname));
+     if (sys_stat(dname,&sbuf) != 0) {
+       DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",fname,dname,strerror(errno)));
+       return(0);	/* *** shouldn't happen! *** */
+     }
+     /* Save 777 part for later */
+     /* dir_mode = sbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); */
+     /* Save for later */
+     dir_mode = sbuf.st_mode;
+     DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,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_IWUSR);
!  
!     if (lp_inherit_mode(SNUM(conn))) {
!       /* 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_mode(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;
***************
*** 63,72 ****
      if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
        result |= S_IXOTH;  
   
!     /* Apply mode mask */
!     result &= lp_create_mode(SNUM(conn));
!     /* Add in force bits */
!     result |= lp_force_create_mode(SNUM(conn));
    }
    return(result);
  }
--- 127,142 ----
      if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
        result |= S_IXOTH;  
   
!     if (lp_inherit_mode(SNUM(conn))) {
!       /* 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_mode(SNUM(conn));
!       /* Add in force bits */
!       result |= lp_force_create_mode(SNUM(conn));
!     }
    }
    return(result);
  }
***************
*** 155,161 ****
  
    if (dos_mode(conn,fname,st) == dosmode) return(0);
  
!   unixmode = unix_mode(conn,dosmode);
  
    /* preserve the s bits */
    mask |= (S_ISUID | S_ISGID);
--- 225,231 ----
  
    if (dos_mode(conn,fname,st) == dosmode) return(0);
  
!   unixmode = unix_mode(conn,dosmode,fname);
  
    /* preserve the s bits */
    mask |= (S_ISUID | S_ISGID);
*** source/smbd/nttrans.c.orig	Sat May 15 02:06:39 1999
--- source/smbd/nttrans.c	Wed May 19 15:30:43 1999
***************
*** 722,728 ****
  		return(UNIXERROR(ERRDOS,ERRnoaccess));
  	} 
  		
! 	unixmode = unix_mode(conn,smb_attr | aARCH);
      
  	/* 
  	 * If it's a request for a directory open, deal with it separately.
--- 722,728 ----
  		return(UNIXERROR(ERRDOS,ERRnoaccess));
  	} 
  		
! 	unixmode = unix_mode(conn,smb_attr | aARCH, fname);
      
  	/* 
  	 * If it's a request for a directory open, deal with it separately.
***************
*** 1061,1067 ****
        return(UNIXERROR(ERRDOS,ERRnoaccess));
      } 
    
!     unixmode = unix_mode(conn,smb_attr | aARCH);
      
      /*
       * If it's a request for a directory open, deal with it separately.
--- 1061,1067 ----
        return(UNIXERROR(ERRDOS,ERRnoaccess));
      } 
    
!     unixmode = unix_mode(conn,smb_attr | aARCH, fname);
      
      /*
       * If it's a request for a directory open, deal with it separately.
***************
*** 1715,1720 ****
--- 1715,1721 ----
    SEC_ACCESS other_access;
    int other_acl_type;
    int num_acls = 0;
+   pstring fname;
   
    *ppdesc = NULL;
  
***************
*** 1771,1777 ****
         * 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);
  
        owner_access = map_unix_perms(&owner_acl_type, mode,
                              S_IRUSR, S_IWUSR, S_IXUSR, fsp->is_directory);
--- 1772,1785 ----
         * ACE entries. These are the permissions a file would get when
         * being created in the directory.
         */
!       mode_t mode;
! 	/* 
! 	 * For fname arg to unix_mode(), use dirname with trailing "/" so that,
! 	 * under "inherit mode", it uses this directory rather than parent.
! 	 */
!       pstrcpy(fname, fsp->fsp_name);
!       pstrcat(fname, "/");
!       mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fname);
  
        owner_access = map_unix_perms(&owner_acl_type, mode,
                              S_IRUSR, S_IWUSR, S_IXUSR, fsp->is_directory);
*** source/smbd/open.c.orig	Sat May 15 02:06:39 1999
--- source/smbd/open.c	Tue May 18 16:09:37 1999
***************
*** 1136,1142 ****
  		 * Create the directory.
  		 */
  
! 		if(dos_mkdir(fname, unix_mode(conn,aDIR)) < 0) {
  			DEBUG(0,("open_directory: unable to create %s. Error was %s\n",
  				 fname, strerror(errno) ));
  			return -1;
--- 1136,1142 ----
  		 * Create the directory.
  		 */
  
! 		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;
*** source/smbd/reply.c.orig	Sat May 15 02:06:40 1999
--- source/smbd/reply.c	Tue May 18 16:09:38 1999
***************
*** 1459,1465 ****
      return(UNIXERROR(ERRDOS,ERRnoaccess));
    }
   
!   unixmode = unix_mode(conn,aARCH);
        
    open_file_shared(fsp,conn,fname,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
                     unixmode, oplock_request,&rmode,NULL);
--- 1459,1465 ----
      return(UNIXERROR(ERRDOS,ERRnoaccess));
    }
   
!   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);
***************
*** 1561,1567 ****
      return(UNIXERROR(ERRDOS,ERRnoaccess));
    }
  
!   unixmode = unix_mode(conn,smb_attr | aARCH);
        
    open_file_shared(fsp,conn,fname,smb_mode,smb_ofun,unixmode,
  	               oplock_request, &rmode,&smb_action);
--- 1561,1567 ----
      return(UNIXERROR(ERRDOS,ERRnoaccess));
    }
  
!   unixmode = unix_mode(conn,smb_attr | aARCH, fname);
        
    open_file_shared(fsp,conn,fname,smb_mode,smb_ofun,unixmode,
  	               oplock_request, &rmode,&smb_action);
***************
*** 1685,1691 ****
        DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
      }
    
!   unixmode = unix_mode(conn,createmode);
    
    fsp = file_new();
    if (!fsp)
--- 1685,1691 ----
        DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
      }
    
!   unixmode = unix_mode(conn,createmode,fname);
    
    fsp = file_new();
    if (!fsp)
***************
*** 1765,1771 ****
    pstrcat(fname,"/TMXXXXXX");
    unix_convert(fname,conn,0,&bad_path,NULL);
    
!   unixmode = unix_mode(conn,createmode);
    
    fsp = file_new();
    if (fsp)
--- 1765,1771 ----
    pstrcat(fname,"/TMXXXXXX");
    unix_convert(fname,conn,0,&bad_path,NULL);
    
!   unixmode = unix_mode(conn,createmode,fname);
    
    fsp = file_new();
    if (fsp)
***************
*** 2986,2992 ****
  
  	/* 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);
  
  	if (!fsp->open) {
  		file_free(fsp);
--- 2986,2992 ----
  
  	/* 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,fname2), 0, NULL, NULL);
  
  	if (!fsp->open) {
  		file_free(fsp);
***************
*** 3145,3151 ****
    unix_convert(directory,conn,0,&bad_path,NULL);
    
    if (check_name(directory, conn))
!     ret = dos_mkdir(directory,unix_mode(conn,aDIR));
    
    if (ret < 0)
    {
--- 3145,3151 ----
    unix_convert(directory,conn,0,&bad_path,NULL);
    
    if (check_name(directory, conn))
!     ret = dos_mkdir(directory,unix_mode(conn,aDIR,directory));
    
    if (ret < 0)
    {
*** source/smbd/trans2.c.orig	Sat May 15 02:06:40 1999
--- source/smbd/trans2.c	Tue May 18 16:09:38 1999
***************
*** 232,238 ****
      return(UNIXERROR(ERRDOS,ERRnoaccess));
    }
  
!   unixmode = unix_mode(conn,open_attr | aARCH);
        
    open_file_shared(fsp,conn,fname,open_mode,open_ofun,unixmode,
  		   oplock_request, &rmode,&smb_action);
--- 232,238 ----
      return(UNIXERROR(ERRDOS,ERRnoaccess));
    }
  
!   unixmode = unix_mode(conn,open_attr | aARCH, fname);
        
    open_file_shared(fsp,conn,fname,open_mode,open_ofun,unixmode,
  		   oplock_request, &rmode,&smb_action);
***************
*** 1962,1968 ****
  
    unix_convert(directory,conn,0,&bad_path,NULL);
    if (check_name(directory,conn))
!     ret = dos_mkdir(directory,unix_mode(conn,aDIR));
    
    if(ret < 0)
      {
--- 1962,1968 ----
  
    unix_convert(directory,conn,0,&bad_path,NULL);
    if (check_name(directory,conn))
!     ret = dos_mkdir(directory,unix_mode(conn,aDIR,directory));
    
    if(ret < 0)
      {
-------------- next part --------------
File ownerships and permissions in SAMBA 2.x
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SAMBA is a very useful product for serving files to the PC desktop
from a UNIX filserver.

But in a large environment (thousands of identifiers and groups) its
filesharing abilities are insufficiently flexible.  While much of this is
inherent in the SMB protocol, nevertheless more could be done.  This paper
suggests some extensions.


Disclaimer
~~~~~~~~~~

My knowledge of PCs is miniscule, and my knowledge of SMB even smaller.
So there may well be detailed inaccuracies in this paper.  Please
read it, in the first instance, for the principles.


Starting point
~~~~~~~~~~~~~~

A large system, many thousand users, many hundred UNIX groups.

Privacy of data is important.  The default umask will be something like 077
rather than 022.  But user-controlled filesharing is also important, using
UNIX permissions and UNIX groups.

Desktop primarily PC, but some UNIX.

Integrated PC/UNIX filestore, particularly a "home directory" per user.

Any solution must be general, with relatively little done centrally,
relatively much devolved to user.  For example "smb.conf(5)" has a simple
"[homes]" share, covering all users;  little more than a default configuration.

It is grossly impractical to be tailoring the generic smb.conf (a centralised
item) with per-user information.  Besides, that would be insufficient for
general filesharing amongst consenting users which requires even finer-grained
per-directory control.


The problem
~~~~~~~~~~~

A user carefully sets permissions on a particular file (and its ancestor
directories) to allow sharing to a specified group.  Using a typical Windows
application (WORD, Excel) to edit that file results in obliteration of those
owner/mode details.  This is a "fact of life" with such applications.

A partial solution is to open up the default umask from 077 (private) to
something like 027 (group access) and use the UNIX "g+s" semantics on the
directory.  But this is a global sledgehammer solution to a problem that
requires much finer-grained control, at least per-user and preferably
per-directory or even per-file.

Because of the way Windows applications work, I think we have to accept that
per-file control is unrealistic.  But per-directory control would still be
very beneficial.


The proposal
~~~~~~~~~~~~

It is proposed to extend samba in an upwards compatible manner to allow
per-user and per-directory setting of owner/mode information on directories
and thence to files in these directories.

UNIX aficionados will be aware of mechanisms such as .login and .profile
to allow users to tailor their working environment, such as umask settings.
They may also be aware of analogous mechanisms on a per-directory level
(such as ".nsr" used by the Legato NetWorker backup product).

It is suggested that samba recognise and act on such a file to allow
user-controlled owner/mode tailoring.  Its processing and interpretation
would be modelled after the existing smb.conf "include .../%u/.../<file>".

This is hereinafter called the "dirinclude" file: the reasons will become
apparent.  Such a file may be placed in any directory within a "[homes]"
share.  It might be more generally useful, but I have not explored that.

The file contains a subset of "smb.conf" instructions, such as:
   create mask        (and create mode)
   directory mask     (and directory mode)
   force create mode  (and force directory mode)
   force group

Other instructions may well be useful:
   delete readonly
   dont descend
   dos filetime resolution
   oplocks

The above lists are by no means exhaustive.

Backwards-compatibility principles probably require the default to be "off".
It is suggested that the main "smb.conf" file contain a global switch
for this feature, such as "dirinclude <filename-template>".  When given,
it switches on this feature.  In each directory it looks for a filename
matching the template (e.g. "samba.smb") and, if found, processes it.

The effects in one directory are inherited by all subdirectories, but can
be further modified by such files in those subdirectories.


Caveats
~~~~~~~

Creation of, change to, and deletion of, the "dirinclude" files need to be
detected and acted upon.  Detection is very easy and painless:  a UNIX "stat"
is done by the "smbd" daemon on the "dirinclude" files themselves prior to
doing a significant operation.  Each stat result is cached:  if it has changed
(and 99.9% of the time it won't) then the file can be reprocessed.


David Lee
T.D.Lee at durham.ac.uk
March 1999


More information about the samba-technical mailing list