Fixed locking bug found by Andrew.
Jeremy.
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 */
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 );
/*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);
#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
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;
+}
BOOL bDosFiletimeResolution;
BOOL bFakeDirCreateTimes;
BOOL bBlockingLocks;
+ BOOL bInheritPerms;
char dummy[3]; /* for alignment */
} service;
False, /* bDosFiletimeResolution */
False, /* bFakeDirCreateTimes */
True, /* bBlockingLocks */
+ False, /* bInheritPerms */
"" /* dummy */
};
{"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},
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)
* 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;
/****************************************************************************
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;
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);
}
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);
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.
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.
* 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);
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;
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);
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);
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)
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)
/* 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);
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)
{
/* 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);
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);
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)
{