From 722aa118c66b020c2b9f2b595e1af50429f13986 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 2 Apr 2004 18:46:19 +0000 Subject: Added per-share parameter "store dos attributes". When set, will store dos attributes in an EA. Based on an original patch from tridge, but modified somewhat to cover all cases. Jeremy. (This used to be commit ed653cd468213e0be901bc654aa3748ce5837947) --- source3/include/smb.h | 3 + source3/param/loadparm.c | 4 ++ source3/printing/nt_printing.c | 6 +- source3/rpc_server/srv_srvsvc_nt.c | 8 +-- source3/smbd/dir.c | 4 +- source3/smbd/dosmode.c | 129 +++++++++++++++++++++++++++++++++++-- source3/smbd/fake_file.c | 8 +-- source3/smbd/fileio.c | 5 +- source3/smbd/nttrans.c | 23 ++----- source3/smbd/open.c | 81 +++++++++++++---------- source3/smbd/posix_acls.c | 2 +- source3/smbd/reply.c | 48 ++++++-------- source3/smbd/trans2.c | 16 ++--- 13 files changed, 227 insertions(+), 110 deletions(-) (limited to 'source3') 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; @@ -159,22 +160,130 @@ uint32 dos_mode_from_sbuf(connection_struct *conn, SMB_STRUCT_STAT *sbuf) return result; } +/**************************************************************************** + 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)); -- cgit