summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2004-06-11 17:54:23 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 10:51:56 -0500
commitfddef6fc201ed127eaac737e725d1c2dd8c6926e (patch)
tree0c8e596fbc8a4a074ecf0161f8189af5875ba876 /source3
parentf28e4f386393b500abfc468e390acfb808d6854a (diff)
downloadsamba-fddef6fc201ed127eaac737e725d1c2dd8c6926e.tar.gz
samba-fddef6fc201ed127eaac737e725d1c2dd8c6926e.tar.bz2
samba-fddef6fc201ed127eaac737e725d1c2dd8c6926e.zip
r1115: Fix for #1427. Catch bad path errors at the right point. Ensure all
our pathname parsing is consistent. Jeremy. (This used to be commit 5e8237e306f0bb0e492f10fb6487938132899384)
Diffstat (limited to 'source3')
-rw-r--r--source3/libsmb/smb_signing.c4
-rw-r--r--source3/rpc_server/srv_srvsvc_nt.c24
-rw-r--r--source3/smbd/filename.c25
-rw-r--r--source3/smbd/msdfs.c4
-rw-r--r--source3/smbd/nttrans.c42
-rw-r--r--source3/smbd/reply.c114
-rw-r--r--source3/smbd/trans2.c61
-rw-r--r--source3/smbd/vfs.c9
8 files changed, 203 insertions, 80 deletions
diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c
index 7130453c0c..63838e6933 100644
--- a/source3/libsmb/smb_signing.c
+++ b/source3/libsmb/smb_signing.c
@@ -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);
diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c
index 087c50451e..54cc0d6161 100644
--- a/source3/rpc_server/srv_srvsvc_nt.c
+++ b/source3/rpc_server/srv_srvsvc_nt.c
@@ -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,
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 67329b51e6..ab75d9c06a 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -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);
}
diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index c66f0477a8..6c132897f9 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -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;
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 25ed08650a..2f498b7c94 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -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);
}
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 5b30fe5b75..961f4d7f55 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -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);
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index a399a12a66..d69fe0700f 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -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));
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 86f180e543..13cfdac0f3 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -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);
}