r20718: Sync up the filename path parsing changes from SAMBA_3_0_24.
authorJeremy Allison <jra@samba.org>
Fri, 12 Jan 2007 23:47:16 +0000 (23:47 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:17:04 +0000 (12:17 -0500)
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)

source3/printing/nt_printing.c
source3/rpc_server/srv_srvsvc_nt.c
source3/smbd/dosmode.c
source3/smbd/filename.c
source3/smbd/msdfs.c
source3/smbd/nttrans.c
source3/smbd/reply.c
source3/smbd/trans2.c

index 5fa5db54e4bf7b7d5f47a4f2559e6ab2f68eada3..8f264bfd1e69afdeafef8dd921e45307c575b75a 100644 (file)
@@ -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);
                        }
index abfa794518c00504d5b5d6a32f1abf394bf54f39..646a414cdad603cf49989e1ebcbc893d47c4bf19 100644 (file)
@@ -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;
index 1172fe3e6b55fe0747f632413e3a41d2483e8d5d..ff4291c08c8183e860d73066f62a5b159cb2c769 100644 (file)
@@ -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)) {
index 1ea5228e919d8dfb880ef1f52503cbbcb7033780..3f02f6090fae9f47d40ac4af46ce9cf3c41c0fa4 100644 (file)
@@ -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;
 }
 
 /****************************************************************************
index 12fd333efefdbc2eaf846326dbc9a5514b25cace..42595c033edcf20fa87314a9ac138654d075149e 100644 (file)
@@ -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);
 
index 3e64cdc2d2656c203be9bac7caeb2a55cb6d58cd..94bf363fc734a9a28af32c7acbd3775a2afc1618 100644 (file)
@@ -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. */
index b3df8acf1156ba428c94f4e9321703446ca6f999..5914a3b169e0b6d25155877720b6877de6d79991 100644 (file)
@@ -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
@@ -36,143 +36,6 @@ extern uint32 global_client_caps;
 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.
@@ -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);
index 40394c3d8af7e78b1838a7c94fa0af4dce77c3de..2cfb692b024968771cc70e36486fc2c794761f16 100644 (file)
@@ -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. */