r1115: Fix for #1427. Catch bad path errors at the right point. Ensure all
authorJeremy Allison <jra@samba.org>
Fri, 11 Jun 2004 17:54:23 +0000 (17:54 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:51:56 +0000 (10:51 -0500)
our pathname parsing is consistent.
Jeremy.
(This used to be commit 5e8237e306f0bb0e492f10fb6487938132899384)

source3/libsmb/smb_signing.c
source3/rpc_server/srv_srvsvc_nt.c
source3/smbd/filename.c
source3/smbd/msdfs.c
source3/smbd/nttrans.c
source3/smbd/reply.c
source3/smbd/trans2.c
source3/smbd/vfs.c

index 7130453c0c9bc0964b9fe46790b82bba381c4d25..63838e6933e68d44d48a08531877e322125020e1 100644 (file)
@@ -748,11 +748,11 @@ static BOOL srv_check_incoming_message(char *inbuf, struct smb_sign_info *si, BO
        
        if (!good) {
 
-               DEBUG(5, ("srv_check_incoming_message: BAD SIG: seq %u wanted SMB signature of\n",
+               DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u wanted SMB signature of\n",
                                        (unsigned int)saved_seq));
                dump_data(5, (const char *)calc_md5_mac, 8);
                
-               DEBUG(5, ("srv_check_incoming_message: BAD SIG: seq %u got SMB signature of\n",
+               DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u got SMB signature of\n",
                                        (unsigned int)saved_seq));
                dump_data(5, (const char *)server_sent_mac, 8);
 
index 087c50451e5d5c42ca597df0f2c346b667d9d042..54cc0d616180e91b25cc0cf5b66b94bed7b92801 100644 (file)
@@ -1886,6 +1886,18 @@ WERROR _srv_net_file_query_secdesc(pipes_struct *p, SRV_Q_NET_FILE_QUERY_SECDESC
 
        unistr2_to_ascii(filename, &q_u->uni_file_name, sizeof(filename));
        unix_convert(filename, conn, NULL, &bad_path, &st);
+       if (bad_path) {
+               DEBUG(3,("_srv_net_file_query_secdesc: bad pathname %s\n", filename));
+               r_u->status = WERR_ACCESS_DENIED;
+               goto error_exit;
+       }
+
+       if (!check_name(filename,conn)) {
+               DEBUG(3,("_srv_net_file_query_secdesc: can't access %s\n", filename));
+               r_u->status = WERR_ACCESS_DENIED;
+               goto error_exit;
+       }
+
        fsp = open_file_shared(conn, filename, &st, SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
                                (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY,
                                &access_mode, &action);
@@ -1990,6 +2002,18 @@ WERROR _srv_net_file_set_secdesc(pipes_struct *p, SRV_Q_NET_FILE_SET_SECDESC *q_
 
        unistr2_to_ascii(filename, &q_u->uni_file_name, sizeof(filename));
        unix_convert(filename, conn, NULL, &bad_path, &st);
+       if (bad_path) {
+               DEBUG(3,("_srv_net_file_set_secdesc: bad pathname %s\n", filename));
+               r_u->status = WERR_ACCESS_DENIED;
+               goto error_exit;
+       }
+
+       if (!check_name(filename,conn)) {
+               DEBUG(3,("_srv_net_file_set_secdesc: can't access %s\n", filename));
+               r_u->status = WERR_ACCESS_DENIED;
+               goto error_exit;
+       }
+
 
        fsp = open_file_shared(conn, filename, &st, SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDWR),
                        (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY,
index 67329b51e6f89c0bd4b79af58971bd027af5fe8b..ab75d9c06aec989442d7a28fcf0a66d088b9d492 100644 (file)
@@ -237,6 +237,15 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen
                                 */
                                DEBUG(5,("Not a dir %s\n",start));
                                *end = '/';
+                               /* 
+                                * We need to return the fact that the intermediate
+                                * name resolution failed. This is used to return an
+                                * error of ERRbadpath rather than ERRbadfile. Some
+                                * Windows applications depend on the difference between
+                                * these two errors.
+                                */
+                               errno = ENOTDIR;
+                               *bad_path = True;
                                return(False);
                        }
 
@@ -265,6 +274,9 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen
                        if (end)
                                pstrcpy(rest,end+1);
 
+                       /* Reset errno so we can detect directory open errors. */
+                       errno = 0;
+
                        /*
                         * Try to find this part of the path in the directory.
                         */
@@ -292,6 +304,11 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen
                                        return(False);
                                }
              
+                               if (errno == ENOTDIR) {
+                                       *bad_path = True;
+                                       return(False);
+                               }
+
                                /* 
                                 * Just the last part of the name doesn't exist.
                                 * We may need to strupper() or strlower() it in case
@@ -392,12 +409,11 @@ BOOL check_name(pstring name,connection_struct *conn)
 {
        BOOL ret = True;
 
-       errno = 0;
-
        if (IS_VETO_PATH(conn, name))  {
                /* Is it not dot or dot dot. */
                if (!((name[0] == '.') && (!name[1] || (name[1] == '.' && !name[2])))) {
                        DEBUG(5,("file path name %s vetoed\n",name));
+                       errno = ENOENT;
                        return False;
                }
        }
@@ -416,13 +432,15 @@ BOOL check_name(pstring name,connection_struct *conn)
                if ( (SMB_VFS_LSTAT(conn,name,&statbuf) != -1) &&
                                (S_ISLNK(statbuf.st_mode)) ) {
                        DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name));
+                       errno = EACCES;
                        ret = False; 
                }
        }
 #endif
 
-       if (!ret)
+       if (!ret) {
                DEBUG(5,("check_name on %s failed\n",name));
+       }
 
        return(ret);
 }
@@ -496,5 +514,6 @@ static BOOL scan_directory(const char *path, char *name, size_t maxlength,
        }
 
        CloseDir(cur_dir);
+       errno = ENOENT;
        return(False);
 }
index c66f0477a84073b2ea02dd01a01f8d5e4a12508b..6c132897f982c1ec0b52b124eb2783736a5a72db 100644 (file)
@@ -65,7 +65,7 @@ static BOOL parse_dfs_path(char* pathname, struct dfs_path* pdp)
        DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
 
        /* rest is reqpath */
-       check_path_syntax(pdp->reqpath, p+1);
+       check_path_syntax(pdp->reqpath, p+1,True);
 
        DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
        return True;
@@ -111,7 +111,7 @@ static BOOL parse_processed_dfs_path(char* pathname, struct dfs_path* pdp)
        DEBUG(10,("parse_processed_dfs_path: servicename: %s\n",pdp->servicename));
 
        /* rest is reqpath */
-       check_path_syntax(pdp->reqpath, p+1);
+       check_path_syntax(pdp->reqpath, p+1,True);
 
        DEBUG(10,("parse_processed_dfs_path: rest of the path: %s\n",pdp->reqpath));
        return True;
index 25ed08650afb5ee66f2ec4844777822bcd509d45..2f498b7c94a624d935280f7508c64bb21d225fa9 100644 (file)
@@ -651,7 +651,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
 
                if(!dir_fsp->is_directory) {
 
-                       srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status);
+                       srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status,False);
                        if (!NT_STATUS_IS_OK(status)) {
                                END_PROFILE(SMBntcreateX);
                                return ERROR_NT(status);
@@ -693,14 +693,14 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
                        dir_name_len++;
                }
 
-               srvstr_get_path(inbuf, rel_fname, smb_buf(inbuf), sizeof(rel_fname), 0, STR_TERMINATE, &status);
+               srvstr_get_path(inbuf, rel_fname, smb_buf(inbuf), sizeof(rel_fname), 0, STR_TERMINATE, &status,False);
                if (!NT_STATUS_IS_OK(status)) {
                        END_PROFILE(SMBntcreateX);
                        return ERROR_NT(status);
                }
                pstrcat(fname, rel_fname);
        } else {
-               srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status);
+               srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status,False);
                if (!NT_STATUS_IS_OK(status)) {
                        END_PROFILE(SMBntcreateX);
                        return ERROR_NT(status);
@@ -762,7 +762,18 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
        set_posix_case_semantics(conn, file_attributes);
                
        unix_convert(fname,conn,0,&bad_path,&sbuf);
-               
+       if (bad_path) {
+               restore_case_semantics(conn, file_attributes);
+               END_PROFILE(SMBntcreateX);
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
+       /* All file access must go through check_name() */
+       if (!check_name(fname,conn)) {
+               restore_case_semantics(conn, file_attributes);
+               END_PROFILE(SMBntcreateX);
+               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
+       }
+
        /* 
         * If it's a request for a directory open, deal with it separately.
         */
@@ -1015,7 +1026,7 @@ static int do_nt_transact_create_pipe( connection_struct *conn, char *inbuf, cha
                return ERROR_DOS(ERRDOS,ERRnoaccess);
        }
 
-       srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                return ERROR_NT(status);
        }
@@ -1218,7 +1229,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
                        return ERROR_DOS(ERRDOS,ERRbadfid);
 
                if(!dir_fsp->is_directory) {
-                       srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status);
+                       srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status, False);
                        if (!NT_STATUS_IS_OK(status)) {
                                return ERROR_NT(status);
                        }
@@ -1251,14 +1262,14 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
 
                {
                        pstring tmpname;
-                       srvstr_get_path(inbuf, tmpname, params+53, sizeof(tmpname), parameter_count-53, STR_TERMINATE, &status);
+                       srvstr_get_path(inbuf, tmpname, params+53, sizeof(tmpname), parameter_count-53, STR_TERMINATE, &status, False);
                        if (!NT_STATUS_IS_OK(status)) {
                                return ERROR_NT(status);
                        }
                        pstrcat(fname, tmpname);
                }
        } else {
-               srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status);
+               srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status, False);
                if (!NT_STATUS_IS_OK(status)) {
                        return ERROR_NT(status);
                }
@@ -1292,6 +1303,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) {
+               restore_case_semantics(conn, file_attributes);
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
+       /* All file access must go through check_name() */
+       if (!check_name(fname,conn)) {
+               restore_case_semantics(conn, file_attributes);
+               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
+       }
     
        /*
         * If it's a request for a directory open, deal with it separately.
@@ -1523,7 +1543,7 @@ int reply_ntrename(connection_struct *conn,
        }
 
        p = smb_buf(inbuf) + 1;
-       p += srvstr_get_path(inbuf, oldname, p, sizeof(oldname), 0, STR_TERMINATE, &status);
+       p += srvstr_get_path(inbuf, oldname, p, sizeof(oldname), 0, STR_TERMINATE, &status, True);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBntrename);
                return ERROR_NT(status);
@@ -1536,7 +1556,7 @@ int reply_ntrename(connection_struct *conn,
        }
 
        p++;
-       p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status);
+       p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, True);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBntrename);
                return ERROR_NT(status);
@@ -1640,7 +1660,7 @@ static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *o
        fsp = file_fsp(params, 0);
        replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False;
        CHECK_FSP(fsp, conn);
-       srvstr_get_path(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE, &status, True);
        if (!NT_STATUS_IS_OK(status)) {
                return ERROR_NT(status);
        }
index 5b30fe5b7551be18f3fd1fc8b7df77c808636298..961f4d7f55051ff37ceee6348a5ab873caf79d6a 100644 (file)
@@ -43,7 +43,7 @@ extern BOOL global_encrypted_passwords_negotiated;
  set.
 ****************************************************************************/
 
-NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
+NTSTATUS check_path_syntax(pstring destname, const pstring srcname, BOOL allow_wcard_names)
 {
        char *d = destname;
        const char *s = srcname;
@@ -119,7 +119,21 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
                        s++;
                } else {
                        if (!(*s & 0x80)) {
-                               *d++ = *s++;
+                               if (allow_wcard_names) {
+                                       *d++ = *s++;
+                               } else {
+                                       switch (*s) {
+                                               case '*':
+                                               case '?':
+                                               case '<':
+                                               case '>':
+                                               case '"':
+                                                       return NT_STATUS_OBJECT_NAME_INVALID;
+                                               default:
+                                                       *d++ = *s++;
+                                                       break;
+                                       }
+                               }
                        } else {
                                switch(next_mb_char_size(s)) {
                                        case 4:
@@ -147,7 +161,7 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
  Pull a string and check the path - provide for error return.
 ****************************************************************************/
 
-size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags, NTSTATUS *err)
+size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags, NTSTATUS *err, BOOL allow_wcard_names)
 {
        pstring tmppath;
        char *tmppath_ptr = tmppath;
@@ -161,7 +175,7 @@ size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len
        } else {
                ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags);
        }
-       *err = check_path_syntax(dest, tmppath);
+       *err = check_path_syntax(dest, tmppath, allow_wcard_names);
        return ret;
 }
 
@@ -516,7 +530,7 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 
        START_PROFILE(SMBchkpth);
 
-       srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBchkpth);
                return ERROR_NT(status);
@@ -525,6 +539,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) {
+               END_PROFILE(SMBchkpth);
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
 
        mode = SVAL(inbuf,smb_vwv0);
 
@@ -548,18 +566,11 @@ 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.
+                        * if the path is invalid. This is different from set_bad_path_error()
+                        * in the non-NT error case.
                         */
-                       if (bad_path) {
-                               END_PROFILE(SMBchkpth);
-                               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
-                       } else {
-                               END_PROFILE(SMBchkpth);
-                               return ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpath);
-                       }
-               } else if (errno == ENOTDIR) {
                        END_PROFILE(SMBchkpth);
-                       return ERROR_NT(NT_STATUS_NOT_A_DIRECTORY);
+                       return ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpath);
                }
 
                END_PROFILE(SMBchkpth);
@@ -594,7 +605,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        START_PROFILE(SMBgetatr);
 
        p = smb_buf(inbuf) + 1;
-       p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status);
+       p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBgetatr);
                return ERROR_NT(status);
@@ -613,6 +624,10 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                ok = True;
        } else {
                unix_convert(fname,conn,0,&bad_path,&sbuf);
+               if (bad_path) {
+                       END_PROFILE(SMBgetatr);
+                       return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               }
                if (check_name(fname,conn)) {
                        if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,fname,&sbuf) == 0) {
                                mode = dos_mode(conn,fname,&sbuf);
@@ -669,13 +684,17 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        START_PROFILE(SMBsetatr);
 
        p = smb_buf(inbuf) + 1;
-       p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status);
+       p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBsetatr);
                return ERROR_NT(status);
        }
 
        unix_convert(fname,conn,0,&bad_path,&sbuf);
+       if (bad_path) {
+               END_PROFILE(SMBsetatr);
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
 
        mode = SVAL(inbuf,smb_vwv0);
        mtime = make_unix_date3(inbuf+smb_vwv1);
@@ -798,7 +817,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        maxentries = SVAL(inbuf,smb_vwv0); 
        dirtype = SVAL(inbuf,smb_vwv1);
        p = smb_buf(inbuf) + 1;
-       p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &nt_status);
+       p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &nt_status, True);
        if (!NT_STATUS_IS_OK(nt_status)) {
                END_PROFILE(SMBsearch);
                return ERROR_NT(nt_status);
@@ -976,7 +995,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 
        outsize = set_message(outbuf,1,0,True);
        p = smb_buf(inbuf) + 1;
-       p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &err);
+       p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &err, True);
        if (!NT_STATUS_IS_OK(err)) {
                END_PROFILE(SMBfclose);
                return ERROR_NT(err);
@@ -1028,7 +1047,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
  
        share_mode = SVAL(inbuf,smb_vwv0);
 
-       srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBopen);
                return ERROR_NT(status);
@@ -1037,6 +1056,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) {
+               END_PROFILE(SMBopen);
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
     
        fsp = open_file_shared(conn,fname,&sbuf,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
                        (uint32)dos_attr, oplock_request,&rmode,NULL);
@@ -1122,7 +1145,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        }
 
        /* XXXX we need to handle passed times, sattr and flags */
-       srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBopenX);
                return ERROR_NT(status);
@@ -1131,6 +1154,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) {
+               END_PROFILE(SMBopenX);
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
     
        fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,(uint32)smb_attr,
                        oplock_request, &rmode,&smb_action);
@@ -1240,7 +1267,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        com = SVAL(inbuf,smb_com);
 
        createmode = SVAL(inbuf,smb_vwv0);
-       srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBcreate);
                return ERROR_NT(status);
@@ -1249,6 +1276,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) {
+               END_PROFILE(SMBcreate);
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
 
        if (createmode & aVOLID)
                DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
@@ -1312,7 +1343,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        START_PROFILE(SMBctemp);
 
        createattr = SVAL(inbuf,smb_vwv0);
-       srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBctemp);
                return ERROR_NT(status);
@@ -1326,6 +1357,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) {
+               END_PROFILE(SMBctemp);
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
   
        tmpfd = smb_mkstemp(fname);
        if (tmpfd == -1) {
@@ -1581,7 +1616,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
                                /* Quick check for "." and ".." */
                                if (fname[0] == '.') {
                                        if (!fname[1] || (fname[1] == '.' && !fname[2])) {
-                                               if ((dirtype & aDIR)) {
+                                               if ((dirtype & FILE_ATTRIBUTE_DIRECTORY) && (dirtype & FILE_ATTRIBUTE_SYSTEM)) {
                                                        sys_direntry = True;
                                                } else {
                                                        continue;
@@ -1594,6 +1629,8 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
                                
                                if (sys_direntry) {
                                        error = NT_STATUS_OBJECT_NAME_INVALID;
+                                       DEBUG(3,("unlink_internals: system directory delete denied [%s] mask [%s]\n",
+                                               fname, mask));
                                        break;
                                }
 
@@ -1632,7 +1669,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        
        dirtype = SVAL(inbuf,smb_vwv0);
        
-       srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status, True);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBunlink);
                return ERROR_NT(status);
@@ -3164,15 +3201,16 @@ NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
                return NT_STATUS_OBJECT_NAME_INVALID;
        }
 
+       if (bad_path) {
+               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+       }
+
        if (check_name(directory, conn))
                ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory));
        
        if (ret == -1) {
                if(errno == ENOENT) {
-                       if (bad_path)
-                               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
-                       else
-                               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
                }
                return map_nt_error_from_unix(errno);
        }
@@ -3191,7 +3229,7 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        NTSTATUS status;
        START_PROFILE(SMBmkdir);
  
-       srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBmkdir);
                return ERROR_NT(status);
@@ -3361,7 +3399,7 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        NTSTATUS status;
        START_PROFILE(SMBrmdir);
 
-       srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBrmdir);
                return ERROR_NT(status);
@@ -3370,6 +3408,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) {
+               END_PROFILE(SMBrmdir);
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
   
        if (check_name(directory,conn)) {
                dptr_closepath(directory,SVAL(inbuf,smb_pid));
@@ -3950,13 +3992,13 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        START_PROFILE(SMBmv);
 
        p = smb_buf(inbuf) + 1;
-       p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status);
+       p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, True);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBmv);
                return ERROR_NT(status);
        }
        p++;
-       p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status);
+       p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, True);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBmv);
                return ERROR_NT(status);
@@ -4102,12 +4144,12 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        *directory = *mask = 0;
 
        p = smb_buf(inbuf);
-       p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status);
+       p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, True);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBcopy);
                return ERROR_NT(status);
        }
-       p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status);
+       p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, True);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBcopy);
                return ERROR_NT(status);
@@ -4267,7 +4309,7 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_DOS(ERRDOS,ERRnoaccess);
        }
 
-       srvstr_get_path(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), 0, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), 0, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(pathworks_setdir);
                return ERROR_NT(status);
index a399a12a66aa118f58854c382159182c6ba48864..d69fe0700f229d2ea1d13bb04be6a596ce8e978a 100644 (file)
@@ -607,7 +607,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
        if (IS_IPC(conn))
                return(ERROR_DOS(ERRSRV,ERRaccess));
 
-       srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                return ERROR_NT(status);
        }
@@ -618,6 +618,9 @@ 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);
+       }
     
        if (!check_name(fname,conn)) {
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
@@ -1376,7 +1379,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
                        return(ERROR_DOS(ERRDOS,ERRunknownlevel));
        }
 
-       srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus);
+       srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus, True);
        if (!NT_STATUS_IS_OK(ntstatus)) {
                return ERROR_NT(ntstatus);
        }
@@ -1384,6 +1387,9 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
        RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf);
 
        unix_convert(directory,conn,0,&bad_path,&sbuf);
+       if (bad_path) {
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
        if(!check_name(directory,conn)) {
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
        }
@@ -1569,7 +1575,7 @@ static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbu
 
        *mask = *directory = *resume_name = 0;
 
-       srvstr_get_path(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE, &ntstatus);
+       srvstr_get_path(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE, &ntstatus, True);
        if (!NT_STATUS_IS_OK(ntstatus)) {
                return ERROR_NT(ntstatus);
        }
@@ -2262,6 +2268,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
        if (!params)
                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 
+       ZERO_STRUCT(sbuf);
+
        if (tran_call == TRANSACT2_QFILEINFO) {
                if (total_params < 4)
                        return(ERROR_DOS(ERRDOS,ERRinvalidparam));
@@ -2277,11 +2285,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                         */
                                                
                        pstrcpy(fname, fsp->fsp_name);
-                       unix_convert(fname,conn,0,&bad_path,&sbuf);
-                       if (!check_name(fname,conn)) {
-                               DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed for fake_file(%s)\n",fname,strerror(errno)));
-                               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
-                       }
+                       /* We know this name is ok, it's already passed the checks. */
                        
                } else if(fsp && (fsp->is_directory || fsp->fd == -1)) {
                        /*
@@ -2289,12 +2293,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                         * handle (returned from an NT SMB). NT5.0 seems
                         * to do this call. JRA.
                         */
+                       /* We know this name is ok, it's already passed the checks. */
                        pstrcpy(fname, fsp->fsp_name);
-                       unix_convert(fname,conn,0,&bad_path,&sbuf);
-                       if (!check_name(fname,conn)) {
-                               DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
-                               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
-                       }
                  
                        if (INFO_LEVEL_IS_UNIX(info_level)) {
                                /* Always do lstat for UNIX calls. */
@@ -2302,7 +2302,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                                        DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
                                        return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                                }
-                       } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) {
+                       } else if (SMB_VFS_STAT(conn,fname,&sbuf)) {
                                DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
                                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                        }
@@ -2334,7 +2334,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
 
                DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
 
-               srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status);
+               srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status, False);
                if (!NT_STATUS_IS_OK(status)) {
                        return ERROR_NT(status);
                }
@@ -2342,6 +2342,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                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);
+               }
                if (!check_name(fname,conn)) {
                        DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
                        return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
@@ -2876,7 +2879,6 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
        BOOL bad_path_oldname = False;
        BOOL bad_path_newname = False;
        SMB_STRUCT_STAT sbuf1, sbuf2;
-       BOOL rc, rcdest;
        pstring last_component_oldname;
        pstring last_component_newname;
        NTSTATUS status = NT_STATUS_OK;
@@ -2889,8 +2891,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
                return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
        }
 
-       rc = unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1);
-       if (!rc && bad_path_oldname) {
+       unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1);
+       if (bad_path_oldname) {
                return NT_STATUS_OBJECT_PATH_NOT_FOUND;
        }
 
@@ -2910,8 +2912,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       rcdest = unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
-       if (!rcdest && bad_path_newname) {
+       unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
+       if (bad_path_newname) {
                return NT_STATUS_OBJECT_PATH_NOT_FOUND;
        }
 
@@ -2979,6 +2981,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
        if (!params)
                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 
+       ZERO_STRUCT(sbuf);
+
        if (tran_call == TRANSACT2_SETFILEINFO) {
                if (total_params < 4)
                        return(ERROR_DOS(ERRDOS,ERRinvalidparam));
@@ -2993,8 +2997,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                         * to do this call. JRA.
                         */
                        pstrcpy(fname, fsp->fsp_name);
-                       unix_convert(fname,conn,0,&bad_path,&sbuf);
-                       if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) {
+                       if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) {
                                DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
                                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                        }
@@ -3032,11 +3035,14 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                        return(ERROR_DOS(ERRDOS,ERRinvalidparam));
 
                info_level = SVAL(params,0);    
-               srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status);
+               srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status, False);
                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);
+               }
 
                /*
                 * For CIFS UNIX extensions the target name may not exist.
@@ -3488,7 +3494,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        char *newname = fname;
 
                        /* Set a hard link. */
-                       srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status);
+                       srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status, False);
                        if (!NT_STATUS_IS_OK(status)) {
                                return ERROR_NT(status);
                        }
@@ -3521,7 +3527,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        overwrite = (CVAL(pdata,0) ? True : False);
                        root_fid = IVAL(pdata,4);
                        len = IVAL(pdata,8);
-                       srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status);
+                       srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status, False);
                        if (!NT_STATUS_IS_OK(status)) {
                                return ERROR_NT(status);
                        }
@@ -3701,7 +3707,7 @@ static int call_trans2mkdir(connection_struct *conn,
        if (total_params < 4)
                return(ERROR_DOS(ERRDOS,ERRinvalidparam));
 
-       srvstr_get_path(inbuf, directory, &params[4], sizeof(directory), -1, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, directory, &params[4], sizeof(directory), -1, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                return ERROR_NT(status);
        }
@@ -3709,6 +3715,9 @@ static int call_trans2mkdir(connection_struct *conn,
        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);
+       }
        if (check_name(directory,conn))
                ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory));
   
index 86f180e54327e08db26dd41d954d88806f957ac2..13cfdac0f35de330ff651e7fe2aa99f34b5131c5 100644 (file)
@@ -829,6 +829,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
        char *resolved_name = NULL;
        size_t con_path_len = strlen(conn->connectpath);
        char *p = NULL;
+       int saved_errno = errno;
 
        DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
 
@@ -842,6 +843,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
                switch (errno) {
                        case ENOTDIR:
                                DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
+                               errno = saved_errno;
                                return False;
                        case ENOENT:
                        {
@@ -866,6 +868,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
 #endif
                                if (!resolved_name) {
                                        DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
+                                       errno = saved_errno;
                                        return False;
                                }
                                pstrcpy(tmp_fname, resolved_name);
@@ -876,6 +879,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
                                resolved_name = strdup(tmp_fname);
                                if (!resolved_name) {
                                        DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
+                                       errno = saved_errno;
                                        return False;
                                }
 #else
@@ -890,6 +894,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
                        }
                        default:
                                DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
+                               errno = saved_errno;
                                return False;
                }
        }
@@ -900,6 +905,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
                DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
                if (free_resolved_name)
                        SAFE_FREE(resolved_name);
+               errno = saved_errno;
                return False;
        }
 
@@ -907,6 +913,7 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
                DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
                if (free_resolved_name)
                        SAFE_FREE(resolved_name);
+               errno = EACCES;
                return False;
        }
 
@@ -925,11 +932,13 @@ BOOL reduce_name(connection_struct *conn, pstring fname)
                DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",fname));
                if (free_resolved_name)
                        SAFE_FREE(resolved_name);
+               errno = EACCES;
                return False;
        }
 
        DEBUG(3,("reduce_name: %s reduced to %s\n", fname, p));
        if (free_resolved_name)
                SAFE_FREE(resolved_name);
+       errno = saved_errno;
        return(True);
 }