diff options
author | Jeremy Allison <jra@samba.org> | 2007-01-12 23:47:16 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:17:04 -0500 |
commit | db0ad252a0622dfac17d44ca646168df4c1c22e5 (patch) | |
tree | 36128572dc6d4319ec9f7ab4622aa620d165b3b9 /source3 | |
parent | 700c3ab1c94fcd0ff422afa0e0e3faf419b3c5af (diff) | |
download | samba-db0ad252a0622dfac17d44ca646168df4c1c22e5.tar.gz samba-db0ad252a0622dfac17d44ca646168df4c1c22e5.tar.bz2 samba-db0ad252a0622dfac17d44ca646168df4c1c22e5.zip |
r20718: Sync up the filename path parsing changes from SAMBA_3_0_24.
The only difference between the two trees now w.r.t file
serving are the changes to smbd/open.c in this branch I need
to review.
Jeremy.
(This used to be commit f4474edf6a0c71001dbd01429ef70bafad6abd74)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/printing/nt_printing.c | 38 | ||||
-rw-r--r-- | source3/rpc_server/srv_srvsvc_nt.c | 10 | ||||
-rw-r--r-- | source3/smbd/dosmode.c | 8 | ||||
-rw-r--r-- | source3/smbd/filename.c | 160 | ||||
-rw-r--r-- | source3/smbd/msdfs.c | 6 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 52 | ||||
-rw-r--r-- | source3/smbd/reply.c | 685 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 88 |
8 files changed, 408 insertions, 639 deletions
diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 5fa5db54e4..8f264bfd1e 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -656,13 +656,13 @@ BOOL nt_printing_init(void) Function to allow filename parsing "the old way". ********************************************************************/ -static BOOL driver_unix_convert(char *name,connection_struct *conn, - char *saved_last_component, BOOL *bad_path, SMB_STRUCT_STAT *pst) +static void driver_unix_convert(char *name,connection_struct *conn, + char *saved_last_component, SMB_STRUCT_STAT *pst) { unix_format(name); unix_clean_name(name); trim_string(name,"/","/"); - return unix_convert(name, conn, saved_last_component, bad_path, pst); + unix_convert(conn, name, False, saved_last_component, pst); } /******************************************************************* @@ -1279,7 +1279,6 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr files_struct *fsp = NULL; SMB_STRUCT_STAT st; SMB_STRUCT_STAT stat_buf; - BOOL bad_path; NTSTATUS status; @@ -1291,7 +1290,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr /* Get file version info (if available) for previous file (if it exists) */ pstrcpy(filepath, old_file); - driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf); + driver_unix_convert(filepath,conn,NULL,&stat_buf); status = open_file_ntcreate(conn, filepath, &stat_buf, FILE_GENERIC_READ, @@ -1327,7 +1326,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr /* Get file version info (if available) for new file */ pstrcpy(filepath, new_file); - driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf); + driver_unix_convert(filepath,conn,NULL,&stat_buf); status = open_file_ntcreate(conn, filepath, &stat_buf, FILE_GENERIC_READ, @@ -1404,7 +1403,6 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_ DATA_BLOB null_pw; fstring res_type; files_struct *fsp = NULL; - BOOL bad_path; SMB_STRUCT_STAT st; connection_struct *conn; NTSTATUS status; @@ -1456,7 +1454,7 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_ * deriver the cversion. */ slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in); - driver_unix_convert(driverpath,conn,NULL,&bad_path,&st); + driver_unix_convert(driverpath,conn,NULL,&st); if ( !vfs_file_exist( conn, driverpath, &st ) ) { *perr = WERR_BADFILE; @@ -1742,7 +1740,6 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract pstring inbuf; pstring outbuf; fstring res_type; - BOOL bad_path; SMB_STRUCT_STAT st; int ver = 0; int i; @@ -1798,7 +1795,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract */ DEBUG(5,("Creating first directory\n")); slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion); - driver_unix_convert(new_dir, conn, NULL, &bad_path, &st); + driver_unix_convert(new_dir, conn, NULL, &st); create_directory(conn, new_dir); /* For each driver file, archi\filexxx.yyy, if there is a duplicate file @@ -1824,7 +1821,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->driverpath); slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); + driver_unix_convert(new_name, conn, NULL, &st); if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", @@ -1840,7 +1837,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->datafile); slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); + driver_unix_convert(new_name, conn, NULL, &st); if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", @@ -1858,7 +1855,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->configfile); slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); + driver_unix_convert(new_name, conn, NULL, &st); if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", @@ -1877,7 +1874,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->helpfile); slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); + driver_unix_convert(new_name, conn, NULL, &st); if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", @@ -1905,7 +1902,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->dependentfiles[i]); slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - driver_unix_convert(new_name, conn, NULL, &bad_path, &st); + driver_unix_convert(new_name, conn, NULL, &st); if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { @@ -4812,7 +4809,6 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct DATA_BLOB null_pw; NTSTATUS nt_status; fstring res_type; - BOOL bad_path; SMB_STRUCT_STAT st; if ( !info_3 ) @@ -4855,7 +4851,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct if ( *info_3->driverpath ) { if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) { pstrcpy( file, s ); - driver_unix_convert(file, conn, NULL, &bad_path, &st); + driver_unix_convert(file, conn, NULL, &st); DEBUG(10,("deleting driverfile [%s]\n", s)); unlink_internals(conn, 0, file, False); } @@ -4864,7 +4860,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct if ( *info_3->configfile ) { if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) { pstrcpy( file, s ); - driver_unix_convert(file, conn, NULL, &bad_path, &st); + driver_unix_convert(file, conn, NULL, &st); DEBUG(10,("deleting configfile [%s]\n", s)); unlink_internals(conn, 0, file, False); } @@ -4873,7 +4869,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct if ( *info_3->datafile ) { if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) { pstrcpy( file, s ); - driver_unix_convert(file, conn, NULL, &bad_path, &st); + driver_unix_convert(file, conn, NULL, &st); DEBUG(10,("deleting datafile [%s]\n", s)); unlink_internals(conn, 0, file, False); } @@ -4882,7 +4878,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct if ( *info_3->helpfile ) { if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) { pstrcpy( file, s ); - driver_unix_convert(file, conn, NULL, &bad_path, &st); + driver_unix_convert(file, conn, NULL, &st); DEBUG(10,("deleting helpfile [%s]\n", s)); unlink_internals(conn, 0, file, False); } @@ -4898,7 +4894,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct if ( (p = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) { pstrcpy( file, p ); - driver_unix_convert(file, conn, NULL, &bad_path, &st); + driver_unix_convert(file, conn, NULL, &st); DEBUG(10,("deleting dependent file [%s]\n", file)); unlink_internals(conn, 0, file, False); } diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c index abfa794518..646a414cda 100644 --- a/source3/rpc_server/srv_srvsvc_nt.c +++ b/source3/rpc_server/srv_srvsvc_nt.c @@ -2036,7 +2036,6 @@ WERROR _srvsvc_NetGetFileSecurity(pipes_struct *p, const char *server_unc, const DATA_BLOB null_pw; files_struct *fsp = NULL; SMB_STRUCT_STAT st; - BOOL bad_path; NTSTATUS nt_status; connection_struct *conn = NULL; BOOL became_user = False; @@ -2067,8 +2066,8 @@ WERROR _srvsvc_NetGetFileSecurity(pipes_struct *p, const char *server_unc, const became_user = True; pstrcpy(tmp_file, file); - unix_convert(tmp_file, conn, NULL, &bad_path, &st); - if (bad_path) { + nt_status = unix_convert(conn, tmp_file, False, NULL, &st); + if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(3,("_srv_net_file_query_secdesc: bad pathname %s\n", file)); status = WERR_ACCESS_DENIED; goto error_exit; @@ -2141,7 +2140,6 @@ WERROR _srvsvc_NetSetFileSecurity(pipes_struct *p, const char *server_unc, const DATA_BLOB null_pw; files_struct *fsp = NULL; SMB_STRUCT_STAT st; - BOOL bad_path; NTSTATUS nt_status; connection_struct *conn = NULL; BOOL became_user = False; @@ -2171,8 +2169,8 @@ WERROR _srvsvc_NetSetFileSecurity(pipes_struct *p, const char *server_unc, const became_user = True; pstrcpy(tmp_file, file); - unix_convert(tmp_file, conn, NULL, &bad_path, &st); - if (bad_path) { + nt_status = unix_convert(conn, tmp_file, False, NULL, &st); + if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(3,("_srv_net_file_set_secdesc: bad pathname %s\n", file)); status = WERR_ACCESS_DENIED; goto error_exit; diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index 1172fe3e6b..ff4291c08c 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -35,14 +35,6 @@ static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf) Work out whether this file is offline ****************************************************************************/ -#ifndef ISDOT -#define ISDOT(p) (*(p) == '.' && *((p) + 1) == '\0') -#endif /* ISDOT */ - -#ifndef ISDOTDOT -#define ISDOTDOT(p) (*(p) == '.' && *((p) + 1) == '.' && *((p) + 2) == '\0') -#endif /* ISDOTDOT */ - static uint32 set_offline_flag(connection_struct *conn, const char *const path) { if (ISDOT(path) || ISDOTDOT(path)) { diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 1ea5228e91..3f02f6090f 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -64,18 +64,20 @@ changes etc. We assume that we have already done a chdir() to the right "root" directory for this service. -The function will return False if some part of the name except for the last -part cannot be resolved +The function will return an NTSTATUS error if some part of the name except for the last +part cannot be resolved, else NT_STATUS_OK. + +Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we didn't +get any fatal errors that should immediately terminate the calling +SMB processing whilst resolving. If the saved_last_component != 0, then the unmodified last component of the pathname is returned there. This is used in an exceptional case in reply_mv (so far). If saved_last_component == 0 then nothing is returned there. -The bad_path arg is set to True if the filename walk failed. This is -used to pick the correct error code to return between ENOENT and ENOTDIR -as Windows applications depend on ERRbadpath being returned if a component -of a pathname does not exist. +If last_component_wcard is true then a MS wildcard was detected and +should be allowed in the last component of the path only. On exit from unix_convert, if *pst was not null, then the file stat struct will be returned if the file exists and was found, if not this @@ -83,8 +85,11 @@ stat struct will be filled with zeros (and this can be detected by checking for nlinks = 0, which can never be true for any file). ****************************************************************************/ -BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_component, - BOOL *bad_path, SMB_STRUCT_STAT *pst) +NTSTATUS unix_convert(connection_struct *conn, + pstring name, + BOOL allow_wcard_last_component, + char *saved_last_component, + SMB_STRUCT_STAT *pst) { SMB_STRUCT_STAT st; char *start, *end; @@ -96,14 +101,15 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen SET_STAT_INVALID(*pst); *dirpath = 0; - *bad_path = False; - if(saved_last_component) + + if(saved_last_component) { *saved_last_component = 0; + } if (conn->printer) { /* we don't ever use the filenames on a printer share as a filename - so don't convert them */ - return True; + return NT_STATUS_OK; } DEBUG(5, ("unix_convert called on file \"%s\"\n", name)); @@ -136,7 +142,12 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen *pst = st; } DEBUG(5,("conversion finished \"\" -> %s\n",name)); - return(True); + return NT_STATUS_OK; + } + + if (name[0] == '.' && (name[1] == '/' || name[1] == '\0')) { + /* Start of pathname can't be "." only. */ + return NT_STATUS_OBJECT_NAME_INVALID; } /* @@ -145,10 +156,11 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen if(saved_last_component) { end = strrchr_m(name, '/'); - if(end) + if (end) { pstrcpy(saved_last_component, end + 1); - else + } else { pstrcpy(saved_last_component, name); + } } /* @@ -169,7 +181,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen if(!conn->case_sensitive && stat_cache_lookup(conn, name, dirpath, &start, &st)) { *pst = st; - return True; + return NT_STATUS_OK; } /* @@ -177,10 +189,22 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen */ if (SMB_VFS_STAT(conn,name,&st) == 0) { + /* Ensure we catch all names with in "/." + this is disallowed under Windows. */ + const char *p = strstr(name, "/."); /* mb safe. */ + if (p) { + if (p[2] == '/') { + /* Error code within a pathname. */ + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } else if (p[2] == '\0') { + /* Error code at the end of a pathname. */ + return NT_STATUS_OBJECT_NAME_INVALID; + } + } stat_cache_add(orig_path, name, conn->case_sensitive); DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); *pst = st; - return(True); + return NT_STATUS_OK; } DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", name, dirpath, start)); @@ -190,19 +214,20 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen * sensitive then searching won't help. */ - if (conn->case_sensitive && !mangle_is_mangled(name, conn->params) && - !*lp_mangled_map(conn->params)) - return(False); - - name_has_wildcard = ms_has_wild(start); + if (conn->case_sensitive && + !mangle_is_mangled(name, conn->params) && + !*lp_mangled_map(conn->params)) { + return NT_STATUS_OK; + } /* * is_mangled() was changed to look at an entire pathname, not * just a component. JRA. */ - if (mangle_is_mangled(start, conn->params)) + if (mangle_is_mangled(start, conn->params)) { component_was_mangled = True; + } /* * Now we need to recursively match the name against the real @@ -218,16 +243,64 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen /* * Pinpoint the end of this section of the filename. */ - end = strchr_m(start, '/'); + end = strchr(start, '/'); /* mb safe. '/' can't be in any encoded char. */ /* * Chop the name at this point. */ - if (end) + if (end) { *end = 0; + } - if(saved_last_component != 0) + if (saved_last_component != 0) { pstrcpy(saved_last_component, end ? end + 1 : start); + } + + /* The name cannot have a component of "." */ + + if (ISDOT(start)) { + if (end) { + if (allow_wcard_last_component) { + /* We're terminating here so we + * can be a little slower and get + * the error code right. Windows + * treats the last part of the pathname + * separately I think, so if the last + * component is a wildcard then we treat + * this ./ as "end of component" */ + + const char *p = strchr(end+1, '/'); + + if (!p && ms_has_wild(end+1)) { + /* Error code at the end of a pathname. */ + return NT_STATUS_OBJECT_NAME_INVALID; + } else { + /* Error code within a pathname. */ + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } + } + /* Error code within a pathname. */ + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } else { + /* Error code at the end of a pathname. */ + return NT_STATUS_OBJECT_NAME_INVALID; + } + } + + /* The name cannot have a wildcard if it's not + the last component. */ + + name_has_wildcard = ms_has_wild(start); + + /* Wildcard not valid anywhere. */ + if (name_has_wildcard && !allow_wcard_last_component) { + return NT_STATUS_OBJECT_NAME_INVALID; + } + + /* Wildcards never valid within a pathname. */ + if (name_has_wildcard && end) { + return NT_STATUS_OBJECT_NAME_INVALID; + } /* * Check if the name exists up to this point. @@ -251,9 +324,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen * Windows applications depend on the difference between * these two errors. */ - errno = ENOTDIR; - *bad_path = True; - return(False); + return NT_STATUS_OBJECT_PATH_NOT_FOUND; } if (!end) { @@ -278,8 +349,9 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen * later. */ - if (end) + if (end) { pstrcpy(rest,end+1); + } /* Reset errno so we can detect directory open errors. */ errno = 0; @@ -288,7 +360,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen * Try to find this part of the path in the directory. */ - if (ms_has_wild(start) || + if (name_has_wildcard || !scan_directory(conn, dirpath, start, sizeof(pstring) - 1 - (start - name))) { if (end) { /* @@ -304,13 +376,15 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen * Windows applications depend on the difference between * these two errors. */ - *bad_path = True; - return(False); + if (errno == ENOENT) { + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } + return map_nt_error_from_unix(errno); } if (errno == ENOTDIR) { - *bad_path = True; - return(False); + /* Name exists but is not a directory. */ + return map_nt_error_from_unix(ENOTDIR); } /* @@ -335,7 +409,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen } DEBUG(5,("New file %s\n",start)); - return(True); + return NT_STATUS_OK; } /* @@ -346,7 +420,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen end = start + strlen(start); if (!safe_strcat(start, "/", sizeof(pstring) - 1 - (start - name)) || !safe_strcat(start, rest, sizeof(pstring) - 1 - (start - name))) { - return False; + return map_nt_error_from_unix(ENAMETOOLONG); } *end = '\0'; } else { @@ -367,8 +441,9 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen /* * Add to the dirpath that we have resolved so far. */ - if (*dirpath) + if (*dirpath) { pstrcat(dirpath,"/"); + } pstrcat(dirpath,start); @@ -377,14 +452,16 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen * as this can change the size. */ - if(!component_was_mangled && !name_has_wildcard) + if(!component_was_mangled && !name_has_wildcard) { stat_cache_add(orig_path, dirpath, conn->case_sensitive); + } /* * Restore the / that we wiped out earlier. */ - if (end) + if (end) { *end = '/'; + } } /* @@ -392,15 +469,16 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen * as this can change the size. */ - if(!component_was_mangled && !name_has_wildcard) + if(!component_was_mangled && !name_has_wildcard) { stat_cache_add(orig_path, name, conn->case_sensitive); + } /* * The name has been resolved. */ DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); - return(True); + return NT_STATUS_OK; } /**************************************************************************** diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index 12fd333efe..42595c033e 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -326,8 +326,8 @@ static BOOL resolve_dfs_path(TALLOC_CTX *ctx, const char *dfspath, pstring localpath; int consumed_level = 1; char *p; - BOOL bad_path = False; SMB_STRUCT_STAT sbuf; + NTSTATUS status; pstring reqpath; if (!dp || !conn) { @@ -349,7 +349,9 @@ static BOOL resolve_dfs_path(TALLOC_CTX *ctx, const char *dfspath, DEBUG(10,("resolve_dfs_path: Conn path = %s req_path = %s\n", conn->connectpath, dp->reqpath)); - unix_convert(dp->reqpath,conn,0,&bad_path,&sbuf); + status = unix_convert(conn, dp->reqpath, False, NULL, &sbuf); + /* Should we terminate on status != NT_STATUS_OK ???? */ + /* JRA... should we strlower the last component here.... ? */ pstrcpy(localpath, dp->reqpath); diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 3e64cdc2d2..94bf363fc7 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -466,7 +466,6 @@ int reply_ntcreate_and_X(connection_struct *conn, SMB_OFF_T file_len = 0; SMB_STRUCT_STAT sbuf; int info = 0; - BOOL bad_path = False; files_struct *fsp=NULL; char *p = NULL; struct timespec c_timespec; @@ -628,18 +627,17 @@ int reply_ntcreate_and_X(connection_struct *conn, set_posix_case_semantics(conn, file_attributes); - unix_convert(fname,conn,0,&bad_path,&sbuf); - - if (bad_path) { + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { restore_case_semantics(conn, file_attributes); END_PROFILE(SMBntcreateX); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } /* All file access must go through check_name() */ if (!check_name(fname,conn)) { restore_case_semantics(conn, file_attributes); END_PROFILE(SMBntcreateX); - return UNIXERROR(ERRDOS, ERRbadpath); + return UNIXERROR(ERRDOS,ERRbadpath); } #if 0 @@ -1090,7 +1088,6 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o SMB_OFF_T file_len = 0; SMB_STRUCT_STAT sbuf; int info = 0; - BOOL bad_path = False; files_struct *fsp = NULL; char *p = NULL; BOOL extended_oplock_granted = False; @@ -1257,15 +1254,15 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { restore_case_semantics(conn, file_attributes); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } /* All file access must go through check_name() */ if (!check_name(fname,conn)) { restore_case_semantics(conn, file_attributes); - return UNIXERROR(ERRDOS, ERRbadpath); + return UNIXERROR(ERRDOS,ERRbadpath); } #if 0 @@ -1562,8 +1559,6 @@ int reply_ntcancel(connection_struct *conn, static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *newname, uint32 attrs) { - BOOL bad_path_oldname = False; - BOOL bad_path_newname = False; SMB_STRUCT_STAT sbuf1, sbuf2; pstring last_component_oldname; pstring last_component_newname; @@ -1577,24 +1572,12 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new ZERO_STRUCT(sbuf1); ZERO_STRUCT(sbuf2); - /* No wildcards. */ - if (ms_has_wild(newname) || ms_has_wild(oldname)) { - return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; - } - if (!CAN_WRITE(conn)) return NT_STATUS_MEDIA_WRITE_PROTECTED; - unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1); - if (bad_path_oldname) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - - /* Quick check for "." and ".." */ - if (last_component_oldname[0] == '.') { - if (!last_component_oldname[1] || (last_component_oldname[1] == '.' && !last_component_oldname[2])) { - return NT_STATUS_OBJECT_NAME_INVALID; - } + status = unix_convert(conn, oldname, False, last_component_oldname, &sbuf1); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* Source must already exist. */ @@ -1611,16 +1594,9 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new return NT_STATUS_NO_SUCH_FILE; } - unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2); - if (bad_path_newname) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - - /* Quick check for "." and ".." */ - if (last_component_newname[0] == '.') { - if (!last_component_newname[1] || (last_component_newname[1] == '.' && !last_component_newname[2])) { - return NT_STATUS_OBJECT_NAME_INVALID; - } + status = unix_convert(conn, newname, False, last_component_newname, &sbuf2); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* Disallow if newname already exists. */ diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index b3df8acf11..5914a3b169 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3,7 +3,7 @@ Main SMB reply routines Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Andrew Bartlett 2001 - Copyright (C) Jeremy Allison 1992-2004. + Copyright (C) Jeremy Allison 1992-2007. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -37,143 +37,6 @@ extern struct current_user current_user; extern BOOL global_encrypted_passwords_negotiated; /**************************************************************************** - Ensure we check the path in *exactly* the same way as W2K for regular pathnames. - We're assuming here that '/' is not the second byte in any multibyte char - set (a safe assumption). '\\' *may* be the second byte in a multibyte char - set. -****************************************************************************/ - -NTSTATUS check_path_syntax(pstring destname, const pstring srcname) -{ - char *d = destname; - const char *s = srcname; - NTSTATUS ret = NT_STATUS_OK; - BOOL start_of_name_component = True; - unsigned int num_bad_components = 0; - - while (*s) { - if (IS_DIRECTORY_SEP(*s)) { - /* - * Safe to assume is not the second part of a mb char as this is handled below. - */ - /* Eat multiple '/' or '\\' */ - while (IS_DIRECTORY_SEP(*s)) { - s++; - } - if ((d != destname) && (*s != '\0')) { - /* We only care about non-leading or trailing '/' or '\\' */ - *d++ = '/'; - } - - start_of_name_component = True; - continue; - } - - if (start_of_name_component) { - if ((s[0] == '.') && (s[1] == '.') && (IS_DIRECTORY_SEP(s[2]) || s[2] == '\0')) { - /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */ - - /* - * No mb char starts with '.' so we're safe checking the directory separator here. - */ - - /* If we just added a '/' - delete it */ - if ((d > destname) && (*(d-1) == '/')) { - *(d-1) = '\0'; - d--; - } - - /* Are we at the start ? Can't go back further if so. */ - if (d <= destname) { - ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; - break; - } - /* Go back one level... */ - /* We know this is safe as '/' cannot be part of a mb sequence. */ - /* NOTE - if this assumption is invalid we are not in good shape... */ - /* Decrement d first as d points to the *next* char to write into. */ - for (d--; d > destname; d--) { - if (*d == '/') - break; - } - s += 2; /* Else go past the .. */ - /* We're still at the start of a name component, just the previous one. */ - - if (num_bad_components) { - /* Hmmm. Should we only decrement the bad_components if - we're removing a bad component ? Need to check this. JRA. */ - num_bad_components--; - } - - continue; - - } else if ((s[0] == '.') && ((s[1] == '\0') || IS_DIRECTORY_SEP(s[1]))) { - /* Component of pathname can't be "." only. */ - ret = NT_STATUS_OBJECT_NAME_INVALID; - num_bad_components++; - *d++ = *s++; - continue; - } - } - - if (!(*s & 0x80)) { - if (*s <= 0x1f) { - return NT_STATUS_OBJECT_NAME_INVALID; - } - switch (*s) { - case '*': - case '?': - case '<': - case '>': - case '"': - return NT_STATUS_OBJECT_NAME_INVALID; - default: - *d++ = *s++; - break; - } - } else { - size_t siz; - /* Get the size of the next MB character. */ - next_codepoint(s,&siz); - switch(siz) { - case 5: - *d++ = *s++; - /*fall through*/ - case 4: - *d++ = *s++; - /*fall through*/ - case 3: - *d++ = *s++; - /*fall through*/ - case 2: - *d++ = *s++; - /*fall through*/ - case 1: - *d++ = *s++; - break; - default: - DEBUG(0,("check_path_syntax: character length assumptions invalid !\n")); - *d = '\0'; - return NT_STATUS_INVALID_PARAMETER; - } - } - if (start_of_name_component && num_bad_components) { - num_bad_components++; - } - start_of_name_component = False; - } - - if (NT_STATUS_EQUAL(ret, NT_STATUS_OBJECT_NAME_INVALID)) { - if (num_bad_components > 1) { - ret = NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - } - - *d = '\0'; - return ret; -} - -/**************************************************************************** Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext path or anything including wildcards. We're assuming here that '/' is not the second byte in any multibyte char @@ -181,15 +44,19 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname) set. ****************************************************************************/ -NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *p_contains_wcard) +NTSTATUS check_path_syntax_internal(pstring destname, + const pstring srcname, + BOOL windows_path, BOOL + *p_last_component_contains_wcard) { char *d = destname; const char *s = srcname; NTSTATUS ret = NT_STATUS_OK; BOOL start_of_name_component = True; - unsigned int num_bad_components = 0; - *p_contains_wcard = False; + if (p_last_component_contains_wcard) { + *p_last_component_contains_wcard = False; + } while (*s) { if (IS_DIRECTORY_SEP(*s)) { @@ -206,6 +73,10 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL * } start_of_name_component = True; + /* New component. */ + if (p_last_component_contains_wcard) { + *p_last_component_contains_wcard = False; + } continue; } @@ -238,36 +109,32 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL * } s += 2; /* Else go past the .. */ /* We're still at the start of a name component, just the previous one. */ - - if (num_bad_components) { - /* Hmmm. Should we only decrement the bad_components if - we're removing a bad component ? Need to check this. JRA. */ - num_bad_components--; - } - continue; } else if ((s[0] == '.') && ((s[1] == '\0') || IS_DIRECTORY_SEP(s[1]))) { - /* Component of pathname can't be "." only. */ - ret = NT_STATUS_OBJECT_NAME_INVALID; - num_bad_components++; - *d++ = *s++; - continue; + if (!windows_path) { + /* Eat the '.' */ + s++; + continue; + } } + } if (!(*s & 0x80)) { - if (*s <= 0x1f) { - return NT_STATUS_OBJECT_NAME_INVALID; - } - if (!*p_contains_wcard) { + if (windows_path) { + if (*s <= 0x1f) { + return NT_STATUS_OBJECT_NAME_INVALID; + } switch (*s) { case '*': case '?': case '<': case '>': case '"': - *p_contains_wcard = True; + if (p_last_component_contains_wcard) { + *p_last_component_contains_wcard = True; + } break; default: break; @@ -295,130 +162,48 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL * *d++ = *s++; break; default: - DEBUG(0,("check_path_syntax_wcard: character length assumptions invalid !\n")); + DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n")); *d = '\0'; return NT_STATUS_INVALID_PARAMETER; } } - if (start_of_name_component && num_bad_components) { - num_bad_components++; - } start_of_name_component = False; } - if (NT_STATUS_EQUAL(ret, NT_STATUS_OBJECT_NAME_INVALID)) { - /* For some strange reason being called from findfirst changes - the num_components number to cause the error return to change. JRA. */ - if (num_bad_components > 2) { - ret = NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - } - *d = '\0'; return ret; } /**************************************************************************** - Check the path for a POSIX client. - We're assuming here that '/' is not the second byte in any multibyte char - set (a safe assumption). + Ensure we check the path in *exactly* the same way as W2K for regular pathnames. + No wildcards allowed. ****************************************************************************/ -NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname) +NTSTATUS check_path_syntax(pstring destname, const pstring srcname) { - char *d = destname; - const char *s = srcname; - NTSTATUS ret = NT_STATUS_OK; - BOOL start_of_name_component = True; - - while (*s) { - if (*s == '/') { - /* - * Safe to assume is not the second part of a mb char as this is handled below. - */ - /* Eat multiple '/' or '\\' */ - while (*s == '/') { - s++; - } - if ((d != destname) && (*s != '\0')) { - /* We only care about non-leading or trailing '/' */ - *d++ = '/'; - } - - start_of_name_component = True; - continue; - } - - if (start_of_name_component) { - if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) { - /* Uh oh - "/../" or "/..\0" ! */ - - /* - * No mb char starts with '.' so we're safe checking the directory separator here. - */ - - /* If we just added a '/' - delete it */ - if ((d > destname) && (*(d-1) == '/')) { - *(d-1) = '\0'; - d--; - } + return check_path_syntax_internal(destname, srcname, True, NULL); +} - /* Are we at the start ? Can't go back further if so. */ - if (d <= destname) { - ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; - break; - } - /* Go back one level... */ - /* We know this is safe as '/' cannot be part of a mb sequence. */ - /* NOTE - if this assumption is invalid we are not in good shape... */ - /* Decrement d first as d points to the *next* char to write into. */ - for (d--; d > destname; d--) { - if (*d == '/') - break; - } - s += 2; /* Else go past the .. */ - continue; +/**************************************************************************** + Ensure we check the path in *exactly* the same way as W2K for regular pathnames. + Wildcards allowed - p_contains_wcard returns true if the last component contained + a wildcard. +****************************************************************************/ - } else if ((s[0] == '.') && ((s[1] == '\0') || (s[1] == '/'))) { - /* Eat the '.' */ - s++; - continue; - } - } +NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *p_contains_wcard) +{ + return check_path_syntax_internal(destname, srcname, True, p_contains_wcard); +} - if (!(*s & 0x80)) { - *d++ = *s++; - } else { - size_t siz; - /* Get the size of the next MB character. */ - next_codepoint(s,&siz); - switch(siz) { - case 5: - *d++ = *s++; - /*fall through*/ - case 4: - *d++ = *s++; - /*fall through*/ - case 3: - *d++ = *s++; - /*fall through*/ - case 2: - *d++ = *s++; - /*fall through*/ - case 1: - *d++ = *s++; - break; - default: - DEBUG(0,("check_path_syntax_posix: character length assumptions invalid !\n")); - *d = '\0'; - return NT_STATUS_INVALID_PARAMETER; - } - } - start_of_name_component = False; - } +/**************************************************************************** + Check the path for a POSIX client. + We're assuming here that '/' is not the second byte in any multibyte char + set (a safe assumption). +****************************************************************************/ - *d = '\0'; - return ret; +static NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname) +{ + return check_path_syntax_internal(destname, srcname, False, NULL); } /**************************************************************************** @@ -823,7 +608,6 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size int outsize = 0; pstring name; BOOL ok = False; - BOOL bad_path = False; SMB_STRUCT_STAT sbuf; NTSTATUS status; @@ -845,10 +629,10 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size RESOLVE_DFSPATH(name, conn, inbuf, outbuf); - unix_convert(name,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, name, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBchkpth); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (check_name(name,conn)) { @@ -871,8 +655,7 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size * 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. This is different from set_bad_path_error() - * in the non-NT error case. + * if the path is invalid. */ END_PROFILE(SMBchkpth); return ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpath); @@ -902,7 +685,6 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size int mode=0; SMB_OFF_T size=0; time_t mtime=0; - BOOL bad_path = False; char *p; NTSTATUS status; @@ -927,10 +709,10 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size mtime = 0; ok = True; } else { - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, fname, False, NULL,&sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBgetatr); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (check_name(fname,conn)) { if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,fname,&sbuf) == 0) { @@ -948,7 +730,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (!ok) { END_PROFILE(SMBgetatr); - return UNIXERROR(ERRDOS, ERRbadfile); + return UNIXERROR(ERRDOS,ERRbadfile); } outsize = set_message(outbuf,10,0,True); @@ -982,7 +764,6 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size int mode; time_t mtime; SMB_STRUCT_STAT sbuf; - BOOL bad_path = False; char *p; NTSTATUS status; @@ -997,10 +778,10 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path || !check_name(fname, conn)) { + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBsetatr); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (fname[0] == '.' && fname[1] == '\0') { @@ -1012,6 +793,11 @@ 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)) { + END_PROFILE(SMBsetatr); + return UNIXERROR(ERRDOS, ERRnoaccess); + } + mode = SVAL(inbuf,smb_vwv0); mtime = srv_make_unix_date3(inbuf+smb_vwv1); @@ -1118,7 +904,6 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size BOOL check_descend = False; BOOL expect_close = False; BOOL can_open = True; - BOOL bad_path = False; NTSTATUS nt_status; BOOL mask_contains_wcard = False; BOOL allow_long_path_components = (SVAL(inbuf,smb_flg2) & FLAGS2_LONG_PATH_COMPONENTS) ? True : False; @@ -1160,7 +945,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size pstrcpy(directory,path); pstrcpy(dir2,path); - unix_convert(directory,conn,0,&bad_path,&sbuf); + nt_status = unix_convert(conn, directory, mask_contains_wcard, NULL, &sbuf); + if (!NT_STATUS_IS_OK(nt_status)) { + END_PROFILE(SMBsearch); + return ERROR_NT(nt_status); + } unix_format(dir2); if (!check_name(directory,conn)) @@ -1209,9 +998,6 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (dptr_num < 0) { if(dptr_num == -2) { END_PROFILE(SMBsearch); - if ((errno == ENOENT) && bad_path) { - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); - } return UNIXERROR(ERRDOS, ERRnofids); } END_PROFILE(SMBsearch); @@ -1377,7 +1163,6 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, time_t mtime=0; int info; SMB_STRUCT_STAT sbuf; - BOOL bad_path = False; files_struct *fsp; int oplock_request = CORE_OPLOCK_REQUEST(inbuf); int deny_mode; @@ -1399,10 +1184,10 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBopen); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (!map_open_params_to_ntcreate(fname, deny_mode, OPENX_FILE_EXISTS_OPEN, @@ -1486,7 +1271,6 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt int mtime=0; SMB_STRUCT_STAT sbuf; int smb_action = 0; - BOOL bad_path = False; files_struct *fsp; NTSTATUS status; SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv9); @@ -1518,10 +1302,10 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBopenX); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (!map_open_params_to_ntcreate(fname, deny_mode, smb_ofun, @@ -1667,7 +1451,6 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int outsize = 0; uint32 fattr = SVAL(inbuf,smb_vwv0); struct utimbuf times; - BOOL bad_path = False; files_struct *fsp; int oplock_request = CORE_OPLOCK_REQUEST(inbuf); SMB_STRUCT_STAT sbuf; @@ -1691,10 +1474,10 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBcreate); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (fattr & aVOLID) { @@ -1758,7 +1541,6 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, pstring fname; int outsize = 0; uint32 fattr = SVAL(inbuf,smb_vwv0); - BOOL bad_path = False; files_struct *fsp; int oplock_request = CORE_OPLOCK_REQUEST(inbuf); int tmpfd; @@ -1782,10 +1564,10 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBctemp); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } tmpfd = smb_mkstemp(fname); @@ -1898,12 +1680,12 @@ static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, Check if a user is allowed to delete a file. ********************************************************************/ -static NTSTATUS can_delete(connection_struct *conn, char *fname, - uint32 dirtype, BOOL bad_path) +static NTSTATUS can_delete(connection_struct *conn, char *fname, uint32 dirtype) { SMB_STRUCT_STAT sbuf; uint32 fattr; files_struct *fsp; + uint32 dirtype_orig = dirtype; NTSTATUS status; DEBUG(10,("can_delete: %s, dirtype = %d\n", fname, dirtype )); @@ -1913,22 +1695,56 @@ static NTSTATUS can_delete(connection_struct *conn, char *fname, } if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0) { - if(errno == ENOENT) { - if (bad_path) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } else { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - } return map_nt_error_from_unix(errno); } fattr = dos_mode(conn,fname,&sbuf); + if (dirtype & FILE_ATTRIBUTE_NORMAL) { + dirtype = aDIR|aARCH|aRONLY; + } + + dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM); + if (!dirtype) { + return NT_STATUS_NO_SUCH_FILE; + } + + if (!dir_check_ftype(conn, fattr, dirtype)) { + if (fattr & aDIR) { + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + return NT_STATUS_NO_SUCH_FILE; + } + + if (dirtype_orig & 0x8000) { + /* These will never be set for POSIX. */ + return NT_STATUS_NO_SUCH_FILE; + } + +#if 0 + if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) { + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + + if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) { + return NT_STATUS_NO_SUCH_FILE; + } + + if (dirtype & 0xFF00) { + /* These will never be set for POSIX. */ + return NT_STATUS_NO_SUCH_FILE; + } + + dirtype &= 0xFF; + if (!dirtype) { + return NT_STATUS_NO_SUCH_FILE; + } + /* Can't delete a directory. */ if (fattr & aDIR) { return NT_STATUS_FILE_IS_A_DIRECTORY; } +#endif #if 0 /* JRATEST */ else if (dirtype & aDIR) /* Asked for a directory and it isn't. */ @@ -1952,9 +1768,6 @@ static NTSTATUS can_delete(connection_struct *conn, char *fname, return NT_STATUS_CANNOT_DELETE; } } - if ((fattr & ~dirtype) & (aHIDDEN | aSYSTEM)) { - return NT_STATUS_NO_SUCH_FILE; - } /* On open checks the open itself will check the share mode, so don't do it here as we'll get it wrong. */ @@ -1979,27 +1792,21 @@ static NTSTATUS can_delete(connection_struct *conn, char *fname, code. ****************************************************************************/ -NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, - char *name, BOOL has_wild) +NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, char *name, BOOL has_wild) { pstring directory; pstring mask; - pstring orig_name; char *p; int count=0; - NTSTATUS error = NT_STATUS_OK; - BOOL bad_path = False; - BOOL rc = True; + NTSTATUS status = NT_STATUS_OK; SMB_STRUCT_STAT sbuf; *directory = *mask = 0; - rc = unix_convert(name,conn,0,&bad_path,&sbuf); - - /* - * Feel my pain, this code needs rewriting *very* badly! -- vl - */ - pstrcpy(orig_name, name); + status = unix_convert(conn, name, has_wild, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + return status; + } p = strrchr_m(name,'/'); if (!p) { @@ -2020,33 +1827,28 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, * Tine Smukavec <valentin.smukavec@hermes.si>. */ - if (!rc && mangle_is_mangled(mask,conn->params)) + if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params)) mangle_check_cache( mask, sizeof(pstring)-1, conn->params ); if (!has_wild) { pstrcat(directory,"/"); pstrcat(directory,mask); - error = can_delete(conn,directory,dirtype,bad_path); - if (!NT_STATUS_IS_OK(error)) - return error; + if (dirtype == 0) { + dirtype = FILE_ATTRIBUTE_NORMAL; + } + status = can_delete(conn,directory,dirtype); + if (!NT_STATUS_IS_OK(status)) + return status; if (SMB_VFS_UNLINK(conn,directory) == 0) { count++; } - } else { struct smb_Dir *dir_hnd = NULL; const char *dname; - /* Ensure we check bad_path in the wcard case. - * This may not be correct w.r.t. Windows (needs - * smbtorture test cases which will be forthcoming) - * but prevents us from continuing in the obvious - * bad path case. This is merely a placeholder. JRA. - */ - - if (!rc && bad_path) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; + if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) { + return NT_STATUS_OBJECT_NAME_INVALID; } if (strequal(mask,"????????.???")) @@ -2062,12 +1864,11 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, if (dir_hnd) { long offset = 0; - error = NT_STATUS_NO_SUCH_FILE; + status = NT_STATUS_NO_SUCH_FILE; while ((dname = ReadDirName(dir_hnd, &offset))) { SMB_STRUCT_STAT st; pstring fname; - BOOL sys_direntry = False; pstrcpy(fname,dname); if (!is_visible_file(conn, directory, dname, &st, True)) { @@ -2077,44 +1878,31 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, /* Quick check for "." and ".." */ if (fname[0] == '.') { if (!fname[1] || (fname[1] == '.' && !fname[2])) { - if (dirtype & FILE_ATTRIBUTE_DIRECTORY) { - sys_direntry = True; - } else { - continue; - } + continue; } } if(!mask_match(fname, mask, conn->case_sensitive)) continue; - if (sys_direntry) { - error = NT_STATUS_OBJECT_NAME_INVALID; - DEBUG(3,("unlink_internals: system directory delete denied [%s] mask [%s]\n", - fname, mask)); - break; - } - slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); - error = can_delete(conn, fname, dirtype, - bad_path); - if (!NT_STATUS_IS_OK(error)) { + status = can_delete(conn, fname, dirtype); + if (!NT_STATUS_IS_OK(status)) { continue; } - if (SMB_VFS_UNLINK(conn,fname) == 0) { + 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(error)) { - error = map_nt_error_from_unix(errno); + if (count == 0 && NT_STATUS_IS_OK(status)) { + status = map_nt_error_from_unix(errno); } - return error; + return status; } /**************************************************************************** @@ -3774,7 +3562,6 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, pstring directory; int outsize; NTSTATUS status; - BOOL bad_path = False; SMB_STRUCT_STAT sbuf; START_PROFILE(SMBmkdir); @@ -3787,10 +3574,10 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(directory, conn, inbuf, outbuf); - unix_convert(directory,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, directory, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBmkdir); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } status = create_directory(conn, directory); @@ -3939,7 +3726,7 @@ BOOL rmdir_internals(connection_struct *conn, const char *directory) pstrcpy(fullname, directory); pstrcat(fullname, "/"); pstrcat(fullname, dname); - + if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) break; if(st.st_mode & S_IFDIR) { @@ -3977,7 +3764,6 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, pstring directory; int outsize = 0; BOOL ok = False; - BOOL bad_path = False; SMB_STRUCT_STAT sbuf; NTSTATUS status; START_PROFILE(SMBrmdir); @@ -3990,10 +3776,10 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(directory, conn, inbuf, outbuf) - unix_convert(directory,conn, NULL,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, directory, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBrmdir); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (check_name(directory,conn)) { @@ -4171,24 +3957,16 @@ static BOOL rename_path_prefix_equal(const char *src, const char *dest) NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *newname, uint32 attrs, BOOL replace_if_exists) { SMB_STRUCT_STAT sbuf; - BOOL bad_path = False; pstring newname_last_component; - NTSTATUS error = NT_STATUS_OK; + NTSTATUS status = NT_STATUS_OK; BOOL dest_exists; - BOOL rcdest = True; struct share_mode_lock *lck = NULL; ZERO_STRUCT(sbuf); - rcdest = unix_convert(newname,conn,newname_last_component,&bad_path,&sbuf); - /* Quick check for "." and ".." */ - if (!bad_path && newname_last_component[0] == '.') { - if (!newname_last_component[1] || (newname_last_component[1] == '.' && !newname_last_component[2])) { - return NT_STATUS_ACCESS_DENIED; - } - } - if (!rcdest && bad_path) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; + status = unix_convert(conn, newname, False, newname_last_component, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* Ensure newname contains a '/' */ @@ -4250,14 +4028,14 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char * return NT_STATUS_OBJECT_NAME_COLLISION; } - error = can_rename(conn,newname,attrs,&sbuf); + status = can_rename(conn,newname,attrs,&sbuf); - if (dest_exists && !NT_STATUS_IS_OK(error)) { + if (dest_exists && !NT_STATUS_IS_OK(status)) { DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(error), fsp->fsp_name,newname)); - if (NT_STATUS_EQUAL(error,NT_STATUS_SHARING_VIOLATION)) - error = NT_STATUS_ACCESS_DENIED; - return error; + nt_errstr(status), fsp->fsp_name,newname)); + if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) + status = NT_STATUS_ACCESS_DENIED; + return status; } if (rename_path_prefix_equal(fsp->fsp_name, newname)) { @@ -4277,15 +4055,15 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char * TALLOC_FREE(lck); if (errno == ENOTDIR || errno == EISDIR) { - error = NT_STATUS_OBJECT_NAME_COLLISION; + status = NT_STATUS_OBJECT_NAME_COLLISION; } else { - error = map_nt_error_from_unix(errno); + status = map_nt_error_from_unix(errno); } DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n", - nt_errstr(error), fsp->fsp_name,newname)); + nt_errstr(status), fsp->fsp_name,newname)); - return error; + return status; } /**************************************************************************** @@ -4300,12 +4078,8 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui pstring last_component_src; pstring last_component_dest; char *p; - BOOL bad_path_src = False; - BOOL bad_path_dest = False; int count=0; - NTSTATUS error = NT_STATUS_OK; - BOOL rc = True; - BOOL rcdest = True; + NTSTATUS status = NT_STATUS_OK; SMB_STRUCT_STAT sbuf1, sbuf2; struct share_mode_lock *lck = NULL; @@ -4314,27 +4088,14 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui ZERO_STRUCT(sbuf1); ZERO_STRUCT(sbuf2); - rc = unix_convert(name,conn,last_component_src,&bad_path_src,&sbuf1); - if (!rc && bad_path_src) { - if (ms_has_wild(last_component_src)) - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - - /* Quick check for "." and ".." */ - if (last_component_src[0] == '.') { - if (!last_component_src[1] || (last_component_src[1] == '.' && !last_component_src[2])) { - return NT_STATUS_OBJECT_NAME_INVALID; - } + status = unix_convert(conn, name, has_wild, last_component_src, &sbuf1); + if (!NT_STATUS_IS_OK(status)) { + return status; } - rcdest = unix_convert(newname,conn,last_component_dest,&bad_path_dest,&sbuf2); - - /* Quick check for "." and ".." */ - if (last_component_dest[0] == '.') { - if (!last_component_dest[1] || (last_component_dest[1] == '.' && !last_component_dest[2])) { - return NT_STATUS_OBJECT_NAME_INVALID; - } + status = unix_convert(conn, newname, True, last_component_dest, &sbuf2); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* @@ -4366,7 +4127,7 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui * Tine Smukavec <valentin.smukavec@hermes.si>. */ - if (!rc && mangle_is_mangled(mask, conn->params)) + if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) mangle_check_cache( mask, sizeof(pstring)-1, conn->params ); if (!has_wild) { @@ -4451,25 +4212,19 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", return NT_STATUS_OBJECT_NAME_NOT_FOUND; return NT_STATUS_OBJECT_PATH_NOT_FOUND; } - error = map_nt_error_from_unix(errno); + status = map_nt_error_from_unix(errno); DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(error), directory,newname)); - - return error; - } + nt_errstr(status), directory,newname)); - if (!rcdest && bad_path_dest) { - if (ms_has_wild(last_component_dest)) - return NT_STATUS_OBJECT_NAME_INVALID; - return NT_STATUS_OBJECT_PATH_NOT_FOUND; + return status; } - error = can_rename(conn,directory,attrs,&sbuf1); + status = can_rename(conn,directory,attrs,&sbuf1); - if (!NT_STATUS_IS_OK(error)) { + if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(error), directory,newname)); - return error; + nt_errstr(status), directory,newname)); + return status; } /* @@ -4505,14 +4260,14 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", TALLOC_FREE(lck); if (errno == ENOTDIR || errno == EISDIR) - error = NT_STATUS_OBJECT_NAME_COLLISION; + status = NT_STATUS_OBJECT_NAME_COLLISION; else - error = map_nt_error_from_unix(errno); + status = map_nt_error_from_unix(errno); DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(error), directory,newname)); + nt_errstr(status), directory,newname)); - return error; + return status; } else { /* * Wildcards - process each file that matches. @@ -4529,8 +4284,8 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", if (dir_hnd) { long offset = 0; - error = NT_STATUS_NO_SUCH_FILE; -/* Was error = 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; @@ -4556,19 +4311,19 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", continue; if (sysdir_entry) { - error = NT_STATUS_OBJECT_NAME_INVALID; + status = NT_STATUS_OBJECT_NAME_INVALID; break; } - error = NT_STATUS_ACCESS_DENIED; + status = NT_STATUS_ACCESS_DENIED; slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname); if (!vfs_object_exist(conn, fname, &sbuf1)) { - error = NT_STATUS_OBJECT_NAME_NOT_FOUND; - DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(error))); + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(status))); continue; } - error = can_rename(conn,fname,attrs,&sbuf1); - if (!NT_STATUS_IS_OK(error)) { + status = can_rename(conn,fname,attrs,&sbuf1); + if (!NT_STATUS_IS_OK(status)) { DEBUG(6,("rename %s refused\n", fname)); continue; } @@ -4584,14 +4339,14 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", 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++; - error = NT_STATUS_OK; + status = NT_STATUS_OK; continue; } if (!replace_if_exists && vfs_file_exist(conn,destname, NULL)) { DEBUG(6,("file_exist %s\n", destname)); - error = NT_STATUS_OBJECT_NAME_COLLISION; + status = NT_STATUS_OBJECT_NAME_COLLISION; continue; } @@ -4604,7 +4359,7 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", if (!SMB_VFS_RENAME(conn,fname,destname)) { rename_open_files(conn, lck, sbuf1.st_dev, sbuf1.st_ino, newname); count++; - error = NT_STATUS_OK; + status = NT_STATUS_OK; } TALLOC_FREE(lck); DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname)); @@ -4612,6 +4367,8 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", CloseDir(dir_hnd); } +#if 0 + /* Don't think needed any more - JRA. */ if (!NT_STATUS_EQUAL(error,NT_STATUS_NO_SUCH_FILE)) { if (!rcdest && bad_path_dest) { if (ms_has_wild(last_component_dest)) @@ -4619,13 +4376,15 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", return NT_STATUS_OBJECT_PATH_NOT_FOUND; } } +#endif + } - if (count == 0 && NT_STATUS_IS_OK(error)) { - error = map_nt_error_from_unix(errno); + if (count == 0 && NT_STATUS_IS_OK(status)) { + status = map_nt_error_from_unix(errno); } - return error; + return status; } /**************************************************************************** @@ -4821,11 +4580,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int ofun = SVAL(inbuf,smb_vwv1); int flags = SVAL(inbuf,smb_vwv2); BOOL target_is_directory=False; - BOOL bad_path1 = False; - BOOL bad_path2 = False; BOOL path_contains_wcard1 = False; BOOL path_contains_wcard2 = False; - BOOL rc = True; SMB_STRUCT_STAT sbuf1, sbuf2; NTSTATUS status; START_PROFILE(SMBcopy); @@ -4856,8 +4612,17 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf); RESOLVE_DFSPATH_WCARD(newname, conn, inbuf, outbuf); - rc = unix_convert(name,conn,0,&bad_path1,&sbuf1); - unix_convert(newname,conn,0,&bad_path2,&sbuf2); + status = unix_convert(conn, name, path_contains_wcard1, NULL, &sbuf1); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBcopy); + return ERROR_NT(status); + } + + status = unix_convert(conn, newname, path_contains_wcard2, NULL, &sbuf2); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBcopy); + return ERROR_NT(status); + } target_is_directory = VALID_STAT_OF_DIR(sbuf2); @@ -4897,7 +4662,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, * Tine Smukavec <valentin.smukavec@hermes.si>. */ - if (!rc && mangle_is_mangled(mask, conn->params)) + if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) mangle_check_cache( mask, sizeof(pstring)-1, conn->params ); has_wild = path_contains_wcard1; @@ -4964,20 +4729,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return(UNIXERROR(ERRHRD,ERRgeneral)); } - if (exists) { - END_PROFILE(SMBcopy); - return ERROR_DOS(ERRDOS,error); - } else { - if((errno == ENOENT) && (bad_path1 || bad_path2) && - !use_nt_status()) { - /* Samba 3.0.22 has ERRDOS/ERRbadpath in the - * DOS error code case - */ - return ERROR_DOS(ERRDOS, ERRbadpath); - } - END_PROFILE(SMBcopy); - return(UNIXERROR(ERRDOS,error)); - } + END_PROFILE(SMBcopy); + return ERROR_DOS(ERRDOS,error); } outsize = set_message(outbuf,1,0,True); diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 40394c3d8a..2cfb692b02 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -751,7 +751,6 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i SMB_INO_T inode = 0; SMB_STRUCT_STAT sbuf; int smb_action = 0; - BOOL bad_path = False; files_struct *fsp; struct ea_list *ea_list = NULL; uint16 flags = 0; @@ -801,13 +800,13 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i /* XXXX we need to handle passed times, sattr and flags */ - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + return ERROR_NT(status); } if (!check_name(fname,conn)) { - return UNIXERROR(ERRDOS, ERRnoaccess); + return UNIXERROR(ERRDOS,ERRnoaccess); } if (open_ofun == 0) { @@ -1662,7 +1661,6 @@ static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outb BOOL dont_descend = False; BOOL out_of_space = False; int space_remaining; - BOOL bad_path = False; BOOL mask_contains_wcard = False; SMB_STRUCT_STAT sbuf; TALLOC_CTX *ea_ctx = NULL; @@ -1720,12 +1718,12 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", RESOLVE_DFSPATH_WCARD(directory, conn, inbuf, outbuf); - unix_convert(directory,conn,0,&bad_path,&sbuf); - if (bad_path) { - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + ntstatus = unix_convert(conn, directory, mask_contains_wcard, NULL, &sbuf); + if (!NT_STATUS_IS_OK(ntstatus)) { + return ERROR_NT(ntstatus); } if(!check_name(directory,conn)) { - return UNIXERROR(ERRDOS, ERRbadpath); + return UNIXERROR(ERRDOS,ERRbadpath); } p = strrchr_m(directory,'/'); @@ -2844,7 +2842,6 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * char *base_name; char *p; SMB_OFF_T pos = 0; - BOOL bad_path = False; BOOL delete_pending = False; int len; time_t create_time, mtime, atime; @@ -2891,11 +2888,11 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * /* Always do lstat for UNIX calls. */ if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); - return UNIXERROR(ERRDOS, ERRbadpath); + return UNIXERROR(ERRDOS,ERRbadpath); } } else if (SMB_VFS_STAT(conn,fname,&sbuf)) { DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); - return UNIXERROR(ERRDOS, ERRbadpath); + return UNIXERROR(ERRDOS,ERRbadpath); } delete_pending = get_delete_on_close_flag(sbuf.st_dev, sbuf.st_ino); @@ -2933,24 +2930,24 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + status = unix_convert(conn, fname, False, NULL, &sbuf); + 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); + return UNIXERROR(ERRDOS,ERRbadpath); } if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); - return UNIXERROR(ERRDOS, ERRbadpath); + return UNIXERROR(ERRDOS,ERRbadpath); } } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf) && (info_level != SMB_INFO_IS_NAME_VALID)) { DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); - return UNIXERROR(ERRDOS, ERRbadpath); + return UNIXERROR(ERRDOS,ERRbadpath); } delete_pending = get_delete_on_close_flag(sbuf.st_dev, sbuf.st_ino); @@ -3671,8 +3668,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newname) { - BOOL bad_path_oldname = False; - BOOL bad_path_newname = False; SMB_STRUCT_STAT sbuf1, sbuf2; pstring last_component_oldname; pstring last_component_newname; @@ -3681,21 +3676,9 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam ZERO_STRUCT(sbuf1); ZERO_STRUCT(sbuf2); - /* No wildcards. */ - if (ms_has_wild(newname) || ms_has_wild(oldname)) { - return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; - } - - unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1); - if (bad_path_oldname) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - - /* Quick check for "." and ".." */ - if (last_component_oldname[0] == '.') { - if (!last_component_oldname[1] || (last_component_oldname[1] == '.' && !last_component_oldname[2])) { - return NT_STATUS_OBJECT_NAME_INVALID; - } + status = unix_convert(conn, oldname, False, last_component_oldname, &sbuf1); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* source must already exist. */ @@ -3707,16 +3690,9 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam return NT_STATUS_ACCESS_DENIED; } - unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2); - if (bad_path_newname) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - - /* Quick check for "." and ".." */ - if (last_component_newname[0] == '.') { - if (!last_component_newname[1] || (last_component_newname[1] == '.' && !last_component_newname[2])) { - return NT_STATUS_OBJECT_NAME_INVALID; - } + status = unix_convert(conn, newname, False, last_component_newname, &sbuf2); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* Disallow if newname already exists. */ @@ -3766,7 +3742,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char SMB_STRUCT_STAT sbuf; pstring fname; int fd = -1; - BOOL bad_path = False; files_struct *fsp = NULL; uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE; gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE; @@ -3796,7 +3771,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char pstrcpy(fname, fsp->fsp_name); if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) { DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno))); - return UNIXERROR(ERRDOS, ERRbadpath); + return UNIXERROR(ERRDOS,ERRbadpath); } } else if (fsp && fsp->print_file) { /* @@ -3837,9 +3812,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + return ERROR_NT(status); } /* @@ -3848,11 +3823,11 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char if(!VALID_STAT(sbuf) && !INFO_LEVEL_IS_UNIX(info_level)) { DEBUG(3,("call_trans2setfilepathinfo: stat of %s failed (%s)\n", fname, strerror(errno))); - return UNIXERROR(ERRDOS, ERRbadpath); + return UNIXERROR(ERRDOS,ERRbadpath); } if(!check_name(fname, conn)) { - return UNIXERROR(ERRDOS, ERRbadpath); + return UNIXERROR(ERRDOS,ERRbadpath); } } @@ -4789,7 +4764,6 @@ static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, char *pdata = *ppdata; pstring directory; SMB_STRUCT_STAT sbuf; - BOOL bad_path = False; NTSTATUS status = NT_STATUS_OK; struct ea_list *ea_list = NULL; @@ -4807,9 +4781,9 @@ static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); - unix_convert(directory,conn,0,&bad_path,&sbuf); - if (bad_path) { - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + status = unix_convert(conn, directory, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + return ERROR_NT(status); } /* Any data in this call is an EA list. */ |