diff options
author | Jeremy Allison <jra@samba.org> | 2007-01-17 02:09:37 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:17:12 -0500 |
commit | 83eb0d1d6d90d182e8eee8496695113c89f8dba1 (patch) | |
tree | d2b02c7647d2755759e0453cb411101429da16b4 /source3 | |
parent | 52a36db39fb96353702616dfac5004239c34cd2c (diff) | |
download | samba-83eb0d1d6d90d182e8eee8496695113c89f8dba1.tar.gz samba-83eb0d1d6d90d182e8eee8496695113c89f8dba1.tar.bz2 samba-83eb0d1d6d90d182e8eee8496695113c89f8dba1.zip |
r20844: Somewhat radical change - this may break the build (I will
watch carefully - so I'm doing it in one transaction so I can
roll back).
Change check_name(), reduce_name() and dptr_create() to
return NTSTATUS. This helps a lot in error path processing
and especially in reduce_name() allows us to ditch the flaky
and error-prone saving of errno and return errors directly.
Jeremy.
(This used to be commit 6133a694aa429d638320e39ffe1c49d172583ccf)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/rpc_server/srv_srvsvc_nt.c | 6 | ||||
-rw-r--r-- | source3/smbd/dir.c | 31 | ||||
-rw-r--r-- | source3/smbd/filename.c | 21 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 28 | ||||
-rw-r--r-- | source3/smbd/reply.c | 389 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 54 | ||||
-rw-r--r-- | source3/smbd/vfs.c | 40 |
7 files changed, 310 insertions, 259 deletions
diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c index 646a414cda..a9adaf3200 100644 --- a/source3/rpc_server/srv_srvsvc_nt.c +++ b/source3/rpc_server/srv_srvsvc_nt.c @@ -2073,7 +2073,8 @@ WERROR _srvsvc_NetGetFileSecurity(pipes_struct *p, const char *server_unc, const goto error_exit; } - if (!check_name(file,conn)) { + nt_status = check_name(conn, file); + if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(3,("_srv_net_file_query_secdesc: can't access %s\n", file)); status = WERR_ACCESS_DENIED; goto error_exit; @@ -2176,7 +2177,8 @@ WERROR _srvsvc_NetSetFileSecurity(pipes_struct *p, const char *server_unc, const goto error_exit; } - if (!check_name(file,conn)) { + nt_status = check_name(conn, file); + if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(3,("_srv_net_file_set_secdesc: can't access %s\n", file)); status = WERR_ACCESS_DENIED; goto error_exit; diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 5a6b9713e5..7be5c03f1b 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -382,21 +382,26 @@ static void dptr_close_oldest(BOOL old) wcard must not be zero. ****************************************************************************/ -int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid, - const char *wcard, BOOL wcard_has_wild, uint32 attr) +NTSTATUS dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid, + const char *wcard, BOOL wcard_has_wild, uint32 attr, int *dptr_hnd_ret) { struct dptr_struct *dptr = NULL; struct smb_Dir *dir_hnd; const char *dir2; + NTSTATUS status; DEBUG(5,("dptr_create dir=%s\n", path)); + *dptr_hnd_ret = -1; + if (!wcard) { - return -1; + return NT_STATUS_INVALID_PARAMETER; } - if (!check_name(path,conn)) - return(-2); /* Code to say use a unix error return code. */ + status = check_name(conn,path); + if (!NT_STATUS_IS_OK(status)) { + return status; + } /* use a const pointer from here on */ dir2 = path; @@ -405,19 +410,20 @@ int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL exp dir_hnd = OpenDir(conn, dir2, wcard, attr); if (!dir_hnd) { - return (-2); + return map_nt_error_from_unix(errno); } string_set(&conn->dirpath,dir2); - if (dirhandles_open >= MAX_OPEN_DIRECTORIES) + if (dirhandles_open >= MAX_OPEN_DIRECTORIES) { dptr_idleoldest(); + } dptr = SMB_MALLOC_P(struct dptr_struct); if(!dptr) { DEBUG(0,("malloc fail in dptr_create.\n")); CloseDir(dir_hnd); - return -1; + return NT_STATUS_NO_MEMORY; } ZERO_STRUCTP(dptr); @@ -447,7 +453,7 @@ int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL exp DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum)); SAFE_FREE(dptr); CloseDir(dir_hnd); - return -1; + return NT_STATUS_TOO_MANY_OPENED_FILES; } } } else { @@ -477,7 +483,7 @@ int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL exp DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum)); SAFE_FREE(dptr); CloseDir(dir_hnd); - return -1; + return NT_STATUS_TOO_MANY_OPENED_FILES; } } } @@ -496,7 +502,7 @@ int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL exp bitmap_clear(dptr_bmap, dptr->dnum - 1); SAFE_FREE(dptr); CloseDir(dir_hnd); - return -1; + return NT_STATUS_NO_MEMORY; } if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) { dptr->has_wild = True; @@ -513,7 +519,8 @@ int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL exp conn->dirptr = dptr; - return(dptr->dnum); + *dptr_hnd_ret = dptr->dnum; + return NT_STATUS_OK; } diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index a36b7ff282..b69d2f3e5e 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -512,28 +512,25 @@ NTSTATUS unix_convert(connection_struct *conn, a valid one for the user to access. ****************************************************************************/ -BOOL check_name(const pstring name,connection_struct *conn) +NTSTATUS check_name(connection_struct *conn, const pstring name) { - BOOL ret = True; - if (IS_VETO_PATH(conn, name)) { /* Is it not dot or dot dot. */ if (!((name[0] == '.') && (!name[1] || (name[1] == '.' && !name[2])))) { - DEBUG(5,("file path name %s vetoed\n",name)); - errno = ENOENT; - return False; + DEBUG(5,("check_name: file path name %s vetoed\n",name)); + return map_nt_error_from_unix(ENOENT); } } if (!lp_widelinks(SNUM(conn)) || !lp_symlinks(SNUM(conn))) { - ret = reduce_name(conn,name); - } - - if (!ret) { - DEBUG(5,("check_name on %s failed\n",name)); + NTSTATUS status = reduce_name(conn,name); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(5,("check_name: name %s failed with %s\n",name, nt_errstr(status))); + return status; + } } - return(ret); + return NT_STATUS_OK; } /**************************************************************************** diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index df65ad7da6..f4d6220592 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -634,10 +634,11 @@ int reply_ntcreate_and_X(connection_struct *conn, return ERROR_NT(status); } /* All file access must go through check_name() */ - if (!check_name(fname,conn)) { + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { restore_case_semantics(conn, file_attributes); END_PROFILE(SMBntcreateX); - return UNIXERROR(ERRDOS,ERRbadpath); + return ERROR_NT(status); } /* This is the correct thing to do (check every time) but can_delete is @@ -1259,9 +1260,10 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o return ERROR_NT(status); } /* All file access must go through check_name() */ - if (!check_name(fname,conn)) { + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { restore_case_semantics(conn, file_attributes); - return UNIXERROR(ERRDOS,ERRbadpath); + return ERROR_NT(status); } /* This is the correct thing to do (check every time) but can_delete is @@ -1570,8 +1572,9 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new ZERO_STRUCT(sbuf1); ZERO_STRUCT(sbuf2); - if (!CAN_WRITE(conn)) + if (!CAN_WRITE(conn)) { return NT_STATUS_MEDIA_WRITE_PROTECTED; + } status = unix_convert(conn, oldname, False, last_component_oldname, &sbuf1); if (!NT_STATUS_IS_OK(status)) { @@ -1582,8 +1585,9 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new if (!VALID_STAT(sbuf1)) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } - if (!check_name(oldname,conn)) { - return NT_STATUS_ACCESS_DENIED; + status = check_name(conn, oldname); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* Ensure attributes match. */ @@ -1602,8 +1606,9 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new return NT_STATUS_OBJECT_NAME_COLLISION; } - if (!check_name(newname,conn)) { - return NT_STATUS_ACCESS_DENIED; + status = check_name(conn, newname); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* No links from a directory. */ @@ -1612,8 +1617,9 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new } /* Ensure this is within the share. */ - if (!reduce_name(conn, oldname) != 0) { - return NT_STATUS_ACCESS_DENIED; + status = reduce_name(conn, oldname); + if (!NT_STATUS_IS_OK(status)) { + return status; } DEBUG(10,("copy_internals: doing file copy %s to %s\n", oldname, newname)); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 9a0e544e38..2d11b3db98 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -638,42 +638,53 @@ int reply_checkpath(connection_struct *conn, char *inbuf,char *outbuf, int dum_s status = unix_convert(conn, name, False, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBcheckpath); - status = map_checkpath_error(inbuf, status); - return ERROR_NT(status); + goto path_err; } - if (check_name(name,conn) && (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,name,&sbuf) == 0)) { - if (!S_ISDIR(sbuf.st_mode)) { - END_PROFILE(SMBcheckpath); - return ERROR_BOTH(NT_STATUS_NOT_A_DIRECTORY,ERRDOS,ERRbadpath); - } - } else { - /* We special case this - as when a Windows machine - is parsing a path is steps through the components - one at a time - if a component fails it expects - ERRbadpath, not ERRbadfile. - */ - if(errno == ENOENT) { - /* - * Windows returns different error codes if - * the parent directory is valid but not the - * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND - * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND - * if the path is invalid. - */ - END_PROFILE(SMBcheckpath); - return ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpath); - } + status = check_name(conn, name); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3,("reply_checkpath: check_name of %s failed (%s)\n",name,nt_errstr(status))); + goto path_err; + } + + if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,name,&sbuf) != 0)) { + DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",name,strerror(errno))); + status = map_nt_error_from_unix(errno); + goto path_err; + } + if (!S_ISDIR(sbuf.st_mode)) { END_PROFILE(SMBcheckpath); - return(UNIXERROR(ERRDOS,ERRbadpath)); + return ERROR_BOTH(NT_STATUS_NOT_A_DIRECTORY,ERRDOS,ERRbadpath); } outsize = set_message(outbuf,0,0,False); END_PROFILE(SMBcheckpath); return outsize; + + path_err: + + END_PROFILE(SMBcheckpath); + + /* We special case this - as when a Windows machine + is parsing a path is steps through the components + one at a time - if a component fails it expects + ERRbadpath, not ERRbadfile. + */ + status = map_checkpath_error(inbuf, status); + if(NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + /* + * Windows returns different error codes if + * the parent directory is valid but not the + * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND + * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND + * if the path is invalid. + */ + return ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpath); + } + + return ERROR_NT(status); } /**************************************************************************** @@ -717,19 +728,23 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size END_PROFILE(SMBgetatr); return ERROR_NT(status); } - if (check_name(fname,conn) && - (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,fname,&sbuf) == 0)) { - mode = dos_mode(conn,fname,&sbuf); - size = sbuf.st_size; - mtime = sbuf.st_mtime; - if (mode & aDIR) { - size = 0; - } - } else { - DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno))); + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3,("reply_getatr: check_name of %s failed (%s)\n",fname,nt_errstr(status))); END_PROFILE(SMBgetatr); + return ERROR_NT(status); + } + if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,fname,&sbuf) != 0)) { + DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno))); return UNIXERROR(ERRDOS,ERRbadfile); } + + mode = dos_mode(conn,fname,&sbuf); + size = sbuf.st_size; + mtime = sbuf.st_mtime; + if (mode & aDIR) { + size = 0; + } } outsize = set_message(outbuf,10,0,True); @@ -792,9 +807,10 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return ERROR_NT(NT_STATUS_ACCESS_DENIED); } - if (!check_name(fname,conn)) { + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBsetatr); - return UNIXERROR(ERRDOS, ERRnoaccess); + return ERROR_NT(status); } mode = SVAL(inbuf,smb_vwv0); @@ -950,9 +966,10 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size } unix_format(dir2); - if (!check_name(directory,conn)) { + nt_status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(nt_status)) { END_PROFILE(SMBsearch); - return UNIXERROR(ERRDOS, ERRnoaccess); + return ERROR_NT(nt_status); } p = strrchr_m(dir2,'/'); @@ -996,14 +1013,9 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size p = smb_buf(outbuf) + 3; if (status_len == 0) { - dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid), mask, mask_contains_wcard, dirtype); - if (dptr_num < 0) { - if(dptr_num == -2) { - END_PROFILE(SMBsearch); - return UNIXERROR(ERRDOS, ERRnofids); - } - END_PROFILE(SMBsearch); - return ERROR_DOS(ERRDOS,ERRnofids); + nt_status = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid), mask, mask_contains_wcard, dirtype,&dptr_num); + if (!NT_STATUS_IS_OK(nt_status)) { + return ERROR_NT(nt_status); } } else { dirtype = dptr_attr(dptr_num); @@ -1839,66 +1851,73 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, dirtype = FILE_ATTRIBUTE_NORMAL; } status = can_delete(conn,directory,dirtype,can_defer); - if (!NT_STATUS_IS_OK(status)) + if (!NT_STATUS_IS_OK(status)) { return status; + } if (SMB_VFS_UNLINK(conn,directory) == 0) { count++; } } else { struct smb_Dir *dir_hnd = NULL; + long offset = 0; const char *dname; if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) { return NT_STATUS_OBJECT_NAME_INVALID; } - if (strequal(mask,"????????.???")) + if (strequal(mask,"????????.???")) { pstrcpy(mask,"*"); + } + + status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(status)) { + return status; + } - if (check_name(directory,conn)) - dir_hnd = OpenDir(conn, directory, mask, dirtype); + dir_hnd = OpenDir(conn, directory, mask, dirtype); + if (dir_hnd == NULL) { + return map_nt_error_from_unix(errno); + } /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then the pattern matches against the long name, otherwise the short name We don't implement this yet XXXX */ - if (dir_hnd) { - long offset = 0; - status = NT_STATUS_NO_SUCH_FILE; + status = NT_STATUS_NO_SUCH_FILE; - while ((dname = ReadDirName(dir_hnd, &offset))) { - SMB_STRUCT_STAT st; - pstring fname; - pstrcpy(fname,dname); + while ((dname = ReadDirName(dir_hnd, &offset))) { + SMB_STRUCT_STAT st; + pstring fname; + pstrcpy(fname,dname); - if (!is_visible_file(conn, directory, dname, &st, True)) { - continue; - } + if (!is_visible_file(conn, directory, dname, &st, True)) { + continue; + } - /* Quick check for "." and ".." */ - if (fname[0] == '.') { - if (!fname[1] || (fname[1] == '.' && !fname[2])) { - continue; - } + /* Quick check for "." and ".." */ + if (fname[0] == '.') { + if (!fname[1] || (fname[1] == '.' && !fname[2])) { + continue; } + } - if(!mask_match(fname, mask, conn->case_sensitive)) - continue; + if(!mask_match(fname, mask, conn->case_sensitive)) { + continue; + } - slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); - status = can_delete(conn, fname, dirtype, - can_defer); - if (!NT_STATUS_IS_OK(status)) { - continue; - } - if (SMB_VFS_UNLINK(conn,fname) == 0) - count++; - DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname)); + slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); + status = can_delete(conn, fname, dirtype, can_defer); + if (!NT_STATUS_IS_OK(status)) { + continue; } - CloseDir(dir_hnd); + if (SMB_VFS_UNLINK(conn,fname) == 0) + count++; + DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname)); } + CloseDir(dir_hnd); } if (count == 0 && NT_STATUS_IS_OK(status)) { @@ -3789,9 +3808,10 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_NT(status); } - if (!check_name(directory,conn)) { + status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBrmdir); - return UNIXERROR(ERRDOS, ERRbadpath); + return ERROR_NT(status); } dptr_closepath(directory,SVAL(inbuf,smb_pid)); @@ -4267,10 +4287,11 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", } TALLOC_FREE(lck); - if (errno == ENOTDIR || errno == EISDIR) + if (errno == ENOTDIR || errno == EISDIR) { status = NT_STATUS_OBJECT_NAME_COLLISION; - else + } else { status = map_nt_error_from_unix(errno); + } DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", nt_errstr(status), directory,newname)); @@ -4282,98 +4303,105 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", */ struct smb_Dir *dir_hnd = NULL; const char *dname; + long offset = 0; pstring destname; if (strequal(mask,"????????.???")) pstrcpy(mask,"*"); - if (check_name(directory,conn)) - dir_hnd = OpenDir(conn, directory, mask, attrs); + status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + dir_hnd = OpenDir(conn, directory, mask, attrs); + if (dir_hnd == NULL) { + return map_nt_error_from_unix(errno); + } - if (dir_hnd) { - long offset = 0; - status = NT_STATUS_NO_SUCH_FILE; -/* Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND; - gentest fix. JRA */ + status = NT_STATUS_NO_SUCH_FILE; +/* Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND; - gentest fix. JRA */ - while ((dname = ReadDirName(dir_hnd, &offset))) { - pstring fname; - BOOL sysdir_entry = False; + while ((dname = ReadDirName(dir_hnd, &offset))) { + pstring fname; + BOOL sysdir_entry = False; - pstrcpy(fname,dname); + pstrcpy(fname,dname); - /* Quick check for "." and ".." */ - if (fname[0] == '.') { - if (!fname[1] || (fname[1] == '.' && !fname[2])) { - if (attrs & aDIR) { - sysdir_entry = True; - } else { - continue; - } + /* Quick check for "." and ".." */ + if (fname[0] == '.') { + if (!fname[1] || (fname[1] == '.' && !fname[2])) { + if (attrs & aDIR) { + sysdir_entry = True; + } else { + continue; } } + } - if (!is_visible_file(conn, directory, dname, &sbuf1, False)) - continue; + if (!is_visible_file(conn, directory, dname, &sbuf1, False)) { + continue; + } - if(!mask_match(fname, mask, conn->case_sensitive)) - continue; + if(!mask_match(fname, mask, conn->case_sensitive)) { + continue; + } - if (sysdir_entry) { - status = NT_STATUS_OBJECT_NAME_INVALID; - break; - } + if (sysdir_entry) { + status = NT_STATUS_OBJECT_NAME_INVALID; + break; + } - status = NT_STATUS_ACCESS_DENIED; - slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname); - if (!vfs_object_exist(conn, fname, &sbuf1)) { - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; - DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(status))); - continue; - } - status = can_rename(conn,fname,attrs,&sbuf1); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(6,("rename %s refused\n", fname)); - continue; - } - pstrcpy(destname,newname); - - if (!resolve_wildcards(fname,destname)) { - DEBUG(6,("resolve_wildcards %s %s failed\n", - fname, destname)); - continue; - } + status = NT_STATUS_ACCESS_DENIED; + slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname); + if (!vfs_object_exist(conn, fname, &sbuf1)) { + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(status))); + continue; + } + status = can_rename(conn,fname,attrs,&sbuf1); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(6,("rename %s refused\n", fname)); + continue; + } + pstrcpy(destname,newname); + + if (!resolve_wildcards(fname,destname)) { + DEBUG(6,("resolve_wildcards %s %s failed\n", + fname, destname)); + continue; + } - if (strcsequal(fname,destname)) { - rename_open_files(conn, NULL, sbuf1.st_dev, sbuf1.st_ino, newname); - DEBUG(3,("rename_internals: identical names in wildcard rename %s - success\n", fname)); - count++; - status = NT_STATUS_OK; - continue; - } + if (strcsequal(fname,destname)) { + rename_open_files(conn, NULL, sbuf1.st_dev, sbuf1.st_ino, newname); + DEBUG(3,("rename_internals: identical names in wildcard rename %s - success\n", fname)); + count++; + status = NT_STATUS_OK; + continue; + } - if (!replace_if_exists && - vfs_file_exist(conn,destname, NULL)) { - DEBUG(6,("file_exist %s\n", destname)); - status = NT_STATUS_OBJECT_NAME_COLLISION; - continue; - } + if (!replace_if_exists && vfs_file_exist(conn,destname, NULL)) { + DEBUG(6,("file_exist %s\n", destname)); + status = NT_STATUS_OBJECT_NAME_COLLISION; + continue; + } - if (rename_path_prefix_equal(fname, destname)) { - return NT_STATUS_SHARING_VIOLATION; - } + if (rename_path_prefix_equal(fname, destname)) { + return NT_STATUS_SHARING_VIOLATION; + } - lck = get_share_mode_lock(NULL, sbuf1.st_dev, sbuf1.st_ino, NULL, NULL); + lck = get_share_mode_lock(NULL, sbuf1.st_dev, sbuf1.st_ino, NULL, NULL); - if (!SMB_VFS_RENAME(conn,fname,destname)) { - rename_open_files(conn, lck, sbuf1.st_dev, sbuf1.st_ino, newname); - count++; - status = NT_STATUS_OK; - } - TALLOC_FREE(lck); - DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname)); + if (!SMB_VFS_RENAME(conn,fname,destname)) { + rename_open_files(conn, lck, sbuf1.st_dev, sbuf1.st_ino, newname); + count++; + status = NT_STATUS_OK; } - CloseDir(dir_hnd); + TALLOC_FREE(lck); + DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname)); } + CloseDir(dir_hnd); + } #if 0 /* Don't think needed any more - JRA. */ @@ -4386,8 +4414,6 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", } #endif - } - if (count == 0 && NT_STATUS_IS_OK(status)) { status = map_nt_error_from_unix(errno); } @@ -4693,40 +4719,49 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, } else { struct smb_Dir *dir_hnd = NULL; const char *dname; + long offset = 0; pstring destname; if (strequal(mask,"????????.???")) pstrcpy(mask,"*"); - if (check_name(directory,conn)) - dir_hnd = OpenDir(conn, directory, mask, 0); + status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(status)) { + return ERROR_NT(status); + } + + dir_hnd = OpenDir(conn, directory, mask, 0); + if (dir_hnd == NULL) { + status = map_nt_error_from_unix(errno); + return ERROR_NT(status); + } - if (dir_hnd) { - long offset = 0; - error = ERRbadfile; + error = ERRbadfile; - while ((dname = ReadDirName(dir_hnd, &offset))) { - pstring fname; - pstrcpy(fname,dname); + while ((dname = ReadDirName(dir_hnd, &offset))) { + pstring fname; + pstrcpy(fname,dname); - if (!is_visible_file(conn, directory, dname, &sbuf1, False)) - continue; + if (!is_visible_file(conn, directory, dname, &sbuf1, False)) { + continue; + } - if(!mask_match(fname, mask, conn->case_sensitive)) - continue; + if(!mask_match(fname, mask, conn->case_sensitive)) { + continue; + } - error = ERRnoaccess; - slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); - pstrcpy(destname,newname); - if (resolve_wildcards(fname,destname) - && NT_STATUS_IS_OK(status = copy_file( - fname,destname,conn,ofun, - count,target_is_directory))) - count++; - DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname)); + error = ERRnoaccess; + slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); + pstrcpy(destname,newname); + if (resolve_wildcards(fname,destname) && + NT_STATUS_IS_OK(status = copy_file( + fname,destname,conn,ofun, + count,target_is_directory))) { + count++; } - CloseDir(dir_hnd); + DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname)); } + CloseDir(dir_hnd); } if (count == 0) { diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 48a5a0c1ac..e91a2134fd 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -805,8 +805,9 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i return ERROR_NT(status); } - if (!check_name(fname,conn)) { - return UNIXERROR(ERRDOS,ERRnoaccess); + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + return ERROR_NT(status); } if (open_ofun == 0) { @@ -1722,8 +1723,9 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", if (!NT_STATUS_IS_OK(ntstatus)) { return ERROR_NT(ntstatus); } - if(!check_name(directory,conn)) { - return UNIXERROR(ERRDOS,ERRbadpath); + ntstatus = check_name(conn, directory); + if (!NT_STATUS_IS_OK(ntstatus)) { + return ERROR_NT(ntstatus); } p = strrchr_m(directory,'/'); @@ -1764,7 +1766,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd if ((ea_ctx = talloc_init("findnext_ea_list")) == NULL) { return ERROR_NT(NT_STATUS_NO_MEMORY); } - + /* Pull out the list of names. */ ea_list = read_ea_name_list(ea_ctx, pdata + 4, ea_size - 4); if (!ea_list) { @@ -1792,10 +1794,10 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* Save the wildcard match and attribs we are using on this directory - needed as lanman2 assumes these are being saved between calls */ - dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid), mask, mask_contains_wcard, dirtype); - if (dptr_num < 0) { + ntstatus = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid), mask, mask_contains_wcard, dirtype, &dptr_num); + if (!NT_STATUS_IS_OK(ntstatus)) { talloc_destroy(ea_ctx); - return(UNIXERROR(ERRDOS,ERRbadfile)); + return ERROR_NT(ntstatus); } DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, mask, dirtype)); @@ -2934,9 +2936,10 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } - if (!check_name(fname,conn)) { - DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); - return UNIXERROR(ERRDOS,ERRbadpath); + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,nt_errstr(status))); + return ERROR_NT(status); } if (INFO_LEVEL_IS_UNIX(info_level)) { @@ -3686,7 +3689,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam return NT_STATUS_OBJECT_NAME_NOT_FOUND; } - if (!check_name(oldname,conn)) { + status = check_name(conn, oldname); + if (!NT_STATUS_IS_OK(status)) { return NT_STATUS_ACCESS_DENIED; } @@ -3700,7 +3704,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam return NT_STATUS_OBJECT_NAME_COLLISION; } - if (!check_name(newname,conn)) { + status = check_name(conn, newname); + if (!NT_STATUS_IS_OK(status)) { return NT_STATUS_ACCESS_DENIED; } @@ -3710,8 +3715,10 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam } /* Ensure this is within the share. */ - if (!reduce_name(conn, oldname) != 0) - return NT_STATUS_ACCESS_DENIED; + status = reduce_name(conn, oldname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", newname, oldname )); @@ -3826,8 +3833,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char return UNIXERROR(ERRDOS,ERRbadpath); } - if(!check_name(fname, conn)) { - return UNIXERROR(ERRDOS,ERRbadpath); + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + return ERROR_NT(status); } } @@ -4366,8 +4374,9 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", } pstrcat(rel_name, link_target); - if (!check_name(rel_name, conn)) { - return(UNIXERROR(ERRDOS,ERRnoaccess)); + status = check_name(conn, rel_name); + if (!NT_STATUS_IS_OK(status)) { + return ERROR_NT(status); } } @@ -4823,9 +4832,10 @@ static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, return ERROR_NT(NT_STATUS_INVALID_PARAMETER); } - if (!check_name(directory,conn)) { - DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno))); - return UNIXERROR(ERRDOS, ERRnoaccess); + status = check_name(conn, directory); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(5,("call_trans2mkdir error (%s)\n", nt_errstr(status))); + return ERROR_NT(status); } status = create_directory(conn, directory); diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index a4ecff921a..47ac9ef461 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -821,7 +821,7 @@ BOOL canonicalize_path(connection_struct *conn, pstring path) it is below dir in the heirachy. This uses realpath. ********************************************************************/ -BOOL reduce_name(connection_struct *conn, const pstring fname) +NTSTATUS reduce_name(connection_struct *conn, const pstring fname) { #ifdef REALPATH_TAKES_NULL BOOL free_resolved_name = True; @@ -836,7 +836,6 @@ BOOL reduce_name(connection_struct *conn, const pstring fname) char *resolved_name = NULL; size_t con_path_len = strlen(conn->connectpath); char *p = NULL; - int saved_errno = errno; DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath)); @@ -850,8 +849,7 @@ BOOL reduce_name(connection_struct *conn, const pstring fname) switch (errno) { case ENOTDIR: DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname)); - errno = saved_errno; - return False; + return map_nt_error_from_unix(errno); case ENOENT: { pstring tmp_fname; @@ -875,8 +873,7 @@ BOOL reduce_name(connection_struct *conn, const pstring fname) #endif if (!resolved_name) { DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname)); - errno = saved_errno; - return False; + return map_nt_error_from_unix(errno); } pstrcpy(tmp_fname, resolved_name); pstrcat(tmp_fname, "/"); @@ -886,8 +883,7 @@ BOOL reduce_name(connection_struct *conn, const pstring fname) resolved_name = SMB_STRDUP(tmp_fname); if (!resolved_name) { DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname)); - errno = saved_errno; - return False; + return NT_STATUS_NO_MEMORY; } #else #ifdef PATH_MAX @@ -901,9 +897,7 @@ BOOL reduce_name(connection_struct *conn, const pstring fname) } default: DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname)); - /* Don't restore the saved errno. We need to return the error that - realpath caused here as it was not one of the cases we handle. JRA. */ - return False; + return map_nt_error_from_unix(errno); } } @@ -911,19 +905,19 @@ BOOL reduce_name(connection_struct *conn, const pstring fname) if (*resolved_name != '/') { DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n")); - if (free_resolved_name) + if (free_resolved_name) { SAFE_FREE(resolved_name); - errno = saved_errno; - return False; + } + return NT_STATUS_OBJECT_NAME_INVALID; } /* Check for widelinks allowed. */ if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) { DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname)); - if (free_resolved_name) + if (free_resolved_name) { SAFE_FREE(resolved_name); - errno = EACCES; - return False; + } + return NT_STATUS_ACCESS_DENIED; } /* Check if we are allowing users to follow symlinks */ @@ -935,18 +929,18 @@ BOOL reduce_name(connection_struct *conn, const pstring fname) SMB_STRUCT_STAT statbuf; if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) && (S_ISLNK(statbuf.st_mode)) ) { - if (free_resolved_name) + if (free_resolved_name) { SAFE_FREE(resolved_name); + } DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name)); - errno = EACCES; - return False; + return NT_STATUS_ACCESS_DENIED; } } #endif DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name)); - if (free_resolved_name) + if (free_resolved_name) { SAFE_FREE(resolved_name); - errno = saved_errno; - return(True); + } + return NT_STATUS_OK; } |