summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorSamba Release Account <samba-bugs@samba.org>1997-08-20 20:32:23 +0000
committerSamba Release Account <samba-bugs@samba.org>1997-08-20 20:32:23 +0000
commit46dbd8c06009ad9e64251ae844fb16f2a30f5ab7 (patch)
treeb3665c4cdda6e60c2e85218f6778213817b4210f /source3
parentc76dc7c2963d1205cf46849df6b6f0edbf63692d (diff)
downloadsamba-46dbd8c06009ad9e64251ae844fb16f2a30f5ab7.tar.gz
samba-46dbd8c06009ad9e64251ae844fb16f2a30f5ab7.tar.bz2
samba-46dbd8c06009ad9e64251ae844fb16f2a30f5ab7.zip
Changes to allow Samba to return the same error code as Windows NT.
Takes care of the cases where a Windows program is parsing a pathname component by component and expects 2 different errors. ERRbadpath - if a component in the path doesn't exist. ERRbaddirectory - if a component in the path exists but is not a directory. Extra error code added to smb.h to support this. Code based on suggestions from "Christian Groessler" <chris@fast-ag.de>. Jeremy (jallison@whistle.com) (This used to be commit 28b3c6db8a81b41b448a4f3cd98e9cd2c4b5fb2e)
Diffstat (limited to 'source3')
-rw-r--r--source3/include/proto.h2
-rw-r--r--source3/include/smb.h6
-rw-r--r--source3/lib/util.c7
-rw-r--r--source3/smbd/pipes.c11
-rw-r--r--source3/smbd/reply.c239
-rw-r--r--source3/smbd/server.c25
-rw-r--r--source3/smbd/trans2.c70
7 files changed, 297 insertions, 63 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 56bdbfe865..f716c1f9a9 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -691,7 +691,7 @@ void killkids(void);
mode_t unix_mode(int cnum,int dosmode);
int dos_mode(int cnum,char *path,struct stat *sbuf);
int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st);
-BOOL unix_convert(char *name,int cnum,pstring saved_last_component);
+BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_path);
int disk_free(char *path,int *bsize,int *dfree,int *dsize);
int sys_disk_free(char *path,int *bsize,int *dfree,int *dsize);
BOOL check_name(char *name,int cnum);
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 0f2dc01865..1dbe04abc8 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -175,14 +175,15 @@ implemented */
#define ERRbadshare 32 /* Share mode on file conflict with open mode */
#define ERRlock 33 /* Lock request conflicts with existing lock */
#define ERRfilexists 80 /* File in operation already exists */
+#define ERRunknownlevel 124
#define ERRbadpipe 230 /* Named pipe invalid */
#define ERRpipebusy 231 /* All instances of pipe are busy */
#define ERRpipeclosing 232 /* named pipe close in progress */
#define ERRnotconnected 233 /* No process on other end of named pipe */
#define ERRmoredata 234 /* More data to be returned */
+#define ERRbaddirectory 267 /* Invalid directory name in a path. */
#define ERROR_EAS_DIDNT_FIT 275 /* Extended attributes didn't fit */
#define ERROR_EAS_NOT_SUPPORTED 282 /* Extended attributes not suppored */
-#define ERRunknownlevel 124
#define ERRunknownipc 2142
@@ -928,4 +929,7 @@ enum case_handling {CASE_LOWER,CASE_UPPER};
/* Size of buffer to use when moving files across filesystems. */
#define COPYBUF_SIZE (8*1024)
+/* Integers used to override error codes. */
+extern int unix_ERR_class;
+extern int unix_ERR_code;
/* _SMB_H */
diff --git a/source3/lib/util.c b/source3/lib/util.c
index ca17fbdcb4..a048c8b3a7 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -755,12 +755,17 @@ time_t file_modtime(char *fname)
BOOL directory_exist(char *dname,struct stat *st)
{
struct stat st2;
+ BOOL ret;
+
if (!st) st = &st2;
if (sys_stat(dname,st) != 0)
return(False);
- return(S_ISDIR(st->st_mode));
+ ret = S_ISDIR(st->st_mode);
+ if(!ret)
+ errno = ENOTDIR;
+ return ret;
}
/*******************************************************************
diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c
index a294ee4f49..afab7e1d91 100644
--- a/source3/smbd/pipes.c
+++ b/source3/smbd/pipes.c
@@ -84,6 +84,7 @@ int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize)
struct stat sbuf;
int smb_action = 0;
int i;
+ BOOL bad_path = False;
/* XXXX we need to handle passed times, sattr and flags */
strcpy(fname,smb_buf(inbuf));
@@ -114,7 +115,7 @@ int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize)
Connections[cnum].read_only = 0;
smb_ofun |= 0x10; /* Add Create it not exists flag */
- unix_convert(fname,cnum,0);
+ unix_convert(fname,cnum,0,&bad_path);
fnum = find_free_file();
if (fnum < 0)
@@ -129,7 +130,15 @@ int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize)
&rmode,&smb_action);
if (!Files[fnum].open)
+ {
+ /* Change the error code if bad_path was set. */
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
close_file(fnum);
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index f630e71e25..cadd63e045 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -534,11 +534,12 @@ int reply_chkpth(char *inbuf,char *outbuf)
int cnum,mode;
pstring name;
BOOL ok = False;
-
+ BOOL bad_path = False;
+
cnum = SVAL(inbuf,smb_tid);
strcpy(name,smb_buf(inbuf) + 1);
- unix_convert(name,cnum,0);
+ unix_convert(name,cnum,0,&bad_path);
mode = SVAL(inbuf,smb_vwv0);
@@ -546,8 +547,20 @@ int reply_chkpth(char *inbuf,char *outbuf)
ok = directory_exist(name,NULL);
if (!ok)
+ {
+ /* We special case this - as when a Windows machine
+ is parsing a path is steps through the components
+ one at a time - if a component fails it expects
+ ERRbadpath, not ERRbadfile.
+ */
+ if(errno == ENOENT)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRbadpath));
-
+ }
+
outsize = set_message(outbuf,0,0,True);
DEBUG(3,("%s chkpth %s cnum=%d mode=%d\n",timestring(),name,cnum,mode));
@@ -569,11 +582,12 @@ int reply_getatr(char *inbuf,char *outbuf)
int mode=0;
uint32 size=0;
time_t mtime=0;
-
+ BOOL bad_path = False;
+
cnum = SVAL(inbuf,smb_tid);
strcpy(fname,smb_buf(inbuf) + 1);
- unix_convert(fname,cnum,0);
+ unix_convert(fname,cnum,0,&bad_path);
/* dos smetimes asks for a stat of "" - it returns a "hidden directory"
under WfWg - weird! */
@@ -587,23 +601,31 @@ int reply_getatr(char *inbuf,char *outbuf)
}
else
if (check_name(fname,cnum))
+ {
+ if (sys_stat(fname,&sbuf) == 0)
{
- if (sys_stat(fname,&sbuf) == 0)
- {
- mode = dos_mode(cnum,fname,&sbuf);
- size = sbuf.st_size;
- mtime = sbuf.st_mtime;
- if (mode & aDIR)
- size = 0;
- ok = True;
- }
- else
- DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
+ mode = dos_mode(cnum,fname,&sbuf);
+ size = sbuf.st_size;
+ mtime = sbuf.st_mtime;
+ if (mode & aDIR)
+ size = 0;
+ ok = True;
+ }
+ else
+ DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
}
if (!ok)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
return(UNIXERROR(ERRDOS,ERRbadfile));
-
+ }
+
outsize = set_message(outbuf,10,0,True);
SSVAL(outbuf,smb_vwv0,mode);
@@ -635,11 +657,12 @@ int reply_setatr(char *inbuf,char *outbuf)
BOOL ok=False;
int mode;
time_t mtime;
-
+ BOOL bad_path = False;
+
cnum = SVAL(inbuf,smb_tid);
strcpy(fname,smb_buf(inbuf) + 1);
- unix_convert(fname,cnum,0);
+ unix_convert(fname,cnum,0,&bad_path);
mode = SVAL(inbuf,smb_vwv0);
mtime = make_unix_date3(inbuf+smb_vwv1);
@@ -652,8 +675,16 @@ int reply_setatr(char *inbuf,char *outbuf)
ok = set_filetime(fname,mtime);
if (!ok)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+ }
+
outsize = set_message(outbuf,0,0,True);
DEBUG(3,("%s setatr name=%s mode=%d\n",timestring(),fname,mode));
@@ -715,6 +746,7 @@ int reply_search(char *inbuf,char *outbuf)
BOOL check_descend = False;
BOOL expect_close = False;
BOOL can_open = True;
+ BOOL bad_path = False;
*mask = *directory = *fname = 0;
@@ -742,26 +774,32 @@ int reply_search(char *inbuf,char *outbuf)
strcpy(directory,smb_buf(inbuf)+1);
strcpy(dir2,smb_buf(inbuf)+1);
- unix_convert(directory,cnum,0);
+ unix_convert(directory,cnum,0,&bad_path);
unix_format(dir2);
if (!check_name(directory,cnum))
- can_open = False;
+ can_open = False;
p = strrchr(dir2,'/');
if (p == NULL)
- {strcpy(mask,dir2);*dir2 = 0;}
+ {
+ strcpy(mask,dir2);
+ *dir2 = 0;
+ }
else
- {*p = 0;strcpy(mask,p+1);}
+ {
+ *p = 0;
+ strcpy(mask,p+1);
+ }
p = strrchr(directory,'/');
if (!p)
- *directory = 0;
+ *directory = 0;
else
- *p = 0;
+ *p = 0;
if (strlen(directory) == 0)
- strcpy(directory,"./");
+ strcpy(directory,"./");
bzero(status,21);
CVAL(status,0) = dirtype;
}
@@ -827,7 +865,14 @@ int reply_search(char *inbuf,char *outbuf)
if (dptr_num < 0)
{
if(dptr_num == -2)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return (UNIXERROR(ERRDOS,ERRnofids));
+ }
return(ERROR(ERRDOS,ERRnofids));
}
}
@@ -974,27 +1019,42 @@ int reply_open(char *inbuf,char *outbuf)
int unixmode;
int rmode=0;
struct stat sbuf;
-
+ BOOL bad_path = False;
+
cnum = SVAL(inbuf,smb_tid);
share_mode = SVAL(inbuf,smb_vwv0);
strcpy(fname,smb_buf(inbuf)+1);
- unix_convert(fname,cnum,0);
+ unix_convert(fname,cnum,0,&bad_path);
fnum = find_free_file();
if (fnum < 0)
return(ERROR(ERRSRV,ERRnofids));
if (!check_name(fname,cnum))
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+ }
+
unixmode = unix_mode(cnum,aARCH);
open_file_shared(fnum,cnum,fname,share_mode,3,unixmode,&rmode,NULL);
if (!Files[fnum].open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
close_file(fnum);
@@ -1047,6 +1107,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
int size=0,fmode=0,mtime=0,rmode=0;
struct stat sbuf;
int smb_action = 0;
+ BOOL bad_path = False;
/* If it's an IPC, pass off the pipe handler. */
if (IS_IPC(cnum))
@@ -1055,14 +1116,21 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
/* XXXX we need to handle passed times, sattr and flags */
strcpy(fname,smb_buf(inbuf));
- unix_convert(fname,cnum,0);
+ unix_convert(fname,cnum,0,&bad_path);
fnum = find_free_file();
if (fnum < 0)
return(ERROR(ERRSRV,ERRnofids));
if (!check_name(fname,cnum))
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
unixmode = unix_mode(cnum,smb_attr | aARCH);
@@ -1070,7 +1138,14 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
&rmode,&smb_action);
if (!Files[fnum].open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
close_file(fnum);
@@ -1147,13 +1222,14 @@ int reply_mknew(char *inbuf,char *outbuf)
int createmode;
mode_t unixmode;
int ofun = 0;
+ BOOL bad_path = False;
com = SVAL(inbuf,smb_com);
cnum = SVAL(inbuf,smb_tid);
createmode = SVAL(inbuf,smb_vwv0);
strcpy(fname,smb_buf(inbuf)+1);
- unix_convert(fname,cnum,0);
+ unix_convert(fname,cnum,0,&bad_path);
if (createmode & aVOLID)
{
@@ -1167,7 +1243,14 @@ int reply_mknew(char *inbuf,char *outbuf)
return(ERROR(ERRSRV,ERRnofids));
if (!check_name(fname,cnum))
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
if(com == SMBmknew)
{
@@ -1184,8 +1267,15 @@ int reply_mknew(char *inbuf,char *outbuf)
open_file_shared(fnum,cnum,fname,(DENY_FCB<<4)|0xF, ofun, unixmode, NULL, NULL);
if (!Files[fnum].open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+ }
+
outsize = set_message(outbuf,1,0,True);
SSVAL(outbuf,smb_vwv0,fnum);
@@ -1212,11 +1302,12 @@ int reply_ctemp(char *inbuf,char *outbuf)
int outsize = 0;
int createmode;
mode_t unixmode;
-
+ BOOL bad_path = False;
+
cnum = SVAL(inbuf,smb_tid);
createmode = SVAL(inbuf,smb_vwv0);
sprintf(fname,"%s/TMXXXXXX",smb_buf(inbuf)+1);
- unix_convert(fname,cnum,0);
+ unix_convert(fname,cnum,0,&bad_path);
unixmode = unix_mode(cnum,createmode);
@@ -1225,7 +1316,14 @@ int reply_ctemp(char *inbuf,char *outbuf)
return(ERROR(ERRSRV,ERRnofids));
if (!check_name(fname,cnum))
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
strcpy(fname2,(char *)mktemp(fname));
@@ -1234,7 +1332,14 @@ int reply_ctemp(char *inbuf,char *outbuf)
open_file_shared(fnum,cnum,fname2,(DENY_FCB<<4)|0xF, 0x10, unixmode, NULL, NULL);
if (!Files[fnum].open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
outsize = set_message(outbuf,1,2 + strlen(fname2),True);
SSVAL(outbuf,smb_vwv0,fnum);
@@ -1290,6 +1395,7 @@ int reply_unlink(char *inbuf,char *outbuf)
int error = ERRnoaccess;
BOOL has_wild;
BOOL exists=False;
+ BOOL bad_path = False;
*directory = *mask = 0;
@@ -1300,7 +1406,7 @@ int reply_unlink(char *inbuf,char *outbuf)
DEBUG(3,("reply_unlink : %s\n",name));
- unix_convert(name,cnum,0);
+ unix_convert(name,cnum,0,&bad_path);
p = strrchr(name,'/');
if (!p) {
@@ -1362,7 +1468,14 @@ int reply_unlink(char *inbuf,char *outbuf)
if (exists)
return(ERROR(ERRDOS,error));
else
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,error));
+ }
}
outsize = set_message(outbuf,0,0,True);
@@ -2415,17 +2528,25 @@ int reply_mkdir(char *inbuf,char *outbuf)
pstring directory;
int cnum;
int outsize,ret= -1;
-
+ BOOL bad_path = False;
+
strcpy(directory,smb_buf(inbuf) + 1);
cnum = SVAL(inbuf,smb_tid);
- unix_convert(directory,cnum,0);
+ unix_convert(directory,cnum,0,&bad_path);
if (check_name(directory,cnum))
ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
if (ret < 0)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+ }
+
outsize = set_message(outbuf,0,0,True);
DEBUG(3,("%s mkdir %s cnum=%d ret=%d\n",timestring(),directory,cnum,ret));
@@ -2443,10 +2564,11 @@ int reply_rmdir(char *inbuf,char *outbuf)
int cnum;
int outsize = 0;
BOOL ok = False;
-
+ BOOL bad_path = False;
+
cnum = SVAL(inbuf,smb_tid);
strcpy(directory,smb_buf(inbuf) + 1);
- unix_convert(directory,cnum,0);
+ unix_convert(directory,cnum,0,&bad_path);
if (check_name(directory,cnum))
{
@@ -2524,8 +2646,15 @@ int reply_rmdir(char *inbuf,char *outbuf)
}
if (!ok)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRbadpath));
-
+ }
+
outsize = set_message(outbuf,0,0,True);
DEBUG(3,("%s rmdir %s\n",timestring(),directory));
@@ -2629,6 +2758,8 @@ int reply_mv(char *inbuf,char *outbuf)
int error = ERRnoaccess;
BOOL has_wild;
BOOL exists=False;
+ BOOL bad_path1 = False;
+ BOOL bad_path2 = False;
*directory = *mask = 0;
@@ -2639,8 +2770,8 @@ int reply_mv(char *inbuf,char *outbuf)
DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
- unix_convert(name,cnum,0);
- unix_convert(newname,cnum,newname_last_component);
+ unix_convert(name,cnum,0,&bad_path1);
+ unix_convert(newname,cnum,newname_last_component,&bad_path2);
/*
* Split the old name into directory and last component
@@ -2775,7 +2906,14 @@ int reply_mv(char *inbuf,char *outbuf)
if (exists)
return(ERROR(ERRDOS,error));
else
+ {
+ if((errno == ENOENT) && (bad_path1 || bad_path2))
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,error));
+ }
}
outsize = set_message(outbuf,0,0,True);
@@ -2865,6 +3003,8 @@ int reply_copy(char *inbuf,char *outbuf)
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;
*directory = *mask = 0;
@@ -2881,8 +3021,8 @@ int reply_copy(char *inbuf,char *outbuf)
return(ERROR(ERRSRV,ERRinvdevice));
}
- unix_convert(name,cnum,0);
- unix_convert(newname,cnum,0);
+ unix_convert(name,cnum,0,&bad_path1);
+ unix_convert(newname,cnum,0,&bad_path2);
target_is_directory = directory_exist(newname,NULL);
@@ -2960,7 +3100,14 @@ int reply_copy(char *inbuf,char *outbuf)
if (exists)
return(ERROR(ERRDOS,error));
else
+ {
+ if((errno == ENOENT) && (bad_path1 || bad_path2))
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,error));
+ }
}
outsize = set_message(outbuf,1,0,True);
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 93d05ffab6..aaf62fdcad 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -426,14 +426,22 @@ 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.
****************************************************************************/
-BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
+BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_path)
{
struct stat st;
char *start, *end;
pstring dirpath;
+ int saved_errno;
*dirpath = 0;
+ *bad_path = False;
+
if(saved_last_component)
*saved_last_component = 0;
@@ -480,12 +488,14 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
if (sys_stat(name,&st) == 0)
return(True);
+ saved_errno = errno;
+
DEBUG(5,("unix_convert(%s,%d)\n",name,cnum));
/* a special case - if we don't have any mangling chars and are case
sensitive then searching won't help */
if (case_sensitive && !is_mangled(name) &&
- !lp_strip_dot() && !use_mangled_map)
+ !lp_strip_dot() && !use_mangled_map && (saved_errno != ENOENT))
return(False);
/* now we need to recursively match the name against the real
@@ -506,7 +516,7 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
if (end) *end = 0;
if(saved_last_component != 0)
- strcpy(saved_last_component, end ? end + 1 : start);
+ strcpy(saved_last_component, end ? end + 1 : start);
/* check if the name exists up to this point */
if (sys_stat(name, &st) == 0)
@@ -540,6 +550,13 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
/* an intermediate part of the name can't be found */
DEBUG(5,("Intermediate not found %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.
+ */
+ *bad_path = True;
return(False);
}
@@ -1940,7 +1957,7 @@ struct
{EPERM,ERRDOS,ERRnoaccess},
{EACCES,ERRDOS,ERRnoaccess},
{ENOENT,ERRDOS,ERRbadfile},
- {ENOTDIR,ERRDOS,ERRbadpath},
+ {ENOTDIR,ERRDOS,ERRbaddirectory},
{EIO,ERRHRD,ERRgeneral},
{EBADF,ERRSRV,ERRsrverror},
{EINVAL,ERRSRV,ERRsrverror},
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index e7fd6824ab..9a48fb3ded 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -184,6 +184,7 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
int32 inode = 0;
struct stat sbuf;
int smb_action = 0;
+ BOOL bad_path = False;
StrnCpy(fname,pname,namelen);
@@ -192,14 +193,21 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
/* XXXX we need to handle passed times, sattr and flags */
- unix_convert(fname,cnum,0);
+ unix_convert(fname,cnum,0,&bad_path);
fnum = find_free_file();
if (fnum < 0)
return(ERROR(ERRSRV,ERRnofids));
if (!check_name(fname,cnum))
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
unixmode = unix_mode(cnum,open_attr | aARCH);
@@ -208,7 +216,14 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
&rmode,&smb_action);
if (!Files[fnum].open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
close_file(fnum);
@@ -559,6 +574,7 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
BOOL dont_descend = False;
BOOL out_of_space = False;
int space_remaining;
+ BOOL bad_path = False;
*directory = *mask = 0;
@@ -586,8 +602,13 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
DEBUG(5,("path=%s\n",directory));
- unix_convert(directory,cnum,0);
+ unix_convert(directory,cnum,0,&bad_path);
if(!check_name(directory,cnum)) {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(ERROR(ERRDOS,ERRbadpath));
}
@@ -616,7 +637,14 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
if (dptr_num < 0)
{
if(dptr_num == -2)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return (UNIXERROR(ERRDOS,ERRbadpath));
+ }
return(ERROR(ERRDOS,ERRbadpath));
}
@@ -1012,7 +1040,7 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
char *fname;
char *p;
int l,pos;
-
+ BOOL bad_path = False;
if (tran_call == TRANSACT2_QFILEINFO) {
int16 fnum = SVALS(params,0);
@@ -1032,9 +1060,14 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
info_level = SVAL(params,0);
fname = &fname1[0];
strcpy(fname,&params[6]);
- unix_convert(fname,cnum,0);
+ unix_convert(fname,cnum,0,&bad_path);
if (!check_name(fname,cnum) || sys_stat(fname,&sbuf)) {
DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRbadpath));
}
pos = 0;
@@ -1212,6 +1245,7 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
pstring fname1;
char *fname;
int fd = -1;
+ BOOL bad_path = False;
if (!CAN_WRITE(cnum))
return(ERROR(ERRSRV,ERRaccess));
@@ -1235,13 +1269,25 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
info_level = SVAL(params,0);
fname = fname1;
strcpy(fname,&params[6]);
- unix_convert(fname,cnum,0);
+ unix_convert(fname,cnum,0,&bad_path);
if(!check_name(fname, cnum))
- return(ERROR(ERRDOS,ERRbadpath));
-
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+
if(sys_stat(fname,&st)!=0) {
DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
- return(ERROR(ERRDOS,ERRbadpath));
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,ERRbadpath));
}
}
@@ -1396,6 +1442,7 @@ static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize,
char *params = *pparams;
pstring directory;
int ret = -1;
+ BOOL bad_path = False;
if (!CAN_WRITE(cnum))
return(ERROR(ERRSRV,ERRaccess));
@@ -1404,13 +1451,18 @@ static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize,
DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
- unix_convert(directory,cnum,0);
+ unix_convert(directory,cnum,0,&bad_path);
if (check_name(directory,cnum))
ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
if(ret < 0)
{
DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
}