From 132ee3990af5d31573978f5a3abf43db2303880b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 7 Sep 2007 20:57:01 +0000 Subject: r25009: Large patch discussed with Volker. Move unix_convert to a talloc-based interface. More development will come on top of this. Remove the "mangled map" parameter. Jeremy. (This used to be commit dee8beba7a92b8a3f68bbcc59fd0a827f68c7736) --- source3/smbd/reply.c | 489 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 312 insertions(+), 177 deletions(-) (limited to 'source3/smbd/reply.c') diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 2694176ca7..dec0e26c41 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -285,11 +285,10 @@ size_t srvstr_get_path(const char *inbuf, uint16 smb_flags2, char *dest, } /**************************************************************************** - Check if we have a correct fsp pointing to a file. Replacement for the - CHECK_FSP macro. + Check if we have a correct fsp pointing to a file. Basic check for open fsp. ****************************************************************************/ -BOOL check_fsp(connection_struct *conn, struct smb_request *req, +BOOL check_fsp_open(connection_struct *conn, struct smb_request *req, files_struct *fsp, struct current_user *user) { if (!(fsp) || !(conn)) { @@ -300,6 +299,20 @@ BOOL check_fsp(connection_struct *conn, struct smb_request *req, reply_nterror(req, NT_STATUS_INVALID_HANDLE); return False; } + return True; +} + +/**************************************************************************** + Check if we have a correct fsp pointing to a file. Replacement for the + CHECK_FSP macro. +****************************************************************************/ + +BOOL check_fsp(connection_struct *conn, struct smb_request *req, + files_struct *fsp, struct current_user *user) +{ + if (!check_fsp_open(conn, req, fsp, user)) { + return False; + } if ((fsp)->is_directory) { reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST); return False; @@ -755,7 +768,9 @@ void reply_ioctl(connection_struct *conn, struct smb_request *req) SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */ SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */ SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */ - p = smb_buf(req->outbuf) + 1; /* Allow for alignment */ + p = smb_buf(req->outbuf); + memset(p, '\0', replysize+1); /* valgrind-safe. */ + p += 1; /* Allow for alignment */ switch (ioctl_code) { case IOCTL_QUERY_JOB_INFO: @@ -775,8 +790,7 @@ void reply_ioctl(connection_struct *conn, struct smb_request *req) srvstr_push((char *)req->outbuf, req->flags2, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII); - } - else { + } else { memset(p+18, 0, 13); } break; @@ -809,14 +823,15 @@ static NTSTATUS map_checkpath_error(const char *inbuf, NTSTATUS status) void reply_checkpath(connection_struct *conn, struct smb_request *req) { - pstring name; + pstring name_in; + char *name = NULL; SMB_STRUCT_STAT sbuf; NTSTATUS status; START_PROFILE(SMBcheckpath); - srvstr_get_path((char *)req->inbuf, req->flags2, name, - smb_buf(req->inbuf) + 1, sizeof(name), 0, + srvstr_get_path((char *)req->inbuf, req->flags2, name_in, + smb_buf(req->inbuf) + 1, sizeof(name_in), 0, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { status = map_checkpath_error((char *)req->inbuf, status); @@ -825,7 +840,7 @@ void reply_checkpath(connection_struct *conn, struct smb_request *req) return; } - status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, name); + status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, name_in); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -836,9 +851,9 @@ void reply_checkpath(connection_struct *conn, struct smb_request *req) goto path_err; } - DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->inbuf,smb_vwv0))); + DEBUG(3,("reply_checkpath %s mode=%d\n", name_in, (int)SVAL(req->inbuf,smb_vwv0))); - status = unix_convert(conn, name, False, NULL, &sbuf); + status = unix_convert(conn, name_in, False, &name, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { goto path_err; } @@ -899,7 +914,8 @@ void reply_checkpath(connection_struct *conn, struct smb_request *req) void reply_getatr(connection_struct *conn, struct smb_request *req) { - pstring fname; + pstring fname_in; + char *fname = NULL; SMB_STRUCT_STAT sbuf; int mode=0; SMB_OFF_T size=0; @@ -910,8 +926,8 @@ void reply_getatr(connection_struct *conn, struct smb_request *req) START_PROFILE(SMBgetatr); p = smb_buf(req->inbuf) + 1; - p += srvstr_get_path((char *)req->inbuf, req->flags2, fname, p, - sizeof(fname), 0, STR_TERMINATE, &status); + p += srvstr_get_path((char *)req->inbuf, req->flags2, fname_in, p, + sizeof(fname_in), 0, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBgetatr); @@ -919,7 +935,7 @@ void reply_getatr(connection_struct *conn, struct smb_request *req) } status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - fname); + fname_in); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -934,7 +950,7 @@ void reply_getatr(connection_struct *conn, struct smb_request *req) /* dos smetimes asks for a stat of "" - it returns a "hidden directory" under WfWg - weird! */ - if (*fname == '\0') { + if (*fname_in == '\0') { mode = aHIDDEN | aDIR; if (!CAN_WRITE(conn)) { mode |= aRONLY; @@ -942,7 +958,7 @@ void reply_getatr(connection_struct *conn, struct smb_request *req) size = 0; mtime = 0; } else { - status = unix_convert(conn, fname, False, NULL,&sbuf); + status = unix_convert(conn, fname_in, False, &fname, NULL,&sbuf); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBgetatr); @@ -997,7 +1013,8 @@ void reply_getatr(connection_struct *conn, struct smb_request *req) void reply_setatr(connection_struct *conn, struct smb_request *req) { - pstring fname; + pstring fname_in; + char *fname = NULL; int mode; time_t mtime; SMB_STRUCT_STAT sbuf; @@ -1012,8 +1029,8 @@ void reply_setatr(connection_struct *conn, struct smb_request *req) } p = smb_buf(req->inbuf) + 1; - p += srvstr_get_path((char *)req->inbuf, req->flags2, fname, p, - sizeof(fname), 0, STR_TERMINATE, &status); + p += srvstr_get_path((char *)req->inbuf, req->flags2, fname_in, p, + sizeof(fname_in), 0, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBsetatr); @@ -1021,7 +1038,7 @@ void reply_setatr(connection_struct *conn, struct smb_request *req) } status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - fname); + fname_in); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -1034,7 +1051,7 @@ void reply_setatr(connection_struct *conn, struct smb_request *req) return; } - status = unix_convert(conn, fname, False, NULL, &sbuf); + status = unix_convert(conn, fname_in, False, &fname, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBsetatr); @@ -1147,7 +1164,7 @@ void reply_dskattr(connection_struct *conn, struct smb_request *req) void reply_search(connection_struct *conn, struct smb_request *req) { pstring mask; - pstring directory; + char *directory = NULL; pstring fname; SMB_OFF_T size; uint32 mode; @@ -1181,7 +1198,7 @@ void reply_search(connection_struct *conn, struct smb_request *req) return; } - *mask = *directory = *fname = 0; + *mask = *fname = 0; /* If we were called as SMBffirst then we must expect close. */ if(CVAL(req->inbuf,smb_com) == SMBffirst) { @@ -1225,8 +1242,7 @@ void reply_search(connection_struct *conn, struct smb_request *req) if (status_len == 0) { SMB_STRUCT_STAT sbuf; - pstrcpy(directory,path); - nt_status = unix_convert(conn, directory, True, NULL, &sbuf); + nt_status = unix_convert(conn, path, True, &directory, NULL, &sbuf); if (!NT_STATUS_IS_OK(nt_status)) { reply_nterror(req, nt_status); END_PROFILE(SMBsearch); @@ -1243,17 +1259,43 @@ void reply_search(connection_struct *conn, struct smb_request *req) p = strrchr_m(directory,'/'); if (!p) { pstrcpy(mask,directory); - pstrcpy(directory,"."); + directory = talloc_strdup(talloc_tos(),"."); + if (!directory) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBsearch); + return; + } } else { *p = 0; pstrcpy(mask,p+1); } if (*directory == '\0') { - pstrcpy(directory,"."); + directory = talloc_strdup(talloc_tos(),"."); + if (!directory) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBsearch); + return; + } } memset((char *)status,'\0',21); SCVAL(status,0,(dirtype & 0x1F)); + + nt_status = dptr_create(conn, + directory, + True, + expect_close, + req->smbpid, + mask, + mask_contains_wcard, + dirtype, + &conn->dirptr); + if (!NT_STATUS_IS_OK(nt_status)) { + reply_nterror(req, nt_status); + END_PROFILE(SMBsearch); + return; + } + dptr_num = dptr_dnum(conn->dirptr); } else { int status_dirtype; @@ -1263,7 +1305,7 @@ void reply_search(connection_struct *conn, struct smb_request *req) dirtype = status_dirtype; } - conn->dirptr = dptr_fetch(status+12,&dptr_num); + conn->dirptr = dptr_fetch(status+12,&dptr_num); if (!conn->dirptr) { goto SearchEmpty; } @@ -1274,25 +1316,6 @@ void reply_search(connection_struct *conn, struct smb_request *req) * check from the initial saved string. */ mask_contains_wcard = ms_has_wild(mask); - } - - if (status_len == 0) { - nt_status = dptr_create(conn, - directory, - True, - expect_close, - req->smbpid, - mask, - mask_contains_wcard, - dirtype, - &conn->dirptr); - if (!NT_STATUS_IS_OK(nt_status)) { - reply_nterror(req, nt_status); - END_PROFILE(SMBsearch); - return; - } - dptr_num = dptr_dnum(conn->dirptr); - } else { dirtype = dptr_attr(dptr_num); } @@ -1393,13 +1416,18 @@ void reply_search(connection_struct *conn, struct smb_request *req) /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */ SSVAL(req->outbuf, smb_flg2, (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS))); - - if ((! *directory) && dptr_path(dptr_num)) - slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); - DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%u of %u\n", + if (!directory) { + directory = dptr_path(dptr_num); + } + + DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n", smb_fn_name(CVAL(req->inbuf,smb_com)), - mask, directory, dirtype, numentries, maxentries ) ); + mask, + directory ? directory : "./", + dirtype, + numentries, + maxentries )); END_PROFILE(SMBsearch); return; @@ -1468,7 +1496,8 @@ void reply_fclose(connection_struct *conn, struct smb_request *req) void reply_open(connection_struct *conn, struct smb_request *req) { - pstring fname; + pstring fname_in; + char *fname = NULL; uint32 fattr=0; SMB_OFF_T size = 0; time_t mtime=0; @@ -1496,8 +1525,8 @@ void reply_open(connection_struct *conn, struct smb_request *req) deny_mode = SVAL(req->inbuf,smb_vwv0); dos_attr = SVAL(req->inbuf,smb_vwv1); - srvstr_get_path((char *)req->inbuf, req->flags2, fname, - smb_buf(req->inbuf)+1, sizeof(fname), 0, + srvstr_get_path((char *)req->inbuf, req->flags2, fname_in, + smb_buf(req->inbuf)+1, sizeof(fname_in), 0, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -1506,7 +1535,7 @@ void reply_open(connection_struct *conn, struct smb_request *req) } status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - fname); + fname_in); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -1519,7 +1548,7 @@ void reply_open(connection_struct *conn, struct smb_request *req) return; } - status = unix_convert(conn, fname, False, NULL, &sbuf); + status = unix_convert(conn, fname_in, False, &fname, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBopen); @@ -1602,7 +1631,8 @@ void reply_open(connection_struct *conn, struct smb_request *req) void reply_open_and_X(connection_struct *conn, struct smb_request *req) { - pstring fname; + pstring fname_in; + char *fname = NULL; uint16 open_flags; int deny_mode; uint32 smb_attr; @@ -1658,8 +1688,8 @@ void reply_open_and_X(connection_struct *conn, struct smb_request *req) } /* XXXX we need to handle passed times, sattr and flags */ - srvstr_get_path((char *)req->inbuf, req->flags2, fname, - smb_buf(req->inbuf), sizeof(fname), 0, STR_TERMINATE, + srvstr_get_path((char *)req->inbuf, req->flags2, fname_in, + smb_buf(req->inbuf), sizeof(fname_in), 0, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -1668,7 +1698,7 @@ void reply_open_and_X(connection_struct *conn, struct smb_request *req) } status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - fname); + fname_in); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBopenX); if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { @@ -1680,7 +1710,7 @@ void reply_open_and_X(connection_struct *conn, struct smb_request *req) return; } - status = unix_convert(conn, fname, False, NULL, &sbuf); + status = unix_convert(conn, fname_in, False, &fname, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBopenX); @@ -1846,7 +1876,8 @@ void reply_ulogoffX(connection_struct *conn, struct smb_request *req) void reply_mknew(connection_struct *conn, struct smb_request *req) { - pstring fname; + pstring fname_in; + char *fname = NULL; int com; uint32 fattr = 0; struct timespec ts[2]; @@ -1875,8 +1906,8 @@ void reply_mknew(connection_struct *conn, struct smb_request *req) srv_make_unix_date3(req->inbuf + smb_vwv1)); /* mtime. */ - srvstr_get_path((char *)req->inbuf, req->flags2, fname, - smb_buf(req->inbuf) + 1, sizeof(fname), 0, + srvstr_get_path((char *)req->inbuf, req->flags2, fname_in, + smb_buf(req->inbuf) + 1, sizeof(fname_in), 0, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -1885,7 +1916,7 @@ void reply_mknew(connection_struct *conn, struct smb_request *req) } status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - fname); + fname_in); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBcreate); if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { @@ -1897,7 +1928,7 @@ void reply_mknew(connection_struct *conn, struct smb_request *req) return; } - status = unix_convert(conn, fname, False, NULL, &sbuf); + status = unix_convert(conn, fname_in, False, &fname, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBcreate); @@ -1974,7 +2005,8 @@ void reply_mknew(connection_struct *conn, struct smb_request *req) void reply_ctemp(connection_struct *conn, struct smb_request *req) { - pstring fname; + pstring fname_in; + char *fname = NULL; uint32 fattr; files_struct *fsp; int oplock_request; @@ -1994,22 +2026,22 @@ void reply_ctemp(connection_struct *conn, struct smb_request *req) fattr = SVAL(req->inbuf,smb_vwv0); oplock_request = CORE_OPLOCK_REQUEST(req->inbuf); - srvstr_get_path((char *)req->inbuf, req->flags2, fname, - smb_buf(req->inbuf)+1, sizeof(fname), 0, STR_TERMINATE, + srvstr_get_path((char *)req->inbuf, req->flags2, fname_in, + smb_buf(req->inbuf)+1, sizeof(fname_in), 0, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBctemp); return; } - if (*fname) { - pstrcat(fname,"/TMXXXXXX"); + if (*fname_in) { + pstrcat(fname_in,"/TMXXXXXX"); } else { - pstrcat(fname,"TMXXXXXX"); + pstrcat(fname_in,"TMXXXXXX"); } status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - fname); + fname_in); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -2022,7 +2054,7 @@ void reply_ctemp(connection_struct *conn, struct smb_request *req) return; } - status = unix_convert(conn, fname, False, NULL, &sbuf); + status = unix_convert(conn, fname_in, False, &fname, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBctemp); @@ -2266,22 +2298,23 @@ static NTSTATUS do_unlink(connection_struct *conn, struct smb_request *req, ****************************************************************************/ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, - uint32 dirtype, char *name, BOOL has_wild) + uint32 dirtype, const char *name_in, BOOL has_wild) { pstring directory; pstring mask; + char *name = NULL; char *p; int count=0; NTSTATUS status = NT_STATUS_OK; SMB_STRUCT_STAT sbuf; - + *directory = *mask = 0; - - status = unix_convert(conn, name, has_wild, NULL, &sbuf); + + status = unix_convert(conn, name_in, has_wild, &name, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { return status; } - + p = strrchr_m(name,'/'); if (!p) { pstrcpy(directory,"."); @@ -2291,7 +2324,7 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, pstrcpy(directory,name); pstrcpy(mask,p+1); } - + /* * We should only check the mangled cache * here if unix_convert failed. This means @@ -2300,10 +2333,18 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, * for a possible mangle. This patch from * Tine Smukavec . */ - - if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params)) - mangle_check_cache( mask, sizeof(pstring)-1, conn->params ); - + + if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params)) { + char *new_mask = NULL; + mangle_lookup_name_from_8_3(talloc_tos(), + mask, + &new_mask, + conn->params ); + if (new_mask) { + pstrcpy(mask, new_mask); + } + } + if (!has_wild) { pstrcat(directory,"/"); pstrcat(directory,mask); @@ -2326,7 +2367,7 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, struct smb_Dir *dir_hnd = NULL; long offset = 0; const char *dname; - + if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) { return NT_STATUS_OBJECT_NAME_INVALID; } @@ -2798,6 +2839,7 @@ void reply_lockread(connection_struct *conn, struct smb_request *req) NTSTATUS status; files_struct *fsp; struct byte_range_lock *br_lck = NULL; + char *p = NULL; START_PROFILE(SMBlockread); @@ -2879,7 +2921,9 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n", SSVAL(req->outbuf,smb_vwv0,nread); SSVAL(req->outbuf,smb_vwv5,nread+3); - SSVAL(smb_buf(req->outbuf),1,nread); + p = smb_buf(req->outbuf); + SCVAL(p,0,0); /* pad byte. */ + SSVAL(p,1,nread); DEBUG(3,("lockread fnum=%d num=%d nread=%d\n", fsp->fnum, (int)numtoread, (int)nread)); @@ -4600,14 +4644,15 @@ void reply_printwrite(connection_struct *conn, struct smb_request *req) void reply_mkdir(connection_struct *conn, struct smb_request *req) { - pstring directory; + pstring directory_in; + char *directory = NULL; NTSTATUS status; SMB_STRUCT_STAT sbuf; START_PROFILE(SMBmkdir); - srvstr_get_path((char *)req->inbuf, req->flags2, directory, - smb_buf(req->inbuf) + 1, sizeof(directory), 0, + srvstr_get_path((char *)req->inbuf, req->flags2, directory_in, + smb_buf(req->inbuf) + 1, sizeof(directory_in), 0, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -4617,7 +4662,7 @@ void reply_mkdir(connection_struct *conn, struct smb_request *req) status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - directory); + directory_in); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -4630,7 +4675,7 @@ void reply_mkdir(connection_struct *conn, struct smb_request *req) return; } - status = unix_convert(conn, directory, False, NULL, &sbuf); + status = unix_convert(conn, directory_in, False, &directory, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBmkdir); @@ -4853,13 +4898,14 @@ NTSTATUS rmdir_internals(connection_struct *conn, const char *directory) void reply_rmdir(connection_struct *conn, struct smb_request *req) { - pstring directory; + pstring directory_in; + char *directory = NULL; SMB_STRUCT_STAT sbuf; NTSTATUS status; START_PROFILE(SMBrmdir); - srvstr_get_path((char *)req->inbuf, req->flags2, directory, - smb_buf(req->inbuf) + 1, sizeof(directory), 0, + srvstr_get_path((char *)req->inbuf, req->flags2, directory_in, + smb_buf(req->inbuf) + 1, sizeof(directory_in), 0, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -4869,7 +4915,7 @@ void reply_rmdir(connection_struct *conn, struct smb_request *req) status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - directory); + directory_in); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -4882,7 +4928,8 @@ void reply_rmdir(connection_struct *conn, struct smb_request *req) return; } - status = unix_convert(conn, directory, False, NULL, &sbuf); + status = unix_convert(conn, directory_in, False, &directory, + NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBrmdir); @@ -4914,87 +4961,129 @@ void reply_rmdir(connection_struct *conn, struct smb_request *req) /******************************************************************* Resolve wildcards in a filename rename. - Note that name is in UNIX charset and thus potentially can be more - than fstring buffer (255 bytes) especially in default UTF-8 case. - Therefore, we use pstring inside and all calls should ensure that - name2 is at least pstring-long (they do already) ********************************************************************/ -static BOOL resolve_wildcards(const char *name1, char *name2) +static BOOL resolve_wildcards(TALLOC_CTX *ctx, + const char *name1, + const char *name2, + char **pp_newname) { - pstring root1,root2; - pstring ext1,ext2; + char *name2_copy = NULL; + char *root1 = NULL; + char *root2 = NULL; + char *ext1 = NULL; + char *ext2 = NULL; char *p,*p2, *pname1, *pname2; - int available_space, actual_space; + name2_copy = talloc_strdup(ctx, name2); + if (!name2_copy) { + return False; + } + pname1 = strrchr_m(name1,'/'); - pname2 = strrchr_m(name2,'/'); + pname2 = strrchr_m(name2_copy,'/'); - if (!pname1 || !pname2) - return(False); + if (!pname1 || !pname2) { + return False; + } - pstrcpy(root1,pname1); - pstrcpy(root2,pname2); + /* Truncate the copy of name2 at the last '/' */ + *pname2 = '\0'; + + /* Now go past the '/' */ + pname1++; + pname2++; + + root1 = talloc_strdup(ctx, pname1); + root2 = talloc_strdup(ctx, pname2); + + if (!root1 || !root2) { + return False; + } + p = strrchr_m(root1,'.'); if (p) { *p = 0; - pstrcpy(ext1,p+1); + ext1 = talloc_strdup(ctx, p+1); } else { - pstrcpy(ext1,""); + ext1 = talloc_strdup(ctx, ""); } p = strrchr_m(root2,'.'); if (p) { *p = 0; - pstrcpy(ext2,p+1); + ext2 = talloc_strdup(ctx, p+1); } else { - pstrcpy(ext2,""); + ext2 = talloc_strdup(ctx, ""); + } + + if (!ext1 || !ext2) { + return False; } p = root1; p2 = root2; while (*p2) { if (*p2 == '?') { + /* Hmmm. Should this be mb-aware ? */ *p2 = *p; p2++; } else if (*p2 == '*') { - pstrcpy(p2, p); + *p2 = '\0'; + root2 = talloc_asprintf(ctx, "%s%s", + root2, + p); + if (!root2) { + return False; + } break; } else { p2++; } - if (*p) + if (*p) { p++; + } } p = ext1; p2 = ext2; while (*p2) { if (*p2 == '?') { + /* Hmmm. Should this be mb-aware ? */ *p2 = *p; p2++; } else if (*p2 == '*') { - pstrcpy(p2, p); + *p2 = '\0'; + ext2 = talloc_asprintf(ctx, "%s%s", + ext2, + p); + if (!ext2) { + return False; + } break; } else { p2++; } - if (*p) + if (*p) { p++; + } } - available_space = sizeof(pstring) - PTR_DIFF(pname2, name2); - - if (ext2[0]) { - actual_space = snprintf(pname2, available_space - 1, "%s.%s", root2, ext2); - if (actual_space >= available_space - 1) { - DEBUG(1,("resolve_wildcards: can't fit resolved name into specified buffer (overrun by %d bytes)\n", - actual_space - available_space)); - } + if (*ext2) { + *pp_newname = talloc_asprintf(ctx, "%s/%s.%s", + name2_copy, + root2, + ext2); } else { - pstrcpy_base(pname2, root2, name2); + *pp_newname = talloc_asprintf(ctx, "%s/%s", + name2_copy, + root2); } - return(True); + if (!*pp_newname) { + return False; + } + + return True; } /**************************************************************************** @@ -5110,11 +5199,14 @@ static void notify_rename(connection_struct *conn, BOOL is_dir, Rename an open file - given an fsp. ****************************************************************************/ -NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, - pstring newname, - const char *newname_last_component, - uint32 attrs, BOOL replace_if_exists) +NTSTATUS rename_internals_fsp(connection_struct *conn, + files_struct *fsp, + char *newname, + const char *newname_last_component, + uint32 attrs, + BOOL replace_if_exists) { + TALLOC_CTX *ctx = talloc_tos(); SMB_STRUCT_STAT sbuf, sbuf1; NTSTATUS status = NT_STATUS_OK; struct share_mode_lock *lck = NULL; @@ -5126,14 +5218,15 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, if (!NT_STATUS_IS_OK(status)) { return status; } - + /* Ensure newname contains a '/' */ if(strrchr_m(newname,'/') == 0) { - pstring tmpstr; - - pstrcpy(tmpstr, "./"); - pstrcat(tmpstr, newname); - pstrcpy(newname, tmpstr); + newname = talloc_asprintf(ctx, + "./%s", + newname); + if (!newname) { + return NT_STATUS_NO_MEMORY; + } } /* @@ -5147,7 +5240,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, if((conn->case_sensitive == False) && (conn->case_preserve == True) && strequal(newname, fsp->fsp_name)) { char *p; - pstring newname_modified_last_component; + char *newname_modified_last_component = NULL; /* * Get the last component of the modified name. @@ -5155,15 +5248,23 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, * character above. */ p = strrchr_m(newname,'/'); - pstrcpy(newname_modified_last_component,p+1); - - if(strcsequal(newname_modified_last_component, + newname_modified_last_component = talloc_strdup(ctx, + p+1); + if (!newname_modified_last_component) { + return NT_STATUS_NO_MEMORY; + } + + if(strcsequal(newname_modified_last_component, newname_last_component) == False) { /* * Replace the modified last component with * the original. */ - pstrcpy(p+1, newname_last_component); + *p = '\0'; /* Truncate at the '/' */ + newname = talloc_asprintf(ctx, + "%s/%s", + newname, + newname_last_component); } } @@ -5263,7 +5364,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, } } TALLOC_FREE(lck); - return NT_STATUS_OK; + return NT_STATUS_OK; } TALLOC_FREE(lck); @@ -5273,7 +5374,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, } else { status = map_nt_error_from_unix(errno); } - + DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n", nt_errstr(status), fsp->fsp_name,newname)); @@ -5286,8 +5387,8 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, ****************************************************************************/ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, - pstring name, - pstring newname, + const char *name_in, + const char *newname_in, uint32 attrs, BOOL replace_if_exists, BOOL src_has_wild, @@ -5295,8 +5396,10 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, { pstring directory; pstring mask; - pstring last_component_src; - pstring last_component_dest; + char *last_component_src = NULL; + char *last_component_dest = NULL; + char *name = NULL; + char *newname = NULL; char *p; int count=0; NTSTATUS status = NT_STATUS_OK; @@ -5311,12 +5414,14 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, ZERO_STRUCT(sbuf1); ZERO_STRUCT(sbuf2); - status = unix_convert(conn, name, src_has_wild, last_component_src, &sbuf1); + status = unix_convert(conn, name_in, src_has_wild, &name, + &last_component_src, &sbuf1); if (!NT_STATUS_IS_OK(status)) { return status; } - status = unix_convert(conn, newname, dest_has_wild, last_component_dest, &sbuf2); + status = unix_convert(conn, newname_in, dest_has_wild, &newname, + &last_component_dest, &sbuf2); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -5351,7 +5456,14 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, */ if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) { - mangle_check_cache( mask, sizeof(pstring)-1, conn->params ); + char *new_mask = NULL; + mangle_lookup_name_from_8_3(talloc_tos(), + mask, + &new_mask, + conn->params ); + if (new_mask) { + pstrcpy(mask, new_mask); + } } if (!src_has_wild) { @@ -5365,16 +5477,17 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, /* Add a terminating '/' to the directory name. */ pstrcat(directory,"/"); pstrcat(directory,mask); - + /* Ensure newname contains a '/' also */ if(strrchr_m(newname,'/') == 0) { - pstring tmpstr; - - pstrcpy(tmpstr, "./"); - pstrcat(tmpstr, newname); - pstrcpy(newname, tmpstr); + newname = talloc_asprintf(talloc_tos(), + "./%s", + newname); + if (!newname) { + return NT_STATUS_NO_MEMORY; + } } - + DEBUG(3, ("rename_internals: case_sensitive = %d, " "case_preserve = %d, short case preserve = %d, " "directory = %s, newname = %s, " @@ -5385,11 +5498,14 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, /* The dest name still may have wildcards. */ if (dest_has_wild) { - if (!resolve_wildcards(directory,newname)) { + char *mod_newname = NULL; + if (!resolve_wildcards(talloc_tos(), + directory,newname,&mod_newname)) { DEBUG(6, ("rename_internals: resolve_wildcards %s %s failed\n", directory,newname)); return NT_STATUS_NO_MEMORY; } + newname = mod_newname; } ZERO_STRUCT(sbuf1); @@ -5452,6 +5568,7 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, files_struct *fsp; pstring fname; BOOL sysdir_entry = False; + char *mod_destname = NULL; pstrcpy(fname,dname); @@ -5483,11 +5600,13 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, pstrcpy(destname,newname); - if (!resolve_wildcards(fname,destname)) { + if (!resolve_wildcards(talloc_tos(), + fname,destname,&mod_destname)) { DEBUG(6, ("resolve_wildcards %s %s failed\n", fname, destname)); continue; } + pstrcpy(destname,mod_destname); ZERO_STRUCT(sbuf1); SMB_VFS_STAT(conn, fname, &sbuf1); @@ -5756,9 +5875,12 @@ NTSTATUS copy_file(connection_struct *conn, void reply_copy(connection_struct *conn, struct smb_request *req) { - pstring name; + pstring name_in; + char *name = NULL; + pstring newname_in; + char *newname = NULL; pstring directory; - pstring mask,newname; + pstring mask; char *p; int count=0; int error = ERRnoaccess; @@ -5787,16 +5909,16 @@ void reply_copy(connection_struct *conn, struct smb_request *req) *directory = *mask = 0; p = smb_buf(req->inbuf); - p += srvstr_get_path_wcard((char *)req->inbuf, req->flags2, name, p, - sizeof(name), 0, STR_TERMINATE, &status, + p += srvstr_get_path_wcard((char *)req->inbuf, req->flags2, name_in, p, + sizeof(name_in), 0, STR_TERMINATE, &status, &source_has_wild); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBcopy); return; } - p += srvstr_get_path_wcard((char *)req->inbuf, req->flags2, newname, p, - sizeof(newname), 0, STR_TERMINATE, &status, + p += srvstr_get_path_wcard((char *)req->inbuf, req->flags2, newname_in, p, + sizeof(newname_in), 0, STR_TERMINATE, &status, &dest_has_wild); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -5804,7 +5926,7 @@ void reply_copy(connection_struct *conn, struct smb_request *req) return; } - DEBUG(3,("reply_copy : %s -> %s\n",name,newname)); + DEBUG(3,("reply_copy : %s -> %s\n",name_in,newname_in)); if (tid2 != conn->cnum) { /* can't currently handle inter share copies XXXX */ @@ -5816,7 +5938,7 @@ void reply_copy(connection_struct *conn, struct smb_request *req) status = resolve_dfspath_wcard(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - name, &source_has_wild); + name_in, &source_has_wild); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -5831,7 +5953,7 @@ void reply_copy(connection_struct *conn, struct smb_request *req) status = resolve_dfspath_wcard(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - newname, &dest_has_wild); + newname_in, &dest_has_wild); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -5844,14 +5966,14 @@ void reply_copy(connection_struct *conn, struct smb_request *req) return; } - status = unix_convert(conn, name, source_has_wild, NULL, &sbuf1); + status = unix_convert(conn, name_in, source_has_wild, &name, NULL, &sbuf1); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBcopy); return; } - status = unix_convert(conn, newname, dest_has_wild, NULL, &sbuf2); + status = unix_convert(conn, newname_in, dest_has_wild, &newname, NULL, &sbuf2); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBcopy); @@ -5900,18 +6022,28 @@ void reply_copy(connection_struct *conn, struct smb_request *req) */ if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) { - mangle_check_cache( mask, sizeof(pstring)-1, conn->params ); + char *new_mask = NULL; + mangle_lookup_name_from_8_3( talloc_tos(), + mask, + &new_mask, + conn->params ); + if (new_mask) { + pstrcpy(mask, new_mask); + } } if (!source_has_wild) { pstrcat(directory,"/"); pstrcat(directory,mask); if (dest_has_wild) { - if (!resolve_wildcards(directory,newname)) { + char *mod_newname = NULL; + if (!resolve_wildcards(talloc_tos(), + directory,newname,&mod_newname)) { reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBcopy); return; } + newname = mod_newname; } status = check_name(conn, directory); @@ -5965,6 +6097,7 @@ void reply_copy(connection_struct *conn, struct smb_request *req) error = ERRbadfile; while ((dname = ReadDirName(dir_hnd, &offset))) { + char *mod_destname = NULL; pstring fname; pstrcpy(fname,dname); @@ -5979,9 +6112,11 @@ void reply_copy(connection_struct *conn, struct smb_request *req) error = ERRnoaccess; slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); pstrcpy(destname,newname); - if (!resolve_wildcards(fname,destname)) { + if (!resolve_wildcards(talloc_tos(), + fname,destname,&mod_destname)) { continue; } + pstrcpy(destname,mod_destname); status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { -- cgit