diff options
-rw-r--r-- | source3/include/smb.h | 3 | ||||
-rw-r--r-- | source3/param/loadparm.c | 4 | ||||
-rw-r--r-- | source3/printing/nt_printing.c | 6 | ||||
-rw-r--r-- | source3/rpc_server/srv_srvsvc_nt.c | 8 | ||||
-rw-r--r-- | source3/smbd/dir.c | 4 | ||||
-rw-r--r-- | source3/smbd/dosmode.c | 129 | ||||
-rw-r--r-- | source3/smbd/fake_file.c | 8 | ||||
-rw-r--r-- | source3/smbd/fileio.c | 5 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 23 | ||||
-rw-r--r-- | source3/smbd/open.c | 81 | ||||
-rw-r--r-- | source3/smbd/posix_acls.c | 2 | ||||
-rw-r--r-- | source3/smbd/reply.c | 48 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 16 |
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)); |