summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd')
-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
6 files changed, 84 insertions, 32 deletions
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)
{