diff options
-rw-r--r-- | source3/param/loadparm.c | 4 | ||||
-rw-r--r-- | source3/smbd/dir.c | 69 |
2 files changed, 73 insertions, 0 deletions
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index a5f01c6abf..6f976cda64 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -339,6 +339,7 @@ typedef struct BOOL bCaseMangle; BOOL bHideDotFiles; BOOL bHideUnReadable; + BOOL bHideUnWriteable; BOOL bBrowseable; BOOL bAvailable; BOOL bRead_only; @@ -457,6 +458,7 @@ static service sDefault = { False, /* case mangle */ True, /* bHideDotFiles */ False, /* bHideUnReadable */ + False, /* bHideUnable */ True, /* bBrowseable */ True, /* bAvailable */ True, /* bRead_only */ @@ -875,6 +877,7 @@ static struct parm_struct parm_table[] = { {"mangling char", P_CHAR, P_LOCAL, &sDefault.magic_char, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL}, {"hide dot files", P_BOOL, P_LOCAL, &sDefault.bHideDotFiles, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL}, {"hide unreadable", P_BOOL, P_LOCAL, &sDefault.bHideUnReadable, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL}, + {"hide unwriteable", P_BOOL, P_LOCAL, &sDefault.bHideUnWriteable, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL}, {"delete veto files", P_BOOL, P_LOCAL, &sDefault.bDeleteVetoFiles, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL}, {"veto files", P_STRING, P_LOCAL, &sDefault.szVetoFiles, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL }, {"hide files", P_STRING, P_LOCAL, &sDefault.szHideFiles, NULL, NULL, FLAG_SHARE | FLAG_GLOBAL }, @@ -1661,6 +1664,7 @@ FN_LOCAL_BOOL(lp_shortpreservecase, bShortCasePreserve) FN_LOCAL_BOOL(lp_casemangle, bCaseMangle) FN_LOCAL_BOOL(lp_hide_dot_files, bHideDotFiles) FN_LOCAL_BOOL(lp_hideunreadable, bHideUnReadable) +FN_LOCAL_BOOL(lp_hideunwriteable, bHideUnWriteable) FN_LOCAL_BOOL(lp_browseable, bBrowseable) FN_LOCAL_BOOL(lp_readonly, bRead_only) FN_LOCAL_BOOL(lp_no_set_dir, bNo_set_dir) diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 7dd425ef8a..01e3063b67 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -722,6 +722,62 @@ static BOOL user_can_read_file(connection_struct *conn, char *name) } /******************************************************************* +check to see if a user can write a file. This is only approximate, +it is used as part of the "hide unwriteable" option. Don't +use it for anything security sensitive +********************************************************************/ + +static BOOL user_can_write_file(connection_struct *conn, char *name) +{ + extern struct current_user current_user; + SMB_STRUCT_STAT ste; + SEC_DESC *psd = NULL; + size_t sd_size; + files_struct *fsp; + int smb_action; + int access_mode; + NTSTATUS status; + uint32 access_granted; + + ZERO_STRUCT(ste); + + /* + * If user is a member of the Admin group + * we never hide files from them. + */ + + if (conn->admin_user) + return True; + + /* If we can't stat it does not show it */ + if (vfs_stat(conn, name, &ste) != 0) + return False; + + /* Pseudo-open the file (note - no fd's created). */ + + if(S_ISDIR(ste.st_mode)) + fsp = open_directory(conn, name, &ste, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), + unix_mode(conn, aDIR, name), &smb_action); + else + fsp = open_file_shared1(conn, name, &ste, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE), + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action); + + if (!fsp) + return False; + + /* Get NT ACL -allocated in main loop talloc context. No free needed here. */ + sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd); + close_file(fsp, False); + + /* No access if SD get failed. */ + if (!sd_size) + return False; + + return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA, + &access_granted, &status); +} + +/******************************************************************* Open a directory. ********************************************************************/ @@ -781,6 +837,19 @@ void *OpenDir(connection_struct *conn, char *name, BOOL use_veto) continue; } + /* Honour _hide unwriteable_ option */ + if (normal_entry && conn && lp_hideunwriteable(SNUM(conn))) { + char *entry; + int ret=0; + + if (asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) { + ret = user_can_write_file(conn, entry); + SAFE_FREE(entry); + } + if (!ret) + continue; + } + if (used + l > dirp->mallocsize) { int s = MAX(used+l,used+2000); char *r; |