From db0ad252a0622dfac17d44ca646168df4c1c22e5 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 12 Jan 2007 23:47:16 +0000 Subject: r20718: Sync up the filename path parsing changes from SAMBA_3_0_24. The only difference between the two trees now w.r.t file serving are the changes to smbd/open.c in this branch I need to review. Jeremy. (This used to be commit f4474edf6a0c71001dbd01429ef70bafad6abd74) --- source3/smbd/reply.c | 685 ++++++++++++++++----------------------------------- 1 file changed, 219 insertions(+), 466 deletions(-) (limited to 'source3/smbd/reply.c') diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index b3df8acf11..5914a3b169 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3,7 +3,7 @@ Main SMB reply routines Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Andrew Bartlett 2001 - Copyright (C) Jeremy Allison 1992-2004. + Copyright (C) Jeremy Allison 1992-2007. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -36,143 +36,6 @@ extern uint32 global_client_caps; extern struct current_user current_user; extern BOOL global_encrypted_passwords_negotiated; -/**************************************************************************** - Ensure we check the path in *exactly* the same way as W2K for regular pathnames. - We're assuming here that '/' is not the second byte in any multibyte char - set (a safe assumption). '\\' *may* be the second byte in a multibyte char - set. -****************************************************************************/ - -NTSTATUS check_path_syntax(pstring destname, const pstring srcname) -{ - char *d = destname; - const char *s = srcname; - NTSTATUS ret = NT_STATUS_OK; - BOOL start_of_name_component = True; - unsigned int num_bad_components = 0; - - while (*s) { - if (IS_DIRECTORY_SEP(*s)) { - /* - * Safe to assume is not the second part of a mb char as this is handled below. - */ - /* Eat multiple '/' or '\\' */ - while (IS_DIRECTORY_SEP(*s)) { - s++; - } - if ((d != destname) && (*s != '\0')) { - /* We only care about non-leading or trailing '/' or '\\' */ - *d++ = '/'; - } - - start_of_name_component = True; - continue; - } - - if (start_of_name_component) { - if ((s[0] == '.') && (s[1] == '.') && (IS_DIRECTORY_SEP(s[2]) || s[2] == '\0')) { - /* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */ - - /* - * No mb char starts with '.' so we're safe checking the directory separator here. - */ - - /* If we just added a '/' - delete it */ - if ((d > destname) && (*(d-1) == '/')) { - *(d-1) = '\0'; - d--; - } - - /* Are we at the start ? Can't go back further if so. */ - if (d <= destname) { - ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; - break; - } - /* Go back one level... */ - /* We know this is safe as '/' cannot be part of a mb sequence. */ - /* NOTE - if this assumption is invalid we are not in good shape... */ - /* Decrement d first as d points to the *next* char to write into. */ - for (d--; d > destname; d--) { - if (*d == '/') - break; - } - s += 2; /* Else go past the .. */ - /* We're still at the start of a name component, just the previous one. */ - - if (num_bad_components) { - /* Hmmm. Should we only decrement the bad_components if - we're removing a bad component ? Need to check this. JRA. */ - num_bad_components--; - } - - continue; - - } else if ((s[0] == '.') && ((s[1] == '\0') || IS_DIRECTORY_SEP(s[1]))) { - /* Component of pathname can't be "." only. */ - ret = NT_STATUS_OBJECT_NAME_INVALID; - num_bad_components++; - *d++ = *s++; - continue; - } - } - - if (!(*s & 0x80)) { - if (*s <= 0x1f) { - return NT_STATUS_OBJECT_NAME_INVALID; - } - switch (*s) { - case '*': - case '?': - case '<': - case '>': - case '"': - return NT_STATUS_OBJECT_NAME_INVALID; - default: - *d++ = *s++; - break; - } - } else { - size_t siz; - /* Get the size of the next MB character. */ - next_codepoint(s,&siz); - switch(siz) { - case 5: - *d++ = *s++; - /*fall through*/ - case 4: - *d++ = *s++; - /*fall through*/ - case 3: - *d++ = *s++; - /*fall through*/ - case 2: - *d++ = *s++; - /*fall through*/ - case 1: - *d++ = *s++; - break; - default: - DEBUG(0,("check_path_syntax: character length assumptions invalid !\n")); - *d = '\0'; - return NT_STATUS_INVALID_PARAMETER; - } - } - if (start_of_name_component && num_bad_components) { - num_bad_components++; - } - start_of_name_component = False; - } - - if (NT_STATUS_EQUAL(ret, NT_STATUS_OBJECT_NAME_INVALID)) { - if (num_bad_components > 1) { - ret = NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - } - - *d = '\0'; - return ret; -} - /**************************************************************************** Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext path or anything including wildcards. @@ -181,15 +44,19 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname) set. ****************************************************************************/ -NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *p_contains_wcard) +NTSTATUS check_path_syntax_internal(pstring destname, + const pstring srcname, + BOOL windows_path, BOOL + *p_last_component_contains_wcard) { char *d = destname; const char *s = srcname; NTSTATUS ret = NT_STATUS_OK; BOOL start_of_name_component = True; - unsigned int num_bad_components = 0; - *p_contains_wcard = False; + if (p_last_component_contains_wcard) { + *p_last_component_contains_wcard = False; + } while (*s) { if (IS_DIRECTORY_SEP(*s)) { @@ -206,6 +73,10 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL * } start_of_name_component = True; + /* New component. */ + if (p_last_component_contains_wcard) { + *p_last_component_contains_wcard = False; + } continue; } @@ -238,36 +109,32 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL * } s += 2; /* Else go past the .. */ /* We're still at the start of a name component, just the previous one. */ - - if (num_bad_components) { - /* Hmmm. Should we only decrement the bad_components if - we're removing a bad component ? Need to check this. JRA. */ - num_bad_components--; - } - continue; } else if ((s[0] == '.') && ((s[1] == '\0') || IS_DIRECTORY_SEP(s[1]))) { - /* Component of pathname can't be "." only. */ - ret = NT_STATUS_OBJECT_NAME_INVALID; - num_bad_components++; - *d++ = *s++; - continue; + if (!windows_path) { + /* Eat the '.' */ + s++; + continue; + } } + } if (!(*s & 0x80)) { - if (*s <= 0x1f) { - return NT_STATUS_OBJECT_NAME_INVALID; - } - if (!*p_contains_wcard) { + if (windows_path) { + if (*s <= 0x1f) { + return NT_STATUS_OBJECT_NAME_INVALID; + } switch (*s) { case '*': case '?': case '<': case '>': case '"': - *p_contains_wcard = True; + if (p_last_component_contains_wcard) { + *p_last_component_contains_wcard = True; + } break; default: break; @@ -295,130 +162,48 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL * *d++ = *s++; break; default: - DEBUG(0,("check_path_syntax_wcard: character length assumptions invalid !\n")); + DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n")); *d = '\0'; return NT_STATUS_INVALID_PARAMETER; } } - if (start_of_name_component && num_bad_components) { - num_bad_components++; - } start_of_name_component = False; } - if (NT_STATUS_EQUAL(ret, NT_STATUS_OBJECT_NAME_INVALID)) { - /* For some strange reason being called from findfirst changes - the num_components number to cause the error return to change. JRA. */ - if (num_bad_components > 2) { - ret = NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - } - *d = '\0'; return ret; } /**************************************************************************** - Check the path for a POSIX client. - We're assuming here that '/' is not the second byte in any multibyte char - set (a safe assumption). + Ensure we check the path in *exactly* the same way as W2K for regular pathnames. + No wildcards allowed. ****************************************************************************/ -NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname) +NTSTATUS check_path_syntax(pstring destname, const pstring srcname) { - char *d = destname; - const char *s = srcname; - NTSTATUS ret = NT_STATUS_OK; - BOOL start_of_name_component = True; - - while (*s) { - if (*s == '/') { - /* - * Safe to assume is not the second part of a mb char as this is handled below. - */ - /* Eat multiple '/' or '\\' */ - while (*s == '/') { - s++; - } - if ((d != destname) && (*s != '\0')) { - /* We only care about non-leading or trailing '/' */ - *d++ = '/'; - } - - start_of_name_component = True; - continue; - } - - if (start_of_name_component) { - if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) { - /* Uh oh - "/../" or "/..\0" ! */ - - /* - * No mb char starts with '.' so we're safe checking the directory separator here. - */ - - /* If we just added a '/' - delete it */ - if ((d > destname) && (*(d-1) == '/')) { - *(d-1) = '\0'; - d--; - } + return check_path_syntax_internal(destname, srcname, True, NULL); +} - /* Are we at the start ? Can't go back further if so. */ - if (d <= destname) { - ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; - break; - } - /* Go back one level... */ - /* We know this is safe as '/' cannot be part of a mb sequence. */ - /* NOTE - if this assumption is invalid we are not in good shape... */ - /* Decrement d first as d points to the *next* char to write into. */ - for (d--; d > destname; d--) { - if (*d == '/') - break; - } - s += 2; /* Else go past the .. */ - continue; +/**************************************************************************** + Ensure we check the path in *exactly* the same way as W2K for regular pathnames. + Wildcards allowed - p_contains_wcard returns true if the last component contained + a wildcard. +****************************************************************************/ - } else if ((s[0] == '.') && ((s[1] == '\0') || (s[1] == '/'))) { - /* Eat the '.' */ - s++; - continue; - } - } +NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *p_contains_wcard) +{ + return check_path_syntax_internal(destname, srcname, True, p_contains_wcard); +} - if (!(*s & 0x80)) { - *d++ = *s++; - } else { - size_t siz; - /* Get the size of the next MB character. */ - next_codepoint(s,&siz); - switch(siz) { - case 5: - *d++ = *s++; - /*fall through*/ - case 4: - *d++ = *s++; - /*fall through*/ - case 3: - *d++ = *s++; - /*fall through*/ - case 2: - *d++ = *s++; - /*fall through*/ - case 1: - *d++ = *s++; - break; - default: - DEBUG(0,("check_path_syntax_posix: character length assumptions invalid !\n")); - *d = '\0'; - return NT_STATUS_INVALID_PARAMETER; - } - } - start_of_name_component = False; - } +/**************************************************************************** + Check the path for a POSIX client. + We're assuming here that '/' is not the second byte in any multibyte char + set (a safe assumption). +****************************************************************************/ - *d = '\0'; - return ret; +static NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname) +{ + return check_path_syntax_internal(destname, srcname, False, NULL); } /**************************************************************************** @@ -823,7 +608,6 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size int outsize = 0; pstring name; BOOL ok = False; - BOOL bad_path = False; SMB_STRUCT_STAT sbuf; NTSTATUS status; @@ -845,10 +629,10 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size RESOLVE_DFSPATH(name, conn, inbuf, outbuf); - unix_convert(name,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, name, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBchkpth); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (check_name(name,conn)) { @@ -871,8 +655,7 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size * the parent directory is valid but not the * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND - * if the path is invalid. This is different from set_bad_path_error() - * in the non-NT error case. + * if the path is invalid. */ END_PROFILE(SMBchkpth); return ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpath); @@ -902,7 +685,6 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size int mode=0; SMB_OFF_T size=0; time_t mtime=0; - BOOL bad_path = False; char *p; NTSTATUS status; @@ -927,10 +709,10 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size mtime = 0; ok = True; } else { - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, fname, False, NULL,&sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBgetatr); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (check_name(fname,conn)) { if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,fname,&sbuf) == 0) { @@ -948,7 +730,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (!ok) { END_PROFILE(SMBgetatr); - return UNIXERROR(ERRDOS, ERRbadfile); + return UNIXERROR(ERRDOS,ERRbadfile); } outsize = set_message(outbuf,10,0,True); @@ -982,7 +764,6 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size int mode; time_t mtime; SMB_STRUCT_STAT sbuf; - BOOL bad_path = False; char *p; NTSTATUS status; @@ -997,10 +778,10 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path || !check_name(fname, conn)) { + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBsetatr); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (fname[0] == '.' && fname[1] == '\0') { @@ -1012,6 +793,11 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return ERROR_NT(NT_STATUS_ACCESS_DENIED); } + if (!check_name(fname,conn)) { + END_PROFILE(SMBsetatr); + return UNIXERROR(ERRDOS, ERRnoaccess); + } + mode = SVAL(inbuf,smb_vwv0); mtime = srv_make_unix_date3(inbuf+smb_vwv1); @@ -1118,7 +904,6 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size BOOL check_descend = False; BOOL expect_close = False; BOOL can_open = True; - BOOL bad_path = False; NTSTATUS nt_status; BOOL mask_contains_wcard = False; BOOL allow_long_path_components = (SVAL(inbuf,smb_flg2) & FLAGS2_LONG_PATH_COMPONENTS) ? True : False; @@ -1160,7 +945,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size pstrcpy(directory,path); pstrcpy(dir2,path); - unix_convert(directory,conn,0,&bad_path,&sbuf); + nt_status = unix_convert(conn, directory, mask_contains_wcard, NULL, &sbuf); + if (!NT_STATUS_IS_OK(nt_status)) { + END_PROFILE(SMBsearch); + return ERROR_NT(nt_status); + } unix_format(dir2); if (!check_name(directory,conn)) @@ -1209,9 +998,6 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (dptr_num < 0) { if(dptr_num == -2) { END_PROFILE(SMBsearch); - if ((errno == ENOENT) && bad_path) { - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); - } return UNIXERROR(ERRDOS, ERRnofids); } END_PROFILE(SMBsearch); @@ -1377,7 +1163,6 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, time_t mtime=0; int info; SMB_STRUCT_STAT sbuf; - BOOL bad_path = False; files_struct *fsp; int oplock_request = CORE_OPLOCK_REQUEST(inbuf); int deny_mode; @@ -1399,10 +1184,10 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBopen); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (!map_open_params_to_ntcreate(fname, deny_mode, OPENX_FILE_EXISTS_OPEN, @@ -1486,7 +1271,6 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt int mtime=0; SMB_STRUCT_STAT sbuf; int smb_action = 0; - BOOL bad_path = False; files_struct *fsp; NTSTATUS status; SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv9); @@ -1518,10 +1302,10 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBopenX); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (!map_open_params_to_ntcreate(fname, deny_mode, smb_ofun, @@ -1667,7 +1451,6 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int outsize = 0; uint32 fattr = SVAL(inbuf,smb_vwv0); struct utimbuf times; - BOOL bad_path = False; files_struct *fsp; int oplock_request = CORE_OPLOCK_REQUEST(inbuf); SMB_STRUCT_STAT sbuf; @@ -1691,10 +1474,10 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBcreate); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (fattr & aVOLID) { @@ -1758,7 +1541,6 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, pstring fname; int outsize = 0; uint32 fattr = SVAL(inbuf,smb_vwv0); - BOOL bad_path = False; files_struct *fsp; int oplock_request = CORE_OPLOCK_REQUEST(inbuf); int tmpfd; @@ -1782,10 +1564,10 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - unix_convert(fname,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, fname, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBctemp); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } tmpfd = smb_mkstemp(fname); @@ -1898,12 +1680,12 @@ static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, Check if a user is allowed to delete a file. ********************************************************************/ -static NTSTATUS can_delete(connection_struct *conn, char *fname, - uint32 dirtype, BOOL bad_path) +static NTSTATUS can_delete(connection_struct *conn, char *fname, uint32 dirtype) { SMB_STRUCT_STAT sbuf; uint32 fattr; files_struct *fsp; + uint32 dirtype_orig = dirtype; NTSTATUS status; DEBUG(10,("can_delete: %s, dirtype = %d\n", fname, dirtype )); @@ -1913,22 +1695,56 @@ static NTSTATUS can_delete(connection_struct *conn, char *fname, } if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0) { - if(errno == ENOENT) { - if (bad_path) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } else { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - } return map_nt_error_from_unix(errno); } fattr = dos_mode(conn,fname,&sbuf); + if (dirtype & FILE_ATTRIBUTE_NORMAL) { + dirtype = aDIR|aARCH|aRONLY; + } + + dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM); + if (!dirtype) { + return NT_STATUS_NO_SUCH_FILE; + } + + if (!dir_check_ftype(conn, fattr, dirtype)) { + if (fattr & aDIR) { + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + return NT_STATUS_NO_SUCH_FILE; + } + + if (dirtype_orig & 0x8000) { + /* These will never be set for POSIX. */ + return NT_STATUS_NO_SUCH_FILE; + } + +#if 0 + if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) { + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + + if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) { + return NT_STATUS_NO_SUCH_FILE; + } + + if (dirtype & 0xFF00) { + /* These will never be set for POSIX. */ + return NT_STATUS_NO_SUCH_FILE; + } + + dirtype &= 0xFF; + if (!dirtype) { + return NT_STATUS_NO_SUCH_FILE; + } + /* Can't delete a directory. */ if (fattr & aDIR) { return NT_STATUS_FILE_IS_A_DIRECTORY; } +#endif #if 0 /* JRATEST */ else if (dirtype & aDIR) /* Asked for a directory and it isn't. */ @@ -1952,9 +1768,6 @@ static NTSTATUS can_delete(connection_struct *conn, char *fname, return NT_STATUS_CANNOT_DELETE; } } - if ((fattr & ~dirtype) & (aHIDDEN | aSYSTEM)) { - return NT_STATUS_NO_SUCH_FILE; - } /* On open checks the open itself will check the share mode, so don't do it here as we'll get it wrong. */ @@ -1979,27 +1792,21 @@ static NTSTATUS can_delete(connection_struct *conn, char *fname, code. ****************************************************************************/ -NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, - char *name, BOOL has_wild) +NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, char *name, BOOL has_wild) { pstring directory; pstring mask; - pstring orig_name; char *p; int count=0; - NTSTATUS error = NT_STATUS_OK; - BOOL bad_path = False; - BOOL rc = True; + NTSTATUS status = NT_STATUS_OK; SMB_STRUCT_STAT sbuf; *directory = *mask = 0; - rc = unix_convert(name,conn,0,&bad_path,&sbuf); - - /* - * Feel my pain, this code needs rewriting *very* badly! -- vl - */ - pstrcpy(orig_name, name); + status = unix_convert(conn, name, has_wild, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + return status; + } p = strrchr_m(name,'/'); if (!p) { @@ -2020,33 +1827,28 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, * Tine Smukavec . */ - if (!rc && mangle_is_mangled(mask,conn->params)) + if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params)) mangle_check_cache( mask, sizeof(pstring)-1, conn->params ); if (!has_wild) { pstrcat(directory,"/"); pstrcat(directory,mask); - error = can_delete(conn,directory,dirtype,bad_path); - if (!NT_STATUS_IS_OK(error)) - return error; + if (dirtype == 0) { + dirtype = FILE_ATTRIBUTE_NORMAL; + } + status = can_delete(conn,directory,dirtype); + if (!NT_STATUS_IS_OK(status)) + return status; if (SMB_VFS_UNLINK(conn,directory) == 0) { count++; } - } else { struct smb_Dir *dir_hnd = NULL; const char *dname; - /* Ensure we check bad_path in the wcard case. - * This may not be correct w.r.t. Windows (needs - * smbtorture test cases which will be forthcoming) - * but prevents us from continuing in the obvious - * bad path case. This is merely a placeholder. JRA. - */ - - if (!rc && bad_path) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; + if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) { + return NT_STATUS_OBJECT_NAME_INVALID; } if (strequal(mask,"????????.???")) @@ -2062,12 +1864,11 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, if (dir_hnd) { long offset = 0; - error = NT_STATUS_NO_SUCH_FILE; + status = NT_STATUS_NO_SUCH_FILE; while ((dname = ReadDirName(dir_hnd, &offset))) { SMB_STRUCT_STAT st; pstring fname; - BOOL sys_direntry = False; pstrcpy(fname,dname); if (!is_visible_file(conn, directory, dname, &st, True)) { @@ -2077,44 +1878,31 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, /* Quick check for "." and ".." */ if (fname[0] == '.') { if (!fname[1] || (fname[1] == '.' && !fname[2])) { - if (dirtype & FILE_ATTRIBUTE_DIRECTORY) { - sys_direntry = True; - } else { - continue; - } + continue; } } if(!mask_match(fname, mask, conn->case_sensitive)) continue; - if (sys_direntry) { - error = NT_STATUS_OBJECT_NAME_INVALID; - DEBUG(3,("unlink_internals: system directory delete denied [%s] mask [%s]\n", - fname, mask)); - break; - } - slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); - error = can_delete(conn, fname, dirtype, - bad_path); - if (!NT_STATUS_IS_OK(error)) { + status = can_delete(conn, fname, dirtype); + if (!NT_STATUS_IS_OK(status)) { continue; } - if (SMB_VFS_UNLINK(conn,fname) == 0) { + if (SMB_VFS_UNLINK(conn,fname) == 0) count++; - } DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname)); } CloseDir(dir_hnd); } } - if (count == 0 && NT_STATUS_IS_OK(error)) { - error = map_nt_error_from_unix(errno); + if (count == 0 && NT_STATUS_IS_OK(status)) { + status = map_nt_error_from_unix(errno); } - return error; + return status; } /**************************************************************************** @@ -3774,7 +3562,6 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, pstring directory; int outsize; NTSTATUS status; - BOOL bad_path = False; SMB_STRUCT_STAT sbuf; START_PROFILE(SMBmkdir); @@ -3787,10 +3574,10 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(directory, conn, inbuf, outbuf); - unix_convert(directory,conn,0,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, directory, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBmkdir); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } status = create_directory(conn, directory); @@ -3939,7 +3726,7 @@ BOOL rmdir_internals(connection_struct *conn, const char *directory) pstrcpy(fullname, directory); pstrcat(fullname, "/"); pstrcat(fullname, dname); - + if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) break; if(st.st_mode & S_IFDIR) { @@ -3977,7 +3764,6 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, pstring directory; int outsize = 0; BOOL ok = False; - BOOL bad_path = False; SMB_STRUCT_STAT sbuf; NTSTATUS status; START_PROFILE(SMBrmdir); @@ -3990,10 +3776,10 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH(directory, conn, inbuf, outbuf) - unix_convert(directory,conn, NULL,&bad_path,&sbuf); - if (bad_path) { + status = unix_convert(conn, directory, False, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBrmdir); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + return ERROR_NT(status); } if (check_name(directory,conn)) { @@ -4171,24 +3957,16 @@ static BOOL rename_path_prefix_equal(const char *src, const char *dest) NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *newname, uint32 attrs, BOOL replace_if_exists) { SMB_STRUCT_STAT sbuf; - BOOL bad_path = False; pstring newname_last_component; - NTSTATUS error = NT_STATUS_OK; + NTSTATUS status = NT_STATUS_OK; BOOL dest_exists; - BOOL rcdest = True; struct share_mode_lock *lck = NULL; ZERO_STRUCT(sbuf); - rcdest = unix_convert(newname,conn,newname_last_component,&bad_path,&sbuf); - /* Quick check for "." and ".." */ - if (!bad_path && newname_last_component[0] == '.') { - if (!newname_last_component[1] || (newname_last_component[1] == '.' && !newname_last_component[2])) { - return NT_STATUS_ACCESS_DENIED; - } - } - if (!rcdest && bad_path) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; + status = unix_convert(conn, newname, False, newname_last_component, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* Ensure newname contains a '/' */ @@ -4250,14 +4028,14 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char * return NT_STATUS_OBJECT_NAME_COLLISION; } - error = can_rename(conn,newname,attrs,&sbuf); + status = can_rename(conn,newname,attrs,&sbuf); - if (dest_exists && !NT_STATUS_IS_OK(error)) { + if (dest_exists && !NT_STATUS_IS_OK(status)) { DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(error), fsp->fsp_name,newname)); - if (NT_STATUS_EQUAL(error,NT_STATUS_SHARING_VIOLATION)) - error = NT_STATUS_ACCESS_DENIED; - return error; + nt_errstr(status), fsp->fsp_name,newname)); + if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) + status = NT_STATUS_ACCESS_DENIED; + return status; } if (rename_path_prefix_equal(fsp->fsp_name, newname)) { @@ -4277,15 +4055,15 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char * TALLOC_FREE(lck); if (errno == ENOTDIR || errno == EISDIR) { - error = NT_STATUS_OBJECT_NAME_COLLISION; + status = NT_STATUS_OBJECT_NAME_COLLISION; } else { - error = map_nt_error_from_unix(errno); + status = map_nt_error_from_unix(errno); } DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n", - nt_errstr(error), fsp->fsp_name,newname)); + nt_errstr(status), fsp->fsp_name,newname)); - return error; + return status; } /**************************************************************************** @@ -4300,12 +4078,8 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui pstring last_component_src; pstring last_component_dest; char *p; - BOOL bad_path_src = False; - BOOL bad_path_dest = False; int count=0; - NTSTATUS error = NT_STATUS_OK; - BOOL rc = True; - BOOL rcdest = True; + NTSTATUS status = NT_STATUS_OK; SMB_STRUCT_STAT sbuf1, sbuf2; struct share_mode_lock *lck = NULL; @@ -4314,27 +4088,14 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui ZERO_STRUCT(sbuf1); ZERO_STRUCT(sbuf2); - rc = unix_convert(name,conn,last_component_src,&bad_path_src,&sbuf1); - if (!rc && bad_path_src) { - if (ms_has_wild(last_component_src)) - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - - /* Quick check for "." and ".." */ - if (last_component_src[0] == '.') { - if (!last_component_src[1] || (last_component_src[1] == '.' && !last_component_src[2])) { - return NT_STATUS_OBJECT_NAME_INVALID; - } + status = unix_convert(conn, name, has_wild, last_component_src, &sbuf1); + if (!NT_STATUS_IS_OK(status)) { + return status; } - rcdest = unix_convert(newname,conn,last_component_dest,&bad_path_dest,&sbuf2); - - /* Quick check for "." and ".." */ - if (last_component_dest[0] == '.') { - if (!last_component_dest[1] || (last_component_dest[1] == '.' && !last_component_dest[2])) { - return NT_STATUS_OBJECT_NAME_INVALID; - } + status = unix_convert(conn, newname, True, last_component_dest, &sbuf2); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* @@ -4366,7 +4127,7 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui * Tine Smukavec . */ - if (!rc && mangle_is_mangled(mask, conn->params)) + if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) mangle_check_cache( mask, sizeof(pstring)-1, conn->params ); if (!has_wild) { @@ -4451,25 +4212,19 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", return NT_STATUS_OBJECT_NAME_NOT_FOUND; return NT_STATUS_OBJECT_PATH_NOT_FOUND; } - error = map_nt_error_from_unix(errno); + status = map_nt_error_from_unix(errno); DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(error), directory,newname)); - - return error; - } + nt_errstr(status), directory,newname)); - if (!rcdest && bad_path_dest) { - if (ms_has_wild(last_component_dest)) - return NT_STATUS_OBJECT_NAME_INVALID; - return NT_STATUS_OBJECT_PATH_NOT_FOUND; + return status; } - error = can_rename(conn,directory,attrs,&sbuf1); + status = can_rename(conn,directory,attrs,&sbuf1); - if (!NT_STATUS_IS_OK(error)) { + if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(error), directory,newname)); - return error; + nt_errstr(status), directory,newname)); + return status; } /* @@ -4505,14 +4260,14 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", TALLOC_FREE(lck); if (errno == ENOTDIR || errno == EISDIR) - error = NT_STATUS_OBJECT_NAME_COLLISION; + status = NT_STATUS_OBJECT_NAME_COLLISION; else - error = map_nt_error_from_unix(errno); + status = map_nt_error_from_unix(errno); DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(error), directory,newname)); + nt_errstr(status), directory,newname)); - return error; + return status; } else { /* * Wildcards - process each file that matches. @@ -4529,8 +4284,8 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", if (dir_hnd) { long offset = 0; - error = NT_STATUS_NO_SUCH_FILE; -/* Was error = NT_STATUS_OBJECT_NAME_NOT_FOUND; - gentest fix. JRA */ + status = NT_STATUS_NO_SUCH_FILE; +/* Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND; - gentest fix. JRA */ while ((dname = ReadDirName(dir_hnd, &offset))) { pstring fname; @@ -4556,19 +4311,19 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", continue; if (sysdir_entry) { - error = NT_STATUS_OBJECT_NAME_INVALID; + status = NT_STATUS_OBJECT_NAME_INVALID; break; } - error = NT_STATUS_ACCESS_DENIED; + status = NT_STATUS_ACCESS_DENIED; slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname); if (!vfs_object_exist(conn, fname, &sbuf1)) { - error = NT_STATUS_OBJECT_NAME_NOT_FOUND; - DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(error))); + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(status))); continue; } - error = can_rename(conn,fname,attrs,&sbuf1); - if (!NT_STATUS_IS_OK(error)) { + status = can_rename(conn,fname,attrs,&sbuf1); + if (!NT_STATUS_IS_OK(status)) { DEBUG(6,("rename %s refused\n", fname)); continue; } @@ -4584,14 +4339,14 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", rename_open_files(conn, NULL, sbuf1.st_dev, sbuf1.st_ino, newname); DEBUG(3,("rename_internals: identical names in wildcard rename %s - success\n", fname)); count++; - error = NT_STATUS_OK; + status = NT_STATUS_OK; continue; } if (!replace_if_exists && vfs_file_exist(conn,destname, NULL)) { DEBUG(6,("file_exist %s\n", destname)); - error = NT_STATUS_OBJECT_NAME_COLLISION; + status = NT_STATUS_OBJECT_NAME_COLLISION; continue; } @@ -4604,7 +4359,7 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", if (!SMB_VFS_RENAME(conn,fname,destname)) { rename_open_files(conn, lck, sbuf1.st_dev, sbuf1.st_ino, newname); count++; - error = NT_STATUS_OK; + status = NT_STATUS_OK; } TALLOC_FREE(lck); DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname)); @@ -4612,6 +4367,8 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", CloseDir(dir_hnd); } +#if 0 + /* Don't think needed any more - JRA. */ if (!NT_STATUS_EQUAL(error,NT_STATUS_NO_SUCH_FILE)) { if (!rcdest && bad_path_dest) { if (ms_has_wild(last_component_dest)) @@ -4619,13 +4376,15 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", return NT_STATUS_OBJECT_PATH_NOT_FOUND; } } +#endif + } - if (count == 0 && NT_STATUS_IS_OK(error)) { - error = map_nt_error_from_unix(errno); + if (count == 0 && NT_STATUS_IS_OK(status)) { + status = map_nt_error_from_unix(errno); } - return error; + return status; } /**************************************************************************** @@ -4821,11 +4580,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int ofun = SVAL(inbuf,smb_vwv1); int flags = SVAL(inbuf,smb_vwv2); BOOL target_is_directory=False; - BOOL bad_path1 = False; - BOOL bad_path2 = False; BOOL path_contains_wcard1 = False; BOOL path_contains_wcard2 = False; - BOOL rc = True; SMB_STRUCT_STAT sbuf1, sbuf2; NTSTATUS status; START_PROFILE(SMBcopy); @@ -4856,8 +4612,17 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf); RESOLVE_DFSPATH_WCARD(newname, conn, inbuf, outbuf); - rc = unix_convert(name,conn,0,&bad_path1,&sbuf1); - unix_convert(newname,conn,0,&bad_path2,&sbuf2); + status = unix_convert(conn, name, path_contains_wcard1, NULL, &sbuf1); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBcopy); + return ERROR_NT(status); + } + + status = unix_convert(conn, newname, path_contains_wcard2, NULL, &sbuf2); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBcopy); + return ERROR_NT(status); + } target_is_directory = VALID_STAT_OF_DIR(sbuf2); @@ -4897,7 +4662,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, * Tine Smukavec . */ - if (!rc && mangle_is_mangled(mask, conn->params)) + if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) mangle_check_cache( mask, sizeof(pstring)-1, conn->params ); has_wild = path_contains_wcard1; @@ -4964,20 +4729,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return(UNIXERROR(ERRHRD,ERRgeneral)); } - if (exists) { - END_PROFILE(SMBcopy); - return ERROR_DOS(ERRDOS,error); - } else { - if((errno == ENOENT) && (bad_path1 || bad_path2) && - !use_nt_status()) { - /* Samba 3.0.22 has ERRDOS/ERRbadpath in the - * DOS error code case - */ - return ERROR_DOS(ERRDOS, ERRbadpath); - } - END_PROFILE(SMBcopy); - return(UNIXERROR(ERRDOS,error)); - } + END_PROFILE(SMBcopy); + return ERROR_DOS(ERRDOS,error); } outsize = set_message(outbuf,1,0,True); -- cgit