summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source3/include/smb.h3
-rw-r--r--source3/param/loadparm.c4
-rw-r--r--source3/printing/nt_printing.c6
-rw-r--r--source3/rpc_server/srv_srvsvc_nt.c8
-rw-r--r--source3/smbd/dir.c4
-rw-r--r--source3/smbd/dosmode.c129
-rw-r--r--source3/smbd/fake_file.c8
-rw-r--r--source3/smbd/fileio.c5
-rw-r--r--source3/smbd/nttrans.c23
-rw-r--r--source3/smbd/open.c81
-rw-r--r--source3/smbd/posix_acls.c2
-rw-r--r--source3/smbd/reply.c48
-rw-r--r--source3/smbd/trans2.c16
13 files changed, 227 insertions, 110 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 24c0100b5b9..3ee6f01d34d 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -1668,4 +1668,7 @@ struct ea_struct {
/* EA names used internally in Samba. KEEP UP TO DATE with prohibited_ea_names in trans2.c !. */
#define SAMBA_POSIX_INHERITANCE_EA_NAME "user.SAMBA_PAI"
+/* EA to use for DOS attributes */
+#define SAMBA_XATTR_DOS_ATTRIB "user.DOSATTRIB"
+
#endif /* _SMB_H */
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 4c0a3948f89..6b09faf7bf9 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -379,6 +379,7 @@ typedef struct
BOOL bMap_system;
BOOL bMap_hidden;
BOOL bMap_archive;
+ BOOL bStoreDosAttributes;
BOOL bLocking;
BOOL bStrictLocking;
BOOL bPosixLocking;
@@ -501,6 +502,7 @@ static service sDefault = {
False, /* bMap_system */
False, /* bMap_hidden */
True, /* bMap_archive */
+ False, /* bStoreDosAttributes */
True, /* bLocking */
True, /* bStrictLocking */
True, /* bPosixLocking */
@@ -994,6 +996,7 @@ static struct parm_struct parm_table[] = {
{"mangled names", P_BOOL, P_LOCAL, &sDefault.bMangledNames, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
{"mangled map", P_STRING, P_LOCAL, &sDefault.szMangledMap, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL | FLAG_DEPRECATED },
{"stat cache", P_BOOL, P_GLOBAL, &Globals.bStatCache, NULL, NULL, FLAG_ADVANCED},
+ {"store dos attributes", P_BOOL, P_LOCAL, &sDefault.bStoreDosAttributes, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
{N_("Domain Options"), P_SEP, P_SEPARATOR},
@@ -1844,6 +1847,7 @@ FN_LOCAL_BOOL(lp_guest_only, bGuest_only)
FN_LOCAL_BOOL(lp_print_ok, bPrint_ok)
FN_LOCAL_BOOL(lp_map_hidden, bMap_hidden)
FN_LOCAL_BOOL(lp_map_archive, bMap_archive)
+FN_LOCAL_BOOL(lp_store_dos_attributes, bStoreDosAttributes)
FN_LOCAL_BOOL(lp_locking, bLocking)
FN_LOCAL_BOOL(lp_strict_locking, bStrictLocking)
FN_LOCAL_BOOL(lp_posix_locking, bPosixLocking)
diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c
index f7e2945426b..449b0e83edc 100644
--- a/source3/printing/nt_printing.c
+++ b/source3/printing/nt_printing.c
@@ -992,7 +992,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
fsp = open_file_shared(conn, filepath, &stat_buf,
SET_OPEN_MODE(DOS_OPEN_RDONLY),
(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
- 0, 0, &access_mode, &action);
+ FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
if (!fsp) {
/* Old file not found, so by definition new file is in fact newer */
DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
@@ -1021,7 +1021,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
fsp = open_file_shared(conn, filepath, &stat_buf,
SET_OPEN_MODE(DOS_OPEN_RDONLY),
(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
- 0, 0, &access_mode, &action);
+ FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
if (!fsp) {
/* New file not found, this shouldn't occur if the caller did its job */
DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
@@ -1137,7 +1137,7 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_
fsp = open_file_shared(conn, driverpath, &st,
SET_OPEN_MODE(DOS_OPEN_RDONLY),
(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
- 0, 0, &access_mode, &action);
+ FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
if (!fsp) {
DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
driverpath, errno));
diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c
index 40d3a43bef9..77b9be99660 100644
--- a/source3/rpc_server/srv_srvsvc_nt.c
+++ b/source3/rpc_server/srv_srvsvc_nt.c
@@ -1887,13 +1887,13 @@ WERROR _srv_net_file_query_secdesc(pipes_struct *p, SRV_Q_NET_FILE_QUERY_SECDESC
unistr2_to_ascii(filename, &q_u->uni_file_name, sizeof(filename));
unix_convert(filename, conn, NULL, &bad_path, &st);
fsp = open_file_shared(conn, filename, &st, SET_OPEN_MODE(DOS_OPEN_RDONLY),
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &action);
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
if (!fsp) {
/* Perhaps it is a directory */
if (errno == EISDIR)
fsp = open_directory(conn, filename, &st,FILE_READ_ATTRIBUTES,0,
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, &action);
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), &action);
if (!fsp) {
DEBUG(3,("_srv_net_file_query_secdesc: Unable to open file %s\n", filename));
@@ -1991,13 +1991,13 @@ WERROR _srv_net_file_set_secdesc(pipes_struct *p, SRV_Q_NET_FILE_SET_SECDESC *q_
unix_convert(filename, conn, NULL, &bad_path, &st);
fsp = open_file_shared(conn, filename, &st, SET_OPEN_MODE(DOS_OPEN_RDWR),
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &action);
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
if (!fsp) {
/* Perhaps it is a directory */
if (errno == EISDIR)
fsp = open_directory(conn, filename, &st,FILE_READ_ATTRIBUTES,0,
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, &action);
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), &action);
if (!fsp) {
DEBUG(3,("_srv_net_file_set_secdesc: Unable to open file %s\n", filename));
diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
index bbd79e16597..06ef23ab8cd 100644
--- a/source3/smbd/dir.c
+++ b/source3/smbd/dir.c
@@ -707,7 +707,7 @@ static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_S
if(S_ISDIR(pst->st_mode))
fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
- unix_mode(conn,aRONLY|aDIR, name), &smb_action);
+ &smb_action);
else
fsp = open_file_stat(conn, name, pst);
@@ -763,7 +763,7 @@ static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_
return True;
else
fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action);
if (!fsp)
return False;
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index 1369c46b2f6..d7dc63bb2fd 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -45,11 +45,12 @@
mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname)
{
- mode_t result = (S_IRUSR | S_IRGRP | S_IROTH);
+ mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
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 (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
+ result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+ }
if (fname && lp_inherit_perms(SNUM(conn))) {
char *dname;
@@ -160,21 +161,129 @@ uint32 dos_mode_from_sbuf(connection_struct *conn, SMB_STRUCT_STAT *sbuf)
}
/****************************************************************************
+ Get DOS attributes from an EA.
+****************************************************************************/
+
+static BOOL get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf, uint32 *pattr)
+{
+ ssize_t sizeret;
+ fstring attrstr;
+ unsigned int dosattr;
+
+ if (!lp_store_dos_attributes(SNUM(conn))) {
+ return False;
+ }
+
+ *pattr = 0;
+
+ sizeret = SMB_VFS_GETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr));
+ if (sizeret == -1) {
+#if defined(ENOTSUP) && defined(ENOATTR)
+ if ((errno != ENOTSUP) && (errno != ENOATTR) && (errno != EACCES)) {
+ DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
+ path, strerror(errno) ));
+ }
+#endif
+ return False;
+ }
+ /* Null terminate string. */
+ attrstr[sizeret] = 0;
+ DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path, attrstr));
+
+ if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
+ sscanf(attrstr, "%x", &dosattr) != 1) {
+ DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path, attrstr));
+ return False;
+ }
+
+ if (S_ISDIR(sbuf->st_mode)) {
+ dosattr |= aDIR;
+ }
+ *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
+
+ DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
+
+ if (dosattr & aHIDDEN) DEBUG(8, ("h"));
+ if (dosattr & aRONLY ) DEBUG(8, ("r"));
+ if (dosattr & aSYSTEM) DEBUG(8, ("s"));
+ if (dosattr & aDIR ) DEBUG(8, ("d"));
+ if (dosattr & aARCH ) DEBUG(8, ("a"));
+
+ DEBUG(8,("\n"));
+
+ return True;
+}
+
+/****************************************************************************
+ Set DOS attributes in an EA.
+****************************************************************************/
+
+static BOOL set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode)
+{
+ fstring attrstr;
+ files_struct *fsp = NULL;
+ BOOL ret = False;
+
+ snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
+ if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) {
+ if((errno != EPERM) && (errno != EACCES)) {
+ return False;
+ }
+
+ /* We want DOS semantics, ie allow non owner with write permission to change the
+ bits on a file. Just like file_utime below.
+ */
+
+ /* Check if we have write access. */
+ if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
+ return False;
+
+ /*
+ * We need to open the file with write access whilst
+ * still in our current user context. This ensures we
+ * are not violating security in doing the setxattr.
+ */
+
+ fsp = open_file_fchmod(conn,path,sbuf);
+ if (!fsp)
+ return ret;
+ become_root();
+ if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) {
+ ret = True;
+ }
+ unbecome_root();
+ close_file_fchmod(fsp);
+ return ret;
+ }
+ DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path));
+ return True;
+}
+
+/****************************************************************************
Change a unix mode to a dos mode.
****************************************************************************/
-uint32 dos_mode(connection_struct *conn,char *path,SMB_STRUCT_STAT *sbuf)
+uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
{
- int result = 0;
+ uint32 result = 0;
DEBUG(8,("dos_mode: %s\n", path));
+ if (!VALID_STAT(*sbuf)) {
+ return 0;
+ }
+
+ /* Get the DOS attributes from an EA by preference. */
+ if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
+ return result;
+ }
+
result = dos_mode_from_sbuf(conn, sbuf);
/* Now do any modifications that depend on the path name. */
/* hide files with a name starting with a . */
if (lp_hide_dot_files(SNUM(conn))) {
- char *p = strrchr_m(path,'/');
+ const char *p = strrchr_m(path,'/');
if (p)
p++;
else
@@ -207,7 +316,7 @@ uint32 dos_mode(connection_struct *conn,char *path,SMB_STRUCT_STAT *sbuf)
chmod a file - but preserve some bits.
********************************************************************/
-int file_chmod(connection_struct *conn,char *fname, uint32 dosmode,SMB_STRUCT_STAT *st)
+int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode, SMB_STRUCT_STAT *st)
{
SMB_STRUCT_STAT st1;
int mask=0;
@@ -215,6 +324,7 @@ int file_chmod(connection_struct *conn,char *fname, uint32 dosmode,SMB_STRUCT_ST
mode_t unixmode;
int ret = -1;
+ DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
if (!st) {
st = &st1;
if (SMB_VFS_STAT(conn,fname,st))
@@ -231,6 +341,11 @@ int file_chmod(connection_struct *conn,char *fname, uint32 dosmode,SMB_STRUCT_ST
if (dos_mode(conn,fname,st) == dosmode)
return(0);
+ /* Store the DOS attributes in an EA by preference. */
+ if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
+ return 0;
+ }
+
unixmode = unix_mode(conn,dosmode,fname);
/* preserve the s bits */
diff --git a/source3/smbd/fake_file.c b/source3/smbd/fake_file.c
index 86d78e039a1..5ccb548ba5b 100644
--- a/source3/smbd/fake_file.c
+++ b/source3/smbd/fake_file.c
@@ -26,7 +26,7 @@
files_struct *open_fake_file_shared1(enum FAKE_FILE_TYPE fake_file_type, connection_struct *conn,char *fname,
SMB_STRUCT_STAT *psbuf,
uint32 desired_access,
- int share_mode,int ofun, mode_t mode,int oplock_request,
+ int share_mode,int ofun, uint32 new_dos_attr, int oplock_request,
int *Access,int *action)
{
extern struct current_user current_user;
@@ -35,7 +35,7 @@ files_struct *open_fake_file_shared1(enum FAKE_FILE_TYPE fake_file_type, connect
if (fake_file_type == 0) {
return open_file_shared1(conn,fname,psbuf,desired_access,
- share_mode,ofun,mode,
+ share_mode,ofun,new_dos_attr,
oplock_request,Access,action);
}
@@ -51,8 +51,8 @@ files_struct *open_fake_file_shared1(enum FAKE_FILE_TYPE fake_file_type, connect
if(!fsp)
return NULL;
- DEBUG(5,("open_fake_file_shared1: fname = %s, FID = %d, share_mode = %x, ofun = %x, mode = %o, oplock request = %d\n",
- fname, fsp->fnum, share_mode, ofun, (int)mode, oplock_request ));
+ DEBUG(5,("open_fake_file_shared1: fname = %s, FID = %d, share_mode = %x, ofun = %x, oplock request = %d\n",
+ fname, fsp->fnum, share_mode, ofun, oplock_request ));
if (!check_name(fname,conn)) {
file_free(fsp);
diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c
index 3462a3b9fa5..c2fb6e34566 100644
--- a/source3/smbd/fileio.c
+++ b/source3/smbd/fileio.c
@@ -176,8 +176,9 @@ ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n)
if (SMB_VFS_FSTAT(fsp,fsp->fd,&st) == 0) {
int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
fsp->size = (SMB_BIG_UINT)st.st_size;
- if (MAP_ARCHIVE(fsp->conn) && !IS_DOS_ARCHIVE(dosmode))
- file_chmod(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st);
+ if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) {
+ file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st);
+ }
/*
* If this is the first write and we have an exclusive oplock then setup
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 21b6db8b469..c9cc44627db 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -586,11 +586,9 @@ int reply_ntcreate_and_X(connection_struct *conn,
SMB_BIG_UINT allocation_size = 0;
int smb_ofun;
int smb_open_mode;
- int smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK);
/* Breakout the oplock request bits so we can set the
reply bits separately. */
int oplock_request = 0;
- mode_t unixmode;
int fmode=0,rmode=0;
SMB_OFF_T file_len = 0;
SMB_STRUCT_STAT sbuf;
@@ -766,8 +764,6 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
unix_convert(fname,conn,0,&bad_path,&sbuf);
- unixmode = unix_mode(conn,smb_attr | aARCH, fname);
-
/*
* If it's a request for a directory open, deal with it separately.
*/
@@ -781,7 +777,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
- fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);
+ fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action);
restore_case_semantics(file_attributes);
@@ -811,14 +807,14 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
fsp = open_file_shared1(conn,fname,&sbuf,
desired_access,
smb_open_mode,
- smb_ofun,unixmode, oplock_request,
+ smb_ofun,file_attributes,oplock_request,
&rmode,&smb_action);
} else {
/* to open a fake_file --metze */
fsp = open_fake_file_shared1(fake_file_type,conn,fname,&sbuf,
desired_access,
smb_open_mode,
- smb_ofun,unixmode, oplock_request,
+ smb_ofun,file_attributes, oplock_request,
&rmode,&smb_action);
}
@@ -857,7 +853,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
}
oplock_request = 0;
- fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);
+ fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action);
if(!fsp) {
restore_case_semantics(file_attributes);
@@ -1134,7 +1130,6 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
char *data = *ppdata;
/* Breakout the oplock request bits so we can set the reply bits separately. */
int oplock_request = 0;
- mode_t unixmode;
int fmode=0,rmode=0;
SMB_OFF_T file_len = 0;
SMB_STRUCT_STAT sbuf;
@@ -1154,7 +1149,6 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
SMB_BIG_UINT allocation_size = 0;
int smb_ofun;
int smb_open_mode;
- int smb_attr;
time_t c_time;
NTSTATUS status;
@@ -1192,7 +1186,6 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
create_options = IVAL(params,32);
sd_len = IVAL(params,36);
root_dir_fid = (uint16)IVAL(params,4);
- smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK);
if (create_options & FILE_OPEN_BY_FILE_ID) {
return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
@@ -1297,8 +1290,6 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
unix_convert(fname,conn,0,&bad_path,&sbuf);
- unixmode = unix_mode(conn,smb_attr | aARCH, fname);
-
/*
* If it's a request for a directory open, deal with it separately.
*/
@@ -1318,7 +1309,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
* CreateDirectory() call.
*/
- fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);
+ fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action);
if(!fsp) {
restore_case_semantics(file_attributes);
@@ -1332,7 +1323,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
*/
fsp = open_file_shared1(conn,fname,&sbuf,desired_access,
- smb_open_mode,smb_ofun,unixmode,
+ smb_open_mode,smb_ofun,file_attributes,
oplock_request,&rmode,&smb_action);
if (!fsp) {
@@ -1350,7 +1341,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
}
oplock_request = 0;
- fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);
+ fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action);
if(!fsp) {
restore_case_semantics(file_attributes);
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 084ae9a1bf2..8ab5dab6ac9 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -741,21 +741,10 @@ static void kernel_flock(files_struct *fsp, int deny_mode)
}
-static BOOL open_match_attributes(connection_struct *conn, char *path, mode_t existing_mode,
- mode_t new_mode, mode_t *returned_mode)
+static BOOL open_match_attributes(connection_struct *conn, const char *path, uint32 old_dos_mode, uint32 new_dos_mode,
+ mode_t existing_mode, mode_t new_mode, mode_t *returned_mode)
{
- uint32 old_dos_mode, new_dos_mode;
uint32 noarch_old_dos_mode, noarch_new_dos_mode;
- SMB_STRUCT_STAT sbuf;
-
- ZERO_STRUCT(sbuf);
-
- sbuf.st_mode = existing_mode;
- old_dos_mode = dos_mode(conn, path, &sbuf);
-
- sbuf.st_mode = new_mode;
- /* The new mode conversion shouldn't look at pathname. */
- new_dos_mode = dos_mode_from_sbuf(conn, &sbuf);
noarch_old_dos_mode = (old_dos_mode & ~FILE_ATTRIBUTE_ARCHIVE);
noarch_new_dos_mode = (new_dos_mode & ~FILE_ATTRIBUTE_ARCHIVE);
@@ -771,11 +760,11 @@ static BOOL open_match_attributes(connection_struct *conn, char *path, mode_t ex
old_dos_mode, (unsigned int)existing_mode, new_dos_mode, (unsigned int)*returned_mode ));
/* If we're mapping SYSTEM and HIDDEN ensure they match. */
- if (lp_map_system(SNUM(conn))) {
+ if (lp_map_system(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) {
if ((old_dos_mode & FILE_ATTRIBUTE_SYSTEM) && !(new_dos_mode & FILE_ATTRIBUTE_SYSTEM))
return False;
}
- if (lp_map_hidden(SNUM(conn))) {
+ if (lp_map_hidden(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) {
if ((old_dos_mode & FILE_ATTRIBUTE_HIDDEN) && !(new_dos_mode & FILE_ATTRIBUTE_HIDDEN))
return False;
}
@@ -787,10 +776,10 @@ static BOOL open_match_attributes(connection_struct *conn, char *path, mode_t ex
****************************************************************************/
files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_STAT *psbuf,
- int share_mode,int ofun, mode_t mode,int oplock_request,
+ int share_mode,int ofun, uint32 new_dos_mode, int oplock_request,
int *Access,int *action)
{
- return open_file_shared1(conn, fname, psbuf, 0, share_mode, ofun, mode,
+ return open_file_shared1(conn, fname, psbuf, 0, share_mode, ofun, new_dos_mode,
oplock_request, Access, action);
}
@@ -800,8 +789,9 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S
files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_STAT *psbuf,
uint32 desired_access,
- int share_mode,int ofun, mode_t mode,int oplock_request,
- int *Access,int *action)
+ int share_mode,int ofun, uint32 new_dos_mode,
+ int oplock_request,
+ int *Access,int *paction)
{
int flags=0;
int flags2=0;
@@ -820,6 +810,10 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
int open_mode=0;
uint16 port = 0;
mode_t new_mode = (mode_t)0;
+ int action;
+ uint32 existing_dos_mode = 0;
+ /* We add aARCH to this as this mode is only used if the file is created new. */
+ mode_t mode = unix_mode(conn,new_dos_mode | aARCH,fname);
if (conn->printer) {
/* printers are handled completely differently. Most of the passed parameters are
@@ -827,7 +821,7 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
if (Access)
*Access = DOS_OPEN_WRONLY;
if (action)
- *action = FILE_WAS_CREATED;
+ *paction = FILE_WAS_CREATED;
return print_fsp_open(conn, fname);
}
@@ -835,14 +829,19 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
if(!fsp)
return NULL;
- DEBUG(10,("open_file_shared: fname = %s, share_mode = %x, ofun = %x, mode = %o, oplock request = %d\n",
- fname, share_mode, ofun, (int)mode, oplock_request ));
+ DEBUG(10,("open_file_shared: fname = %s, dos_attrs = %x, share_mode = %x, ofun = %x, mode = %o, oplock request = %d\n",
+ fname, new_dos_mode, share_mode, ofun, (int)mode, oplock_request ));
if (!check_name(fname,conn)) {
file_free(fsp);
return NULL;
}
+ new_dos_mode &= SAMBA_ATTRIBUTES_MASK;
+ if (file_existed) {
+ existing_dos_mode = dos_mode(conn, fname, psbuf);
+ }
+
/* ignore any oplock requests if oplocks are disabled */
if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break) {
oplock_request = 0;
@@ -883,9 +882,11 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
/* We only care about matching attributes on file exists and truncate. */
if (file_existed && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE)) {
- if (!open_match_attributes(conn, fname, psbuf->st_mode, mode, &new_mode)) {
- DEBUG(5,("open_file_shared: attributes missmatch for file %s (0%o, 0%o)\n",
- fname, (int)psbuf->st_mode, (int)mode ));
+ if (!open_match_attributes(conn, fname, existing_dos_mode, new_dos_mode,
+ psbuf->st_mode, mode, &new_mode)) {
+ DEBUG(5,("open_file_shared: attributes missmatch for file %s (%x %x) (0%o, 0%o)\n",
+ fname, existing_dos_mode, new_dos_mode,
+ (int)psbuf->st_mode, (int)mode ));
file_free(fsp);
errno = EACCES;
return NULL;
@@ -929,7 +930,7 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
#endif /* O_SYNC */
if (flags != O_RDONLY && file_existed &&
- (!CAN_WRITE(conn) || IS_DOS_READONLY(dos_mode(conn,fname,psbuf)))) {
+ (!CAN_WRITE(conn) || IS_DOS_READONLY(existing_dos_mode))) {
if (!fcbopen) {
DEBUG(5,("open_file_shared: read/write access requested for file %s on read only %s\n",
fname, !CAN_WRITE(conn) ? "share" : "file" ));
@@ -1120,16 +1121,19 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
DEBUG(10,("open_file_shared : share_mode = %x\n", fsp->share_mode ));
- if (Access)
+ if (Access) {
(*Access) = open_mode;
+ }
- if (action) {
- if (file_existed && !(flags2 & O_TRUNC))
- *action = FILE_WAS_OPENED;
- if (!file_existed)
- *action = FILE_WAS_CREATED;
- if (file_existed && (flags2 & O_TRUNC))
- *action = FILE_WAS_OVERWRITTEN;
+ if (file_existed && !(flags2 & O_TRUNC))
+ action = FILE_WAS_OPENED;
+ if (file_existed && (flags2 & O_TRUNC))
+ action = FILE_WAS_OVERWRITTEN;
+ if (!file_existed)
+ action = FILE_WAS_CREATED;
+
+ if (paction) {
+ *paction = action;
}
/*
@@ -1164,6 +1168,13 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
}
}
+ if (action == FILE_WAS_OVERWRITTEN || action == FILE_WAS_CREATED) {
+ /* Files should be initially set as archive */
+ if (lp_map_archive(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) {
+ file_set_dosmode(conn, fname, new_dos_mode | aARCH, NULL);
+ }
+ }
+
/*
* Take care of inherited ACLs on created files - if default ACL not
* selected.
@@ -1257,7 +1268,7 @@ int close_file_fchmod(files_struct *fsp)
****************************************************************************/
files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_STAT *psbuf,
- uint32 desired_access, int share_mode, int smb_ofun, mode_t unixmode, int *action)
+ uint32 desired_access, int share_mode, int smb_ofun, int *action)
{
extern struct current_user current_user;
BOOL got_stat = False;
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index ee370437ec3..620e123e14d 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -3181,7 +3181,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
the mask bits, not the real group bits, for a file with an ACL.
****************************************************************************/
-int get_acl_group_bits( connection_struct *conn, char *fname, mode_t *mode )
+int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode )
{
int entry_id = SMB_ACL_FIRST_ENTRY;
SMB_ACL_ENTRY_T entry;
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index f5c4f25e408..fde4ee627fd 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -678,8 +678,9 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
else
mode &= ~aDIR;
- if (check_name(fname,conn))
- ok = (file_chmod(conn,fname,mode,NULL) == 0);
+ if (check_name(fname,conn)) {
+ ok = (file_set_dosmode(conn,fname,mode,NULL) == 0);
+ }
} else {
ok = True;
}
@@ -1008,12 +1009,12 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
int share_mode;
SMB_OFF_T size = 0;
time_t mtime=0;
- mode_t unixmode;
int rmode=0;
SMB_STRUCT_STAT sbuf;
BOOL bad_path = False;
files_struct *fsp;
int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+ uint16 dos_attr = SVAL(inbuf,smb_vwv1);
NTSTATUS status;
START_PROFILE(SMBopen);
@@ -1029,10 +1030,8 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
unix_convert(fname,conn,0,&bad_path,&sbuf);
- unixmode = unix_mode(conn,aARCH,fname);
-
fsp = open_file_shared(conn,fname,&sbuf,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
- unixmode, oplock_request,&rmode,NULL);
+ (uint32)dos_attr, oplock_request,&rmode,NULL);
if (!fsp) {
END_PROFILE(SMBopen);
@@ -1089,7 +1088,6 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
#endif
int smb_ofun = SVAL(inbuf,smb_vwv8);
- mode_t unixmode;
SMB_OFF_T size=0;
int fmode=0,mtime=0,rmode=0;
SMB_STRUCT_STAT sbuf;
@@ -1121,9 +1119,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
unix_convert(fname,conn,0,&bad_path,&sbuf);
- unixmode = unix_mode(conn,smb_attr | aARCH, fname);
-
- fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,unixmode,
+ fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,(uint32)smb_attr,
oplock_request, &rmode,&smb_action);
if (!fsp) {
@@ -1215,7 +1211,6 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
int com;
int outsize = 0;
int createmode;
- mode_t unixmode;
int ofun = 0;
BOOL bad_path = False;
files_struct *fsp;
@@ -1240,8 +1235,6 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
if (createmode & aVOLID)
DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
- unixmode = unix_mode(conn,createmode,fname);
-
if(com == SMBmknew) {
/* We should fail if file exists. */
ofun = FILE_CREATE_IF_NOT_EXIST;
@@ -1252,7 +1245,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
/* Open file in dos compatibility share mode. */
fsp = open_file_shared(conn,fname,&sbuf,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
- ofun, unixmode, oplock_request, NULL, NULL);
+ ofun, (uint32)createmode, oplock_request, NULL, NULL);
if (!fsp) {
END_PROFILE(SMBcreate);
@@ -1269,7 +1262,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
DEBUG( 2, ( "new file %s\n", fname ) );
- DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n", fname, fsp->fd, createmode, (int)unixmode ) );
+ DEBUG( 3, ( "mknew %s fd=%d dmode=%d\n", fname, fsp->fd, createmode ) );
END_PROFILE(SMBcreate);
return(outsize);
@@ -1283,8 +1276,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
{
pstring fname;
int outsize = 0;
- int createmode;
- mode_t unixmode;
+ int createattr;
BOOL bad_path = False;
files_struct *fsp;
int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
@@ -1295,7 +1287,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
START_PROFILE(SMBctemp);
- createmode = SVAL(inbuf,smb_vwv0);
+ createattr = SVAL(inbuf,smb_vwv0);
srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBctemp);
@@ -1307,8 +1299,6 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
unix_convert(fname,conn,0,&bad_path,&sbuf);
- unixmode = unix_mode(conn,createmode,fname);
-
tmpfd = smb_mkstemp(fname);
if (tmpfd == -1) {
END_PROFILE(SMBctemp);
@@ -1322,7 +1312,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
fsp = open_file_shared(conn,fname,&sbuf,
SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
FILE_EXISTS_OPEN|FILE_FAIL_IF_NOT_EXIST,
- unixmode, oplock_request, NULL, NULL);
+ (uint32)createattr, oplock_request, NULL, NULL);
/* close fd from smb_mkstemp() */
close(tmpfd);
@@ -1356,8 +1346,8 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
DEBUG( 2, ( "created temp file %s\n", fname ) );
- DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
- fname, fsp->fd, createmode, (int)unixmode ) );
+ DEBUG( 3, ( "ctemp %s fd=%d umode=%o\n",
+ fname, fsp->fd, sbuf.st_mode ) );
END_PROFILE(SMBctemp);
return(outsize);
@@ -1384,7 +1374,7 @@ static NTSTATUS can_rename(char *fname,connection_struct *conn, SMB_STRUCT_STAT
unix_ERR_code = 0;
fsp = open_file_shared1(conn, fname, pst, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action);
if (!fsp) {
NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
@@ -1449,7 +1439,7 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype, BOO
unix_ERR_code = 0;
fsp = open_file_shared1(conn, fname, &sbuf, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action);
if (!fsp) {
NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
@@ -3949,7 +3939,8 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
SMB_OFF_T ret=-1;
files_struct *fsp1,*fsp2;
pstring dest;
-
+ uint32 dosattrs;
+
*err_ret = 0;
pstrcpy(dest,dest1);
@@ -3967,7 +3958,7 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
return(False);
fsp1 = open_file_shared(conn,src,&src_sbuf,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),FILE_ATTRIBUTE_NORMAL,0,&Access,&action);
if (!fsp1)
return(False);
@@ -3975,11 +3966,12 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
if (!target_is_directory && count)
ofun = FILE_EXISTS_OPEN;
+ dosattrs = dos_mode(conn, src, &src_sbuf);
if (SMB_VFS_STAT(conn,dest,&sbuf2) == -1)
ZERO_STRUCTP(&sbuf2);
fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
- ofun,src_sbuf.st_mode,0,&Access,&action);
+ ofun,dosattrs,0,&Access,&action);
if (!fsp2) {
close_file(fsp1,False);
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index b1807705a0b..a88722edde5 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -55,6 +55,7 @@ SMB_BIG_UINT get_allocation_size(files_struct *fsp, SMB_STRUCT_STAT *sbuf)
static const char *prohibited_ea_names[] = {
SAMBA_POSIX_INHERITANCE_EA_NAME,
+ SAMBA_XATTR_DOS_ATTRIB,
NULL
};
@@ -538,7 +539,6 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
int32 open_size;
char *pname;
pstring fname;
- mode_t unixmode;
SMB_OFF_T size=0;
int fmode=0,mtime=0,rmode;
SMB_INO_T inode = 0;
@@ -586,9 +586,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
- unixmode = unix_mode(conn,open_attr | aARCH, fname);
-
- fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,unixmode,
+ fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,(uint32)open_attr,
oplock_request, &rmode,&smb_action);
if (!fsp) {
@@ -3133,7 +3131,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
new_fsp = open_file_shared1(conn, fname, &sbuf,FILE_WRITE_DATA,
SET_OPEN_MODE(DOS_OPEN_RDWR),
(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
- 0, 0, &access_mode, &action);
+ FILE_ATTRIBUTE_NORMAL,
+ 0, &access_mode, &action);
if (new_fsp == NULL)
return(UNIXERROR(ERRDOS,ERRbadpath));
@@ -3528,8 +3527,8 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n", fname, dosmode ));
- if(file_chmod(conn, fname, dosmode, NULL)) {
- DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
+ if(file_set_dosmode(conn, fname, dosmode, NULL)) {
+ DEBUG(2,("file_set_dosmode of %s failed (%s)\n", fname, strerror(errno)));
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
}
@@ -3559,7 +3558,8 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
new_fsp = open_file_shared(conn, fname, &sbuf,
SET_OPEN_MODE(DOS_OPEN_RDWR),
(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
- 0, 0, &access_mode, &action);
+ FILE_ATTRIBUTE_NORMAL,
+ 0, &access_mode, &action);
if (new_fsp == NULL)
return(UNIXERROR(ERRDOS,ERRbadpath));