From fddef6fc201ed127eaac737e725d1c2dd8c6926e Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 11 Jun 2004 17:54:23 +0000 Subject: 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) --- source3/libsmb/smb_signing.c | 4 +- source3/rpc_server/srv_srvsvc_nt.c | 24 ++++++++ source3/smbd/filename.c | 25 +++++++- source3/smbd/msdfs.c | 4 +- source3/smbd/nttrans.c | 42 ++++++++++---- source3/smbd/reply.c | 114 +++++++++++++++++++++++++------------ source3/smbd/trans2.c | 61 +++++++++++--------- source3/smbd/vfs.c | 9 +++ 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, ¶ms[6], sizeof(fname), -1, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, ¶ms[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, ¶ms[6], sizeof(fname), -1, STR_TERMINATE, &status); + srvstr_get_path(inbuf, fname, ¶ms[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, ¶ms[4], sizeof(directory), -1, STR_TERMINATE, &status); + srvstr_get_path(inbuf, directory, ¶ms[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); } -- cgit