summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h4
-rw-r--r--source3/lib/interfaces.c3
-rw-r--r--source3/lib/util.c28
-rw-r--r--source3/param/loadparm.c4
-rw-r--r--source3/smbd/blocking.c8
-rw-r--r--source3/smbd/dosmode.c77
-rw-r--r--source3/smbd/nttrans.c6
-rw-r--r--source3/smbd/open.c2
-rw-r--r--source3/smbd/reply.c19
-rw-r--r--source3/smbd/trans2.c4
10 files changed, 122 insertions, 33 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index e2d6c2e5d4..c3bbb505a2 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -347,6 +347,7 @@ char *smbd_mktemp(char *template);
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 */
@@ -1336,6 +1337,7 @@ BOOL lp_dos_filetimes(int );
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 );
@@ -2612,7 +2614,7 @@ void DirCacheFlush(int snum);
/*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);
diff --git a/source3/lib/interfaces.c b/source3/lib/interfaces.c
index 29181c394a..e7b9efa1f0 100644
--- a/source3/lib/interfaces.c
+++ b/source3/lib/interfaces.c
@@ -39,6 +39,9 @@
#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
diff --git a/source3/lib/util.c b/source3/lib/util.c
index a39dc1a516..001baa0e3e 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -3280,3 +3280,31 @@ char *lock_path(char *name)
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;
+}
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 3ac6d78f04..eb981fb5d2 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -357,6 +357,7 @@ typedef struct
BOOL bDosFiletimeResolution;
BOOL bFakeDirCreateTimes;
BOOL bBlockingLocks;
+ BOOL bInheritPerms;
char dummy[3]; /* for alignment */
} service;
@@ -462,6 +463,7 @@ static service sDefault =
False, /* bDosFiletimeResolution */
False, /* bFakeDirCreateTimes */
True, /* bBlockingLocks */
+ False, /* bInheritPerms */
"" /* dummy */
};
@@ -609,6 +611,7 @@ static struct parm_struct parm_table[] =
{"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},
@@ -1397,6 +1400,7 @@ FN_LOCAL_BOOL(lp_dos_filetimes,bDosFiletimes)
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)
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c
index 5e7d4a0c87..292eb2455e 100644
--- a/source3/smbd/blocking.c
+++ b/source3/smbd/blocking.c
@@ -208,7 +208,13 @@ static void reply_lockingX_error(blocking_lock_record *blr, int eclass, int32 ec
* 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;
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index 27393fe1c6..9690f115c4 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -26,33 +26,68 @@ extern int DEBUGLEVEL;
/****************************************************************************
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;
@@ -62,11 +97,17 @@ mode_t unix_mode(connection_struct *conn,int dosmode)
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);
}
@@ -155,7 +196,7 @@ int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *
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);
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 9615c5ada2..81536156e5 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -726,7 +726,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
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.
@@ -1073,7 +1073,7 @@ static int call_nt_transact_create(connection_struct *conn,
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.
@@ -1834,7 +1834,7 @@ static size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
* 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);
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 88de1db151..ad208005a0 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1147,7 +1147,7 @@ int open_directory(files_struct *fsp,connection_struct *conn,
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;
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 1e90ff4c4f..d15a26b20c 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1547,7 +1547,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
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);
@@ -1649,7 +1649,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
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);
@@ -1773,7 +1773,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
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)
@@ -1853,7 +1853,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
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)
@@ -3076,7 +3076,7 @@ int reply_printopen(connection_struct *conn,
/* 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);
@@ -3235,7 +3235,7 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
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)
{
@@ -4291,7 +4291,12 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
/* 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);
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 9811a9ff01..896200059f 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -232,7 +232,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf,
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);
@@ -2014,7 +2014,7 @@ static int call_trans2mkdir(connection_struct *conn,
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)
{