diff options
author | Jeremy Allison <jra@samba.org> | 2007-09-12 21:48:20 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:30:41 -0500 |
commit | 12f61e09d943ea7fc4149166077507b5b0b3b4e7 (patch) | |
tree | 8382cf512a97b3159c3cda38eb952c85f8f2237f /source3/smbd | |
parent | 4754b0ec65a3be4380f3216bd3f59c1906db259b (diff) | |
download | samba-12f61e09d943ea7fc4149166077507b5b0b3b4e7.tar.gz samba-12f61e09d943ea7fc4149166077507b5b0b3b4e7.tar.bz2 samba-12f61e09d943ea7fc4149166077507b5b0b3b4e7.zip |
r25117: The mega-patch Jerry was waiting for. Remove all pstrings from
the main server code paths. We should now be able to cope with
paths up to PATH_MAX length now.
Final job will be to add the TALLOC_CTX * parameter to
unix_convert to make it explicit (for Volker).
Jeremy.
(This used to be commit 7f0db75fb0f24873577dcb758a2ecee74fdc4297)
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/close.c | 3 | ||||
-rw-r--r-- | source3/smbd/dir.c | 135 | ||||
-rw-r--r-- | source3/smbd/mangle.c | 2 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 23 | ||||
-rw-r--r-- | source3/smbd/open.c | 40 | ||||
-rw-r--r-- | source3/smbd/posix_acls.c | 64 | ||||
-rw-r--r-- | source3/smbd/process.c | 2 | ||||
-rw-r--r-- | source3/smbd/reply.c | 469 | ||||
-rw-r--r-- | source3/smbd/service.c | 22 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 329 | ||||
-rw-r--r-- | source3/smbd/vfs.c | 110 |
11 files changed, 731 insertions, 468 deletions
diff --git a/source3/smbd/close.c b/source3/smbd/close.c index 4eb1a30342..40db9f9b7f 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -478,7 +478,8 @@ static NTSTATUS close_directory(files_struct *fsp, enum file_close_type close_ty TALLOC_FREE(lck); - status = rmdir_internals(fsp->conn, fsp->fsp_name); + status = rmdir_internals(talloc_tos(), + fsp->conn, fsp->fsp_name); DEBUG(5,("close_directory: %s. Delete on close was set - " "deleting directory returned %s.\n", diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 7a6815b680..a7b1b020b8 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -1,18 +1,19 @@ -/* +/* Unix SMB/CIFS implementation. Directory handling routines Copyright (C) Andrew Tridgell 1992-1998 - + Copyright (C) Jeremy Allison 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 the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -72,15 +73,25 @@ static int dirhandles_open = 0; Make a dir struct. ****************************************************************************/ -void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T size,uint32 mode,time_t date, BOOL uc) -{ +BOOL make_dir_struct(TALLOC_CTX *ctx, + char *buf, + const char *mask, + const char *fname, + SMB_OFF_T size, + uint32 mode, + time_t date, + BOOL uc) +{ char *p; - pstring mask2; + char *mask2 = talloc_strdup(ctx, mask); - pstrcpy(mask2,mask); + if (!mask2) { + return False; + } - if ((mode & aDIR) != 0) + if ((mode & aDIR) != 0) { size = 0; + } memset(buf+1,' ',11); if ((p = strchr_m(mask2,'.')) != NULL) { @@ -88,8 +99,9 @@ void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T si push_ascii(buf+1,mask2,8, 0); push_ascii(buf+9,p+1,3, 0); *p = '.'; - } else + } else { push_ascii(buf+1,mask2,11, 0); + } memset(buf+21,'\0',DIR_STRUCT_SIZE-21); SCVAL(buf,21,mode); @@ -100,6 +112,7 @@ void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T si Strange, but verified on W2K3. Needed for OS/2. JRA. */ push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0); DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname)); + return True; } /**************************************************************************** @@ -238,7 +251,7 @@ static void dptr_close_internal(struct dptr_struct *dptr) DLIST_REMOVE(dirptrs, dptr); - /* + /* * Free the dnum in the bitmap. Remember the dnum value is always * biased by one with respect to the bitmap. */ @@ -563,7 +576,10 @@ static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffs Return the next visible file name, skipping veto'd and invisible files. ****************************************************************************/ -const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst) +const char *dptr_ReadDirName(TALLOC_CTX *ctx, + struct dptr_struct *dptr, + long *poffset, + SMB_STRUCT_STAT *pst) { SET_STAT_INVALID(*pst); @@ -578,7 +594,7 @@ const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT } if (!dptr->did_stat) { - pstring pathreal; + char *pathreal = NULL; /* We know the stored wcard contains no wildcard characters. See if we can match with a stat call. If we can't, then set did_stat to true to @@ -602,14 +618,19 @@ const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT return dptr->wcard; } - pstrcpy(pathreal,dptr->path); - pstrcat(pathreal,"/"); - pstrcat(pathreal,dptr->wcard); + pathreal = talloc_asprintf(ctx, + "%s/%s", + dptr->path, + dptr->wcard); + if (!pathreal) { + return NULL; + } if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) { /* We need to set the underlying dir_hnd offset to -1 also as this function is usually called with the output from TellDir. */ dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET; + TALLOC_FREE(pathreal); return dptr->wcard; } else { /* If we get any other error than ENOENT or ENOTDIR @@ -618,10 +639,13 @@ const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT /* We need to set the underlying dir_hdn offset to -1 also as this function is usually called with the output from TellDir. */ dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET; + TALLOC_FREE(pathreal); return dptr->wcard; } } + TALLOC_FREE(pathreal); + /* In case sensitive mode we don't search - we know if it doesn't exist with a stat we will fail. */ @@ -768,35 +792,43 @@ static BOOL mangle_mask_match(connection_struct *conn, Get an 8.3 directory entry. ****************************************************************************/ -BOOL get_dir_entry(connection_struct *conn,char *mask,uint32 dirtype, pstring fname, - SMB_OFF_T *size,uint32 *mode,time_t *date,BOOL check_descend) +BOOL get_dir_entry(TALLOC_CTX *ctx, + connection_struct *conn, + const char *mask, + uint32 dirtype, + char **pp_fname_out, + SMB_OFF_T *size, + uint32 *mode, + time_t *date, + BOOL check_descend) { - const char *dname; + const char *dname = NULL; BOOL found = False; SMB_STRUCT_STAT sbuf; - pstring path; - pstring pathreal; - pstring filename; + char *pathreal = NULL; + const char *filename = NULL; BOOL needslash; - *path = *pathreal = *filename = 0; + *pp_fname_out = NULL; needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/'); - if (!conn->dirptr) + if (!conn->dirptr) { return(False); + } while (!found) { long curoff = dptr_TellDir(conn->dirptr); - dname = dptr_ReadDirName(conn->dirptr, &curoff, &sbuf); + dname = dptr_ReadDirName(ctx, conn->dirptr, &curoff, &sbuf); DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n", (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd))); - if (dname == NULL) + if (dname == NULL) { return(False); + } - pstrcpy(filename,dname); + filename = dname; /* notice the special *.* handling. This appears to be the only difference between the wildcard handling in this routine and in the trans2 routines. @@ -805,44 +837,65 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,uint32 dirtype, pstring fn if ((strcmp(mask,"*.*") == 0) || mask_match_search(filename,mask,False) || mangle_mask_match(conn,filename,mask)) { + char mname[13]; if (!mangle_is_8_3(filename, False, conn->params)) { - char mname[13]; if (!name_to_8_3(filename,mname,False, conn->params)) { continue; } - pstrcpy(filename,mname); + filename = mname; + } + + if (needslash) { + pathreal = talloc_asprintf(ctx, + "%s/%s", + conn->dirpath, + dname); + } else { + pathreal = talloc_asprintf(ctx, + "%s%s", + conn->dirpath, + dname); + } + if (!pathreal) { + return False; } - pstrcpy(fname,filename); - *path = 0; - pstrcpy(path,conn->dirpath); - if(needslash) - pstrcat(path,"/"); - pstrcpy(pathreal,path); - pstrcat(path,fname); - pstrcat(pathreal,dname); if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) { - DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) )); + DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n", + pathreal, strerror(errno) )); + TALLOC_FREE(pathreal); continue; } - + *mode = dos_mode(conn,pathreal,&sbuf); if (!dir_check_ftype(conn,*mode,dirtype)) { DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",filename,(unsigned int)*mode,(unsigned int)dirtype)); + TALLOC_FREE(pathreal); continue; } *size = sbuf.st_size; *date = sbuf.st_mtime; - DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname)); + DEBUG(3,("get_dir_entry mask=[%s] found %s " + "fname=%s (%s)\n", + mask, + pathreal, + dname, + filename)); found = True; + *pp_fname_out = talloc_strdup(ctx, filename); + if (!*pp_fname_out) { + return False; + } + DirCacheAdd(conn->dirptr->dir_hnd, dname, curoff); + TALLOC_FREE(pathreal); } } @@ -1198,7 +1251,7 @@ void SeekDir(struct smb_Dir *dirp, long offset) if (offset != dirp->offset) { if (offset == START_OF_DIRECTORY_OFFSET) { RewindDir(dirp, &offset); - /* + /* * Ok we should really set the file number here * to 1 to enable ".." to be returned next. Trouble * is I'm worried about callers using SeekDir(dirp,0) diff --git a/source3/smbd/mangle.c b/source3/smbd/mangle.c index 61490c444e..4c00f6d14a 100644 --- a/source3/smbd/mangle.c +++ b/source3/smbd/mangle.c @@ -135,6 +135,8 @@ BOOL name_to_8_3(const char *in, BOOL cache83, const struct share_params *p) { + memset(out,'\0',13); + /* name mangling can be disabled for speed, in which case we just truncate the string */ if (!lp_manglednames(p)) { diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 7886ee86ce..c40fbc763c 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -2050,16 +2050,18 @@ void reply_ntrename(connection_struct *conn, struct smb_request *req) switch(rename_type) { case RENAME_FLAG_RENAME: - status = rename_internals(conn, req, oldname, newname, - attrs, False, src_has_wcard, - dest_has_wcard); + status = rename_internals(ctx, conn, req, oldname, + newname, attrs, False, src_has_wcard, + dest_has_wcard); break; case RENAME_FLAG_HARD_LINK: if (src_has_wcard || dest_has_wcard) { /* No wildcards. */ status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; } else { - status = hardlink_internals(conn, oldname, newname); + status = hardlink_internals(conn, + oldname, + newname); } break; case RENAME_FLAG_COPY: @@ -2235,8 +2237,15 @@ static void call_nt_transact_rename(connection_struct *conn, return; } - status = rename_internals(conn, req, fsp->fsp_name, - new_name, 0, replace_if_exists, False, dest_has_wcard); + status = rename_internals(ctx, + conn, + req, + fsp->fsp_name, + new_name, + 0, + replace_if_exists, + False, + dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { @@ -2252,7 +2261,7 @@ static void call_nt_transact_rename(connection_struct *conn, */ send_nt_replies(req, NT_STATUS_OK, NULL, 0, NULL, 0); - DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", + DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", fsp->fsp_name, new_name)); return; diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 691599ca97..8e1068e708 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -117,22 +117,26 @@ static void change_file_owner_to_parent(connection_struct *conn, (unsigned int)parent_st.st_uid )); } -static void change_dir_owner_to_parent(connection_struct *conn, +static NTSTATUS change_dir_owner_to_parent(connection_struct *conn, const char *inherit_from_dir, const char *fname, SMB_STRUCT_STAT *psbuf) { - pstring saved_dir; + char *saved_dir = NULL; SMB_STRUCT_STAT sbuf; SMB_STRUCT_STAT parent_st; + TALLOC_CTX *ctx = talloc_stackframe(); + NTSTATUS status = NT_STATUS_OK; int ret; ret = SMB_VFS_STAT(conn, inherit_from_dir, &parent_st); if (ret == -1) { + status = map_nt_error_from_unix(errno); DEBUG(0,("change_dir_owner_to_parent: failed to stat parent " "directory %s. Error was %s\n", inherit_from_dir, strerror(errno) )); - return; + TALLOC_FREE(ctx); + return status; } /* We've already done an lstat into psbuf, and we know it's a @@ -142,14 +146,19 @@ static void change_dir_owner_to_parent(connection_struct *conn, should work on any UNIX (thanks tridge :-). JRA. */ - if (!vfs_GetWd(conn,saved_dir)) { + saved_dir = vfs_GetWd(ctx,conn); + if (!saved_dir) { + status = map_nt_error_from_unix(errno); DEBUG(0,("change_dir_owner_to_parent: failed to get " - "current working directory\n")); - return; + "current working directory. Error was %s\n", + strerror(errno))); + TALLOC_FREE(ctx); + return status; } /* Chdir into the new path. */ if (vfs_ChDir(conn, fname) == -1) { + status = map_nt_error_from_unix(errno); DEBUG(0,("change_dir_owner_to_parent: failed to change " "current working directory to %s. Error " "was %s\n", fname, strerror(errno) )); @@ -157,6 +166,7 @@ static void change_dir_owner_to_parent(connection_struct *conn, } if (SMB_VFS_STAT(conn,".",&sbuf) == -1) { + status = map_nt_error_from_unix(errno); DEBUG(0,("change_dir_owner_to_parent: failed to stat " "directory '.' (%s) Error was %s\n", fname, strerror(errno))); @@ -170,6 +180,7 @@ static void change_dir_owner_to_parent(connection_struct *conn, DEBUG(0,("change_dir_owner_to_parent: " "device/inode/mode on directory %s changed. " "Refusing to chown !\n", fname )); + status = NT_STATUS_ACCESS_DENIED; goto out; } @@ -177,6 +188,7 @@ static void change_dir_owner_to_parent(connection_struct *conn, ret = SMB_VFS_CHOWN(conn, ".", parent_st.st_uid, (gid_t)-1); unbecome_root(); if (ret == -1) { + status = map_nt_error_from_unix(errno); DEBUG(10,("change_dir_owner_to_parent: failed to chown " "directory %s to parent directory uid %u. " "Error was %s\n", fname, @@ -190,7 +202,9 @@ static void change_dir_owner_to_parent(connection_struct *conn, out: + TALLOC_FREE(ctx); vfs_ChDir(conn,saved_dir); + return status; } /**************************************************************************** @@ -500,9 +514,10 @@ static void validate_my_share_entries(int num, if (is_deferred_open_entry(share_entry) && !open_was_deferred(share_entry->op_mid)) { - pstring str; - pstr_sprintf(str, "Got a deferred entry without a request: " - "PANIC: %s\n", share_mode_str(num, share_entry)); + char *str = talloc_asprintf(talloc_tos(), + "Got a deferred entry without a request: " + "PANIC: %s\n", + share_mode_str(num, share_entry)); smb_panic(str); } @@ -539,11 +554,12 @@ static void validate_my_share_entries(int num, panic: { - pstring str; + char *str; DEBUG(0,("validate_my_share_entries: PANIC : %s\n", share_mode_str(num, share_entry) )); - slprintf(str, sizeof(str)-1, "validate_my_share_entries: " - "file %s, oplock_type = 0x%x, op_type = 0x%x\n", + str = talloc_asprintf(talloc_tos(), + "validate_my_share_entries: " + "file %s, oplock_type = 0x%x, op_type = 0x%x\n", fsp->fsp_name, (unsigned int)fsp->oplock_type, (unsigned int)share_entry->op_type ); smb_panic(str); diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index 64051d23b1..f7cadeec3e 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -79,9 +79,9 @@ typedef struct canon_ace { struct pai_entry { struct pai_entry *next, *prev; enum ace_owner owner_type; - posix_id unix_ug; + posix_id unix_ug; }; - + struct pai_val { BOOL pai_protected; unsigned int num_entries; @@ -1001,7 +1001,7 @@ NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_i Ensure the enforced permissions for this share apply. ****************************************************************************/ -static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type) +static void apply_default_perms(const files_struct *fsp, canon_ace *pace, mode_t type) { int snum = SNUM(fsp->conn); mode_t and_bits = (mode_t)0; @@ -1047,7 +1047,7 @@ static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type) static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) { - fstring u_name; + const char *u_name = NULL; /* "Everyone" always matches every uid. */ @@ -1059,7 +1059,11 @@ static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) if (uid_ace->unix_ug.uid == current_user.ut.uid && group_ace->unix_ug.gid == current_user.ut.gid) return True; - fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid)); + /* u_name talloc'ed off tos. */ + u_name = uidtoname(uid_ace->unix_ug.uid); + if (!u_name) { + return False; + } return user_in_group_sid(u_name, &group_ace->trustee); } @@ -1074,7 +1078,7 @@ static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) ****************************************************************************/ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, - files_struct *fsp, + const files_struct *fsp, const DOM_SID *pfile_owner_sid, const DOM_SID *pfile_grp_sid, SMB_STRUCT_STAT *pst, @@ -2106,7 +2110,7 @@ static void arrange_posix_perms( char *filename, canon_ace **pp_list_head) Create a linked list of canonical ACE entries. ****************************************************************************/ -static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf, +static canon_ace *canonicalise_acl( const files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf, const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type) { connection_struct *conn = fsp->conn; @@ -4416,8 +4420,9 @@ static int check_posix_acl_group_access(connection_struct *conn, const char *fna BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname) { - SMB_STRUCT_STAT sbuf; - pstring dname; + SMB_STRUCT_STAT sbuf; + TALLOC_CTX *ctx = talloc_tos(); + char *dname = NULL; int ret; if (!CAN_WRITE(conn)) { @@ -4425,7 +4430,12 @@ BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname) } /* Get the parent directory permission mask and owners. */ - pstrcpy(dname, parent_dirname(fname)); + if (!parent_dirname_talloc(ctx, + fname, + &dname, + NULL)) { + return False; + } if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) { return False; } @@ -4445,7 +4455,7 @@ BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname) #ifdef S_ISVTX /* sticky bit means delete only by owner or root. */ if (sbuf.st_mode & S_ISVTX) { - SMB_STRUCT_STAT sbuf_file; + SMB_STRUCT_STAT sbuf_file; if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) { if (errno == ENOENT) { /* If the file doesn't already exist then @@ -4563,21 +4573,19 @@ BOOL can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_ST descriptor via TALLOC_FREE(). This is designed for dealing with user space access checks in smbd outside of the VFS. For example, checking access rights in OpenEventlog(). - + Assume we are dealing with files (for now) ********************************************************************/ -SEC_DESC* get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) +SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) { SEC_DESC *psd, *ret_sd; connection_struct conn; files_struct finfo; struct fd_handle fh; - pstring path; - pstring filename; - + ZERO_STRUCT( conn ); - + if ( !(conn.mem_ctx = talloc_init( "novfs_get_nt_acl" )) ) { DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n")); return NULL; @@ -4590,35 +4598,33 @@ SEC_DESC* get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) } conn.params->service = -1; - - pstrcpy( path, "/" ); - set_conn_connectpath(&conn, path); - + + set_conn_connectpath(&conn, "/"); + if (!smbd_vfs_init(&conn)) { DEBUG(0,("get_nt_acl_no_snum: Unable to create a fake connection struct!\n")); conn_free_internal( &conn ); return NULL; } - + ZERO_STRUCT( finfo ); ZERO_STRUCT( fh ); - + finfo.fnum = -1; finfo.conn = &conn; finfo.fh = &fh; finfo.fh->fd = -1; - pstrcpy( filename, fname ); - finfo.fsp_name = filename; - + finfo.fsp_name = CONST_DISCARD(char *,fname); + if (get_nt_acl( &finfo, DACL_SECURITY_INFORMATION, &psd ) == 0) { DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n")); conn_free_internal( &conn ); return NULL; } - + ret_sd = dup_sec_desc( ctx, psd ); - + conn_free_internal( &conn ); - + return ret_sd; } diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 8b3e85f4b4..29b942de81 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -1227,7 +1227,7 @@ void remove_from_common_flags2(uint32 v) void construct_reply_common(const char *inbuf, char *outbuf) { set_message(inbuf,outbuf,0,0,False); - + SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com)); SIVAL(outbuf,smb_rcls,0); SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 7ac6c4699f..b94c91fe8e 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -1193,9 +1193,9 @@ void reply_dskattr(connection_struct *conn, struct smb_request *req) void reply_search(connection_struct *conn, struct smb_request *req) { - pstring mask; + char *mask = NULL; char *directory = NULL; - pstring fname; + char *fname = NULL; SMB_OFF_T size; uint32 mode; time_t date; @@ -1229,8 +1229,6 @@ void reply_search(connection_struct *conn, struct smb_request *req) return; } - *mask = *fname = 0; - /* If we were called as SMBffirst then we must expect close. */ if(CVAL(req->inbuf,smb_com) == SMBffirst) { expect_close = True; @@ -1297,8 +1295,8 @@ void reply_search(connection_struct *conn, struct smb_request *req) p = strrchr_m(directory,'/'); if (!p) { - pstrcpy(mask,directory); - directory = talloc_strdup(talloc_tos(),"."); + mask = directory; + directory = talloc_strdup(ctx,"."); if (!directory) { reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBsearch); @@ -1306,11 +1304,11 @@ void reply_search(connection_struct *conn, struct smb_request *req) } } else { *p = 0; - pstrcpy(mask,p+1); + mask = p+1; } if (*directory == '\0') { - directory = talloc_strdup(talloc_tos(),"."); + directory = talloc_strdup(ctx,"."); if (!directory) { reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBsearch); @@ -1349,7 +1347,10 @@ void reply_search(connection_struct *conn, struct smb_request *req) goto SearchEmpty; } string_set(&conn->dirpath,dptr_path(dptr_num)); - pstrcpy(mask, dptr_wcard(dptr_num)); + mask = dptr_wcard(dptr_num); + if (!mask) { + goto SearchEmpty; + } /* * For a 'continue' search we have no string. So * check from the initial saved string. @@ -1363,8 +1364,12 @@ void reply_search(connection_struct *conn, struct smb_request *req) if ((dirtype&0x1F) == aVOLID) { char buf[DIR_STRUCT_SIZE]; memcpy(buf,status,21); - make_dir_struct(buf,"???????????",volume_label(SNUM(conn)), - 0,aVOLID,0,!allow_long_path_components); + if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)), + 0,aVOLID,0,!allow_long_path_components)) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBsearch); + return; + } dptr_fill(buf+12,dptr_num); if (dptr_zero(buf+12) && (status_len==0)) { numentries = 1; @@ -1393,12 +1398,23 @@ void reply_search(connection_struct *conn, struct smb_request *req) } for (i=numentries;(i<maxentries) && !finished;i++) { - finished = !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend); + finished = !get_dir_entry(ctx,conn,mask,dirtype,&fname, + &size,&mode,&date,check_descend); if (!finished) { char buf[DIR_STRUCT_SIZE]; memcpy(buf,status,21); - make_dir_struct(buf,mask,fname,size, mode,date, - !allow_long_path_components); + if (!make_dir_struct(ctx, + buf, + mask, + fname, + size, + mode, + date, + !allow_long_path_components)) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBsearch); + return; + } if (!dptr_fill(buf+12,dptr_num)) { break; } @@ -2237,8 +2253,10 @@ static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp, * unlink a file with all relevant access checks *******************************************************************/ -static NTSTATUS do_unlink(connection_struct *conn, struct smb_request *req, - char *fname, uint32 dirtype) +static NTSTATUS do_unlink(connection_struct *conn, + struct smb_request *req, + const char *fname, + uint32 dirtype) { SMB_STRUCT_STAT sbuf; uint32 fattr; @@ -2362,15 +2380,14 @@ static NTSTATUS do_unlink(connection_struct *conn, struct smb_request *req, NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, uint32 dirtype, const char *name_in, BOOL has_wild) { - pstring directory; - pstring mask; + const char *directory = NULL; + char *mask = NULL; char *name = NULL; - char *p; + char *p = NULL; int count=0; NTSTATUS status = NT_STATUS_OK; SMB_STRUCT_STAT sbuf; - - *directory = *mask = 0; + TALLOC_CTX *ctx = talloc_tos(); status = unix_convert(conn, name_in, has_wild, &name, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { @@ -2379,12 +2396,15 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, p = strrchr_m(name,'/'); if (!p) { - pstrcpy(directory,"."); - pstrcpy(mask,name); + directory = talloc_strdup(ctx, "."); + if (!directory) { + return NT_STATUS_NO_MEMORY; + } + mask = name; } else { *p = 0; - pstrcpy(directory,name); - pstrcpy(mask,p+1); + directory = name; + mask = p+1; } /* @@ -2398,18 +2418,23 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params)) { char *new_mask = NULL; - mangle_lookup_name_from_8_3(talloc_tos(), + mangle_lookup_name_from_8_3(ctx, mask, &new_mask, conn->params ); if (new_mask) { - pstrcpy(mask, new_mask); + mask = new_mask; } } if (!has_wild) { - pstrcat(directory,"/"); - pstrcat(directory,mask); + directory = talloc_asprintf(ctx, + "%s/%s", + directory, + mask); + if (!directory) { + return NT_STATUS_NO_MEMORY; + } if (dirtype == 0) { dirtype = FILE_ATTRIBUTE_NORMAL; } @@ -2435,7 +2460,8 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, } if (strequal(mask,"????????.???")) { - pstrcpy(mask,"*"); + mask[0] = '*'; + mask[1] = '\0'; } status = check_name(conn, directory); @@ -2447,35 +2473,37 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, if (dir_hnd == NULL) { return map_nt_error_from_unix(errno); } - + /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then the pattern matches against the long name, otherwise the short name We don't implement this yet XXXX */ - + status = NT_STATUS_NO_SUCH_FILE; while ((dname = ReadDirName(dir_hnd, &offset))) { SMB_STRUCT_STAT st; - pstring fname; - pstrcpy(fname,dname); + char *fname = NULL; if (!is_visible_file(conn, directory, dname, &st, True)) { continue; } /* Quick check for "." and ".." */ - if (fname[0] == '.') { - if (!fname[1] || (fname[1] == '.' && !fname[2])) { - continue; - } + if (ISDOT(dname) || ISDOTDOT(dname)) { + continue; } - if(!mask_match(fname, mask, conn->case_sensitive)) { + if(!mask_match(dname, mask, conn->case_sensitive)) { continue; } - - slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); + + fname = talloc_asprintf(ctx, "%s/%s", + directory, + dname); + if (!fname) { + return NT_STATUS_NO_MEMORY; + } status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { @@ -2485,16 +2513,19 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, status = do_unlink(conn, req, fname, dirtype); if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(fname); continue; } count++; DEBUG(3,("unlink_internals: succesful unlink [%s]\n", fname)); + + TALLOC_FREE(fname); } CloseDir(dir_hnd); } - + if (count == 0 && NT_STATUS_IS_OK(status)) { status = map_nt_error_from_unix(errno); } @@ -2577,9 +2608,12 @@ void reply_unlink(connection_struct *conn, struct smb_request *req) static void fail_readraw(void) { - pstring errstr; - slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)", - strerror(errno) ); + const char *errstr = talloc_asprintf(talloc_tos(), + "FAIL ! reply_readbraw: socket write fail (%s)", + strerror(errno)); + if (!errstr) { + errstr = ""; + } exit_server_cleanly(errstr); } @@ -3097,12 +3131,14 @@ static int setup_readX_header(const uint8 *inbuf, uint8 *outbuf, False); data = smb_buf(outbuf); + memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */ + + SCVAL(outbuf,smb_vwv0,0xFF); SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */ SSVAL(outbuf,smb_vwv5,smb_maxcnt); SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf)); SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16)); SSVAL(smb_buf(outbuf),-2,smb_maxcnt); - SCVAL(outbuf,smb_vwv0,0xFF); /* Reset the outgoing length, set_message truncates at 0x1FFFF. */ _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4)); return outsize; @@ -3136,7 +3172,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, #if defined(WITH_SENDFILE) /* - * We can only use sendfile on a non-chained packet + * We can only use sendfile on a non-chained packet * but we can use on a non-oplocked file. tridge proved this * on a train in Germany :-). JRA. */ @@ -3146,7 +3182,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, uint8 headerbuf[smb_size + 12 * 2]; DATA_BLOB header; - /* + /* * Set up the packet header before send. We * assume here the sendfile will work (get the * correct amount of data). @@ -4790,7 +4826,9 @@ void reply_mkdir(connection_struct *conn, struct smb_request *req) tree recursively. Return True on ok, False on fail. ****************************************************************************/ -static BOOL recursive_rmdir(connection_struct *conn, char *directory) +static BOOL recursive_rmdir(TALLOC_CTX *ctx, + connection_struct *conn, + char *directory) { const char *dname = NULL; BOOL ret = True; @@ -4801,33 +4839,35 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory) return False; while((dname = ReadDirName(dir_hnd, &offset))) { - pstring fullname; + char *fullname = NULL; SMB_STRUCT_STAT st; - if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) + if (ISDOT(dname) || ISDOTDOT(dname)) { continue; + } - if (!is_visible_file(conn, directory, dname, &st, False)) + if (!is_visible_file(conn, directory, dname, &st, False)) { continue; + } /* Construct the full name. */ - if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) { + fullname = talloc_asprintf(ctx, + "%s/%s", + directory, + dname); + if (!fullname) { errno = ENOMEM; ret = False; break; } - pstrcpy(fullname, directory); - pstrcat(fullname, "/"); - pstrcat(fullname, dname); - if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) { ret = False; break; } if(st.st_mode & S_IFDIR) { - if(!recursive_rmdir(conn, fullname)) { + if(!recursive_rmdir(ctx, conn, fullname)) { ret = False; break; } @@ -4839,6 +4879,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory) ret = False; break; } + TALLOC_FREE(fullname); } CloseDir(dir_hnd); return ret; @@ -4848,7 +4889,9 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory) The internals of the rmdir code - called elsewhere. ****************************************************************************/ -NTSTATUS rmdir_internals(connection_struct *conn, const char *directory) +NTSTATUS rmdir_internals(TALLOC_CTX *ctx, + connection_struct *conn, + const char *directory) { int ret; SMB_STRUCT_STAT st; @@ -4878,7 +4921,7 @@ NTSTATUS rmdir_internals(connection_struct *conn, const char *directory) } if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) { - /* + /* * Check to see if the only thing in this directory are * vetoed files/directories. If so then delete them and * retry. If we fail to delete any of them (and we *don't* @@ -4909,34 +4952,40 @@ NTSTATUS rmdir_internals(connection_struct *conn, const char *directory) RewindDir(dir_hnd,&dirpos); while ((dname = ReadDirName(dir_hnd,&dirpos))) { - pstring fullname; + char *fullname = NULL; - if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) + if (ISDOT(dname) || ISDOTDOT(dname)) { continue; - if (!is_visible_file(conn, directory, dname, &st, False)) + } + if (!is_visible_file(conn, directory, dname, &st, False)) { continue; + } + + fullname = talloc_asprintf(ctx, + "%s/%s", + directory, + dname); - /* Construct the full name. */ - if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) { + if(!fullname) { errno = ENOMEM; break; } - pstrcpy(fullname, directory); - pstrcat(fullname, "/"); - pstrcat(fullname, dname); - - if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) + if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) { break; + } if(st.st_mode & S_IFDIR) { if(lp_recursive_veto_delete(SNUM(conn))) { - if(!recursive_rmdir(conn, fullname)) + if(!recursive_rmdir(ctx, conn, fullname)) break; } - if(SMB_VFS_RMDIR(conn,fullname) != 0) + if(SMB_VFS_RMDIR(conn,fullname) != 0) { break; - } else if(SMB_VFS_UNLINK(conn,fullname) != 0) + } + } else if(SMB_VFS_UNLINK(conn,fullname) != 0) { break; + } + TALLOC_FREE(fullname); } CloseDir(dir_hnd); /* Retry the rmdir */ @@ -5012,17 +5061,17 @@ void reply_rmdir(connection_struct *conn, struct smb_request *req) } dptr_closepath(directory, req->smbpid); - status = rmdir_internals(conn, directory); + status = rmdir_internals(ctx, conn, directory); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBrmdir); return; } - + reply_outbuf(req, 0, 0); - + DEBUG( 3, ( "rmdir %s\n", directory ) ); - + END_PROFILE(SMBrmdir); return; } @@ -5451,19 +5500,21 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, /**************************************************************************** The guts of the rename command, split out so it may be called by the NT SMB - code. + code. ****************************************************************************/ -NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, - const char *name_in, - const char *newname_in, - uint32 attrs, - BOOL replace_if_exists, - BOOL src_has_wild, - BOOL dest_has_wild) +NTSTATUS rename_internals(TALLOC_CTX *ctx, + connection_struct *conn, + struct smb_request *req, + const char *name_in, + const char *newname_in, + uint32 attrs, + BOOL replace_if_exists, + BOOL src_has_wild, + BOOL dest_has_wild) { - pstring directory; - pstring mask; + char *directory = NULL; + char *mask = NULL; char *last_component_src = NULL; char *last_component_dest = NULL; char *name = NULL; @@ -5475,9 +5526,6 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, struct smb_Dir *dir_hnd = NULL; const char *dname; long offset = 0; - pstring destname; - - *directory = *mask = 0; ZERO_STRUCT(sbuf1); ZERO_STRUCT(sbuf2); @@ -5496,8 +5544,8 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, /* * Split the old name into directory and last component - * strings. Note that unix_convert may have stripped off a - * leading ./ from both name and newname if the rename is + * strings. Note that unix_convert may have stripped off a + * leading ./ from both name and newname if the rename is * at the root of the share. We need to make sure either both * name and newname contain a / character or neither of them do * as this is checked in resolve_wildcards(). @@ -5505,12 +5553,18 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, p = strrchr_m(name,'/'); if (!p) { - pstrcpy(directory,"."); - pstrcpy(mask,name); + directory = talloc_strdup(ctx, "."); + if (!directory) { + return NT_STATUS_NO_MEMORY; + } + mask = name; } else { *p = 0; - pstrcpy(directory,name); - pstrcpy(mask,p+1); + directory = talloc_strdup(ctx, name); + if (!directory) { + return NT_STATUS_NO_MEMORY; + } + mask = p+1; *p = '/'; /* Replace needed for exceptional test below. */ } @@ -5525,12 +5579,12 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) { char *new_mask = NULL; - mangle_lookup_name_from_8_3(talloc_tos(), + mangle_lookup_name_from_8_3(ctx, mask, &new_mask, conn->params ); if (new_mask) { - pstrcpy(mask, new_mask); + mask = new_mask; } } @@ -5543,12 +5597,16 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, BOOL is_short_name = mangle_is_8_3(name, True, conn->params); /* Add a terminating '/' to the directory name. */ - pstrcat(directory,"/"); - pstrcat(directory,mask); + directory = talloc_asprintf_append(directory, + "/%s", + mask); + if (!directory) { + return NT_STATUS_NO_MEMORY; + } /* Ensure newname contains a '/' also */ if(strrchr_m(newname,'/') == 0) { - newname = talloc_asprintf(talloc_tos(), + newname = talloc_asprintf(ctx, "./%s", newname); if (!newname) { @@ -5559,23 +5617,25 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, DEBUG(3, ("rename_internals: case_sensitive = %d, " "case_preserve = %d, short case preserve = %d, " "directory = %s, newname = %s, " - "last_component_dest = %s, is_8_3 = %d\n", + "last_component_dest = %s, is_8_3 = %d\n", conn->case_sensitive, conn->case_preserve, - conn->short_case_preserve, directory, + conn->short_case_preserve, directory, newname, last_component_dest, is_short_name)); /* The dest name still may have wildcards. */ if (dest_has_wild) { char *mod_newname = NULL; - if (!resolve_wildcards(talloc_tos(), + if (!resolve_wildcards(ctx, directory,newname,&mod_newname)) { - DEBUG(6, ("rename_internals: resolve_wildcards %s %s failed\n", - directory,newname)); + DEBUG(6, ("rename_internals: resolve_wildcards " + "%s %s failed\n", + directory, + newname)); return NT_STATUS_NO_MEMORY; } newname = mod_newname; } - + ZERO_STRUCT(sbuf1); SMB_VFS_STAT(conn, directory, &sbuf1); @@ -5613,41 +5673,38 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, * Wildcards - process each file that matches. */ if (strequal(mask,"????????.???")) { - pstrcpy(mask,"*"); + mask[0] = '*'; + mask[1] = '\0'; } - + status = check_name(conn, directory); if (!NT_STATUS_IS_OK(status)) { return status; } - + dir_hnd = OpenDir(conn, directory, mask, attrs); if (dir_hnd == NULL) { return map_nt_error_from_unix(errno); } - + status = NT_STATUS_NO_SUCH_FILE; /* * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND; * - gentest fix. JRA */ - + while ((dname = ReadDirName(dir_hnd, &offset))) { - files_struct *fsp; - pstring fname; + files_struct *fsp = NULL; + char *fname = NULL; + char *destname = NULL; BOOL sysdir_entry = False; - char *mod_destname = NULL; - pstrcpy(fname,dname); - /* Quick check for "." and ".." */ - if (fname[0] == '.') { - if (!fname[1] || (fname[1] == '.' && !fname[2])) { - if (attrs & aDIR) { - sysdir_entry = True; - } else { - continue; - } + if (ISDOT(dname) || ISDOTDOT(dname)) { + if (attrs & aDIR) { + sysdir_entry = True; + } else { + continue; } } @@ -5655,27 +5712,34 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, continue; } - if(!mask_match(fname, mask, conn->case_sensitive)) { + if(!mask_match(dname, mask, conn->case_sensitive)) { continue; } - + if (sysdir_entry) { status = NT_STATUS_OBJECT_NAME_INVALID; break; } - slprintf(fname, sizeof(fname)-1, "%s/%s", directory, dname); + fname = talloc_asprintf(ctx, + "%s/%s", + directory, + dname); + if (!fname) { + return NT_STATUS_NO_MEMORY; + } - pstrcpy(destname,newname); - - if (!resolve_wildcards(talloc_tos(), - fname,destname,&mod_destname)) { - DEBUG(6, ("resolve_wildcards %s %s failed\n", + if (!resolve_wildcards(ctx, + fname,newname,&destname)) { + DEBUG(6, ("resolve_wildcards %s %s failed\n", fname, destname)); + TALLOC_FREE(fname); continue; } - pstrcpy(destname,mod_destname); - + if (!destname) { + return NT_STATUS_NO_MEMORY; + } + ZERO_STRUCT(sbuf1); SMB_VFS_STAT(conn, fname, &sbuf1); @@ -5714,13 +5778,16 @@ NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req, DEBUG(3,("rename_internals: doing rename on %s -> " "%s\n",fname,destname)); + + TALLOC_FREE(fname); + TALLOC_FREE(destname); } CloseDir(dir_hnd); if (count == 0 && NT_STATUS_IS_OK(status)) { status = map_nt_error_from_unix(errno); } - + return status; } @@ -5804,7 +5871,7 @@ void reply_mv(connection_struct *conn, struct smb_request *req) DEBUG(3,("reply_mv : %s -> %s\n",name,newname)); - status = rename_internals(conn, req, name, newname, attrs, False, + status = rename_internals(ctx, conn, req, name, newname, attrs, False, src_has_wcard, dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { @@ -5831,9 +5898,10 @@ void reply_mv(connection_struct *conn, struct smb_request *req) * TODO: check error codes on all callers */ -NTSTATUS copy_file(connection_struct *conn, - char *src, - char *dest1, +NTSTATUS copy_file(TALLOC_CTX *ctx, + connection_struct *conn, + const char *src, + const char *dest1, int ofun, int count, BOOL target_is_directory) @@ -5841,24 +5909,32 @@ NTSTATUS copy_file(connection_struct *conn, SMB_STRUCT_STAT src_sbuf, sbuf2; SMB_OFF_T ret=-1; files_struct *fsp1,*fsp2; - pstring dest; + char *dest = NULL; uint32 dosattrs; uint32 new_create_disposition; NTSTATUS status; - - pstrcpy(dest,dest1); + + dest = talloc_strdup(ctx, dest1); + if (!dest) { + return NT_STATUS_NO_MEMORY; + } if (target_is_directory) { - char *p = strrchr_m(src,'/'); + const char *p = strrchr_m(src,'/'); if (p) { p++; } else { p = src; } - pstrcat(dest,"/"); - pstrcat(dest,p); + dest = talloc_asprintf_append(dest, + "/%s", + p); + if (!dest) { + return NT_STATUS_NO_MEMORY; + } } if (!vfs_file_exist(conn,src,&src_sbuf)) { + TALLOC_FREE(dest); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } @@ -5867,6 +5943,7 @@ NTSTATUS copy_file(connection_struct *conn, } else { if (!map_open_params_to_ntcreate(dest1,0,ofun, NULL, NULL, &new_create_disposition, NULL)) { + TALLOC_FREE(dest); return NT_STATUS_INVALID_PARAMETER; } } @@ -5881,6 +5958,7 @@ NTSTATUS copy_file(connection_struct *conn, NULL, &fsp1); if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(dest); return status; } @@ -5898,6 +5976,8 @@ NTSTATUS copy_file(connection_struct *conn, INTERNAL_OPEN_ONLY, NULL, &fsp2); + TALLOC_FREE(dest); + if (!NT_STATUS_IS_OK(status)) { close_file(fsp1,ERROR_CLOSE); return status; @@ -5913,7 +5993,7 @@ NTSTATUS copy_file(connection_struct *conn, src_sbuf.st_size = 0; } } - + if (src_sbuf.st_size) { ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size); } @@ -5950,8 +6030,8 @@ void reply_copy(connection_struct *conn, struct smb_request *req) { char *name = NULL; char *newname = NULL; - pstring directory; - pstring mask; + char *directory = NULL; + char *mask = NULL; char *p; int count=0; int error = ERRnoaccess; @@ -5978,8 +6058,6 @@ void reply_copy(connection_struct *conn, struct smb_request *req) ofun = SVAL(req->inbuf,smb_vwv1); flags = SVAL(req->inbuf,smb_vwv2); - *directory = *mask = 0; - p = smb_buf(req->inbuf); p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &name, p, 0, STR_TERMINATE, &status, @@ -6080,12 +6158,22 @@ void reply_copy(connection_struct *conn, struct smb_request *req) p = strrchr_m(name,'/'); if (!p) { - pstrcpy(directory,"./"); - pstrcpy(mask,name); + directory = talloc_strdup(ctx, "./"); + if (!directory) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBcopy); + return; + } + mask = name; } else { *p = 0; - pstrcpy(directory,name); - pstrcpy(mask,p+1); + directory = talloc_strdup(ctx, name); + if (!directory) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBcopy); + return; + } + mask = p+1; } /* @@ -6099,21 +6187,22 @@ void reply_copy(connection_struct *conn, struct smb_request *req) if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) { char *new_mask = NULL; - mangle_lookup_name_from_8_3( talloc_tos(), + mangle_lookup_name_from_8_3(ctx, mask, &new_mask, conn->params ); if (new_mask) { - pstrcpy(mask, new_mask); + mask = new_mask; } } if (!source_has_wild) { - pstrcat(directory,"/"); - pstrcat(directory,mask); + directory = talloc_asprintf_append(directory, + "/%s", + mask); if (dest_has_wild) { char *mod_newname = NULL; - if (!resolve_wildcards(talloc_tos(), + if (!resolve_wildcards(ctx, directory,newname,&mod_newname)) { reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBcopy); @@ -6135,9 +6224,9 @@ void reply_copy(connection_struct *conn, struct smb_request *req) END_PROFILE(SMBcopy); return; } - - status = copy_file(conn,directory,newname,ofun, - count,target_is_directory); + + status = copy_file(ctx,conn,directory,newname,ofun, + count,target_is_directory); if(!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -6148,12 +6237,13 @@ void reply_copy(connection_struct *conn, struct smb_request *req) } } else { struct smb_Dir *dir_hnd = NULL; - const char *dname; + const char *dname = NULL; long offset = 0; - pstring destname; - if (strequal(mask,"????????.???")) - pstrcpy(mask,"*"); + if (strequal(mask,"????????.???")) { + mask[0] = '*'; + mask[1] = '\0'; + } status = check_name(conn, directory); if (!NT_STATUS_IS_OK(status)) { @@ -6161,7 +6251,7 @@ void reply_copy(connection_struct *conn, struct smb_request *req) END_PROFILE(SMBcopy); return; } - + dir_hnd = OpenDir(conn, directory, mask, 0); if (dir_hnd == NULL) { status = map_nt_error_from_unix(errno); @@ -6173,26 +6263,41 @@ 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); - + char *destname = NULL; + char *fname = NULL; + + if (ISDOT(dname) || ISDOTDOT(dname)) { + continue; + } + if (!is_visible_file(conn, directory, dname, &sbuf1, False)) { continue; } - if(!mask_match(fname, mask, conn->case_sensitive)) { + if(!mask_match(dname, mask, conn->case_sensitive)) { continue; } error = ERRnoaccess; - slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); - pstrcpy(destname,newname); - if (!resolve_wildcards(talloc_tos(), - fname,destname,&mod_destname)) { + fname = talloc_asprintf(ctx, + "%s/%s", + directory, + dname); + if (!fname) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBcopy); + return; + } + + if (!resolve_wildcards(ctx, + fname,newname,&destname)) { continue; } - pstrcpy(destname,mod_destname); + if (!destname) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + END_PROFILE(SMBcopy); + return; + } status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { @@ -6200,25 +6305,27 @@ void reply_copy(connection_struct *conn, struct smb_request *req) END_PROFILE(SMBcopy); return; } - + status = check_name(conn, destname); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); END_PROFILE(SMBcopy); return; } - + DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname, destname)); - status = copy_file(conn,fname,destname,ofun, + status = copy_file(ctx,conn,fname,destname,ofun, count,target_is_directory); if (NT_STATUS_IS_OK(status)) { count++; } + TALLOC_FREE(fname); + TALLOC_FREE(destname); } CloseDir(dir_hnd); } - + if (count == 0) { if(err) { /* Error on close... */ diff --git a/source3/smbd/service.c b/source3/smbd/service.c index aeb0e0f31d..4daa2924a2 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -52,7 +52,7 @@ static BOOL canonicalize_path(connection_struct *conn, pstring path) Observent people will notice a similarity between this and check_path_syntax :-). ****************************************************************************/ -void set_conn_connectpath(connection_struct *conn, const pstring connectpath) +void set_conn_connectpath(connection_struct *conn, const char *connectpath) { pstring destname; char *d = destname; @@ -1117,27 +1117,31 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, strerror(errno) )); } change_to_root_user(); - /* Call VFS disconnect hook */ + /* Call VFS disconnect hook */ SMB_VFS_DISCONNECT(conn); yield_connection(conn, lp_servicename(snum)); conn_free(conn); *status = NT_STATUS_BAD_NETWORK_NAME; return NULL; } - + string_set(&conn->origpath,conn->connectpath); - + #if SOFTLINK_OPTIMISATION /* resolve any soft links early if possible */ if (vfs_ChDir(conn,conn->connectpath) == 0) { - pstring s; - pstrcpy(s,conn->connectpath); - vfs_GetWd(conn,s); + TALLOC_CTX *ctx = talloc_stackframe(); + char *s = vfs_GetWd(ctx,s); + if (!s) { + *status = map_nt_error_from_unix(errno); + return NULL; + } set_conn_connectpath(conn,s); vfs_ChDir(conn,conn->connectpath); + TALLOC_FREE(ctx); } #endif - + /* * Print out the 'connected as' stuff here as we need * to know the effective uid and gid we will be using @@ -1153,7 +1157,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() ); dbgtext( "(pid %d)\n", (int)sys_getpid() ); } - + /* we've finished with the user stuff - go back to root */ change_to_root_user(); return(conn); diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 8e03094aef..63dcb06f5d 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1,4 +1,4 @@ -/* +/* Unix SMB/CIFS implementation. SMB transaction2 handling Copyright (C) Jeremy Allison 1994-2007 @@ -13,12 +13,12 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -211,7 +211,7 @@ static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_str if (strnequal(p, "system.", 7) || samba_private_attr_name(p)) continue; - + listp = TALLOC_P(mem_ctx, struct ea_list); if (!listp) return NULL; @@ -1008,7 +1008,9 @@ static void call_trans2open(connection_struct *conn, Case can be significant or not. **********************************************************/ -static BOOL exact_match(connection_struct *conn, char *str, char *mask) +static BOOL exact_match(connection_struct *conn, + const char *str, + const char *mask) { if (mask[0] == '.' && mask[1] == 0) return False; @@ -1134,21 +1136,29 @@ static NTSTATUS unix_perms_from_wire( connection_struct *conn, Get a level dependent lanman2 dir entry. ****************************************************************************/ -static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, - char *path_mask,uint32 dirtype,int info_level, - int requires_resume_key, - BOOL dont_descend,char **ppdata, - char *base_data, char *end_data, - int space_remaining, - BOOL *out_of_space, BOOL *got_exact_match, - int *last_entry_off, struct ea_list *name_list, TALLOC_CTX *ea_ctx) +static BOOL get_lanman2_dir_entry(TALLOC_CTX *ctx, + connection_struct *conn, + uint16 flags2, + const char *path_mask, + uint32 dirtype, + int info_level, + int requires_resume_key, + BOOL dont_descend, + char **ppdata, + char *base_data, + char *end_data, + int space_remaining, + BOOL *out_of_space, + BOOL *got_exact_match, + int *last_entry_off, + struct ea_list *name_list) { const char *dname; BOOL found = False; SMB_STRUCT_STAT sbuf; - pstring mask; - pstring pathreal; - pstring fname; + const char *mask = NULL; + char *pathreal = NULL; + const char *fname = NULL; char *p, *q, *pdata = *ppdata; uint32 reskey=0; long prev_dirpos=0; @@ -1166,7 +1176,6 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, BOOL check_mangled_names = lp_manglednames(conn->params); char mangled_name[13]; /* mangled 8.3 name. */ - *fname = 0; *out_of_space = False; *got_exact_match = False; @@ -1174,18 +1183,20 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, ZERO_STRUCT(adate_ts); ZERO_STRUCT(create_date_ts); - if (!conn->dirptr) + if (!conn->dirptr) { return(False); + } p = strrchr_m(path_mask,'/'); if(p != NULL) { - if(p[1] == '\0') - pstrcpy(mask,"*.*"); - else - pstrcpy(mask, p+1); - } else - pstrcpy(mask, path_mask); - + if(p[1] == '\0') { + mask = talloc_strdup(ctx,"*.*"); + } else { + mask = p+1; + } + } else { + mask = path_mask; + } while (!found) { BOOL got_match; @@ -1193,7 +1204,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, /* Needed if we run out of space */ long curr_dirpos = prev_dirpos = dptr_TellDir(conn->dirptr); - dname = dptr_ReadDirName(conn->dirptr,&curr_dirpos,&sbuf); + dname = dptr_ReadDirName(ctx,conn->dirptr,&curr_dirpos,&sbuf); /* * Due to bugs in NT client redirectors we are not using @@ -1206,7 +1217,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %ld\n", (long)conn->dirptr,curr_dirpos)); - + if (!dname) { return(False); } @@ -1217,14 +1228,15 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, * pathreal which is composed from dname. */ - pstrcpy(fname,dname); + pathreal = NULL; + fname = dname; /* Mangle fname if it's an illegal name. */ - if (mangle_must_mangle(fname,conn->params)) { - if (!name_to_8_3(fname,mangled_name,True,conn->params)) { + if (mangle_must_mangle(dname,conn->params)) { + if (!name_to_8_3(dname,mangled_name,True,conn->params)) { continue; /* Error - couldn't mangle. */ } - pstrcpy(fname,mangled_name); + fname = mangled_name; } if(!(got_match = *got_exact_match = exact_match(conn, fname, mask))) { @@ -1250,21 +1262,34 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, } if (got_match) { - BOOL isdots = (strequal(dname,"..") || strequal(dname,".")); + BOOL isdots = (ISDOT(dname) || ISDOTDOT(dname)); + if (dont_descend && !isdots) { continue; } - - pstrcpy(pathreal,conn->dirpath); - if(needslash) { - pstrcat(pathreal,"/"); + + if (needslash) { + pathreal = NULL; + pathreal = talloc_asprintf(ctx, + "%s/%s", + conn->dirpath, + dname); + } else { + pathreal = talloc_asprintf(ctx, + "%s%s", + conn->dirpath, + dname); + } + + if (!pathreal) { + return False; } - pstrcat(pathreal,dname); if (INFO_LEVEL_IS_UNIX(info_level)) { if (SMB_VFS_LSTAT(conn,pathreal,&sbuf) != 0) { DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n", pathreal,strerror(errno))); + TALLOC_FREE(pathreal); continue; } } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) { @@ -1283,6 +1308,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n", pathreal,strerror(errno))); + TALLOC_FREE(pathreal); continue; } } @@ -1295,6 +1321,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, if (!dir_check_ftype(conn,mode,dirtype)) { DEBUG(5,("get_lanman2_dir_entry: [%s] attribs didn't match %x\n",fname,dirtype)); + TALLOC_FREE(pathreal); continue; } @@ -1316,9 +1343,9 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, create_date = convert_timespec_to_time_t(create_date_ts); mdate = convert_timespec_to_time_t(mdate_ts); adate = convert_timespec_to_time_t(adate_ts); - + DEBUG(5,("get_lanman2_dir_entry: found %s fname=%s\n",pathreal,fname)); - + found = True; dptr_DirCacheAdd(conn->dirptr, dname, curr_dirpos); @@ -1425,7 +1452,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, SSVAL(p,20,mode); p += 22; /* p now points to the EA area. */ - file_list = get_ea_list_from_file(ea_ctx, conn, NULL, pathreal, &ea_len); + file_list = get_ea_list_from_file(ctx, conn, NULL, pathreal, &ea_len); name_list = ea_list_union(name_list, file_list, &ea_len); /* We need to determine if this entry will fit in the space available. */ @@ -1439,7 +1466,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, } /* Push the ea_data followed by the name. */ - p += fill_ea_buffer(ea_ctx, p, space_remaining, conn, name_list); + p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list); nameptr = p; len = srvstr_push(base_data, flags2, p + 1, fname, PTR_DIFF(end_data, p), @@ -1537,7 +1564,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, SIVAL(pdata,0,len); p = pdata + len; break; - + case SMB_FIND_FILE_FULL_DIRECTORY_INFO: DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n")); p += 4; @@ -1713,7 +1740,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, break; - default: + default: return(False); } @@ -1760,7 +1787,7 @@ static void call_trans2findfirst(connection_struct *conn, BOOL requires_resume_key; int info_level; char *directory = NULL; - pstring mask; + const char *mask = NULL; char *p; int last_entry_off=0; int dptr_num = -1; @@ -1772,7 +1799,6 @@ static void call_trans2findfirst(connection_struct *conn, int space_remaining; BOOL mask_contains_wcard = False; SMB_STRUCT_STAT sbuf; - TALLOC_CTX *ea_ctx = NULL; struct ea_list *ea_list = NULL; NTSTATUS ntstatus = NT_STATUS_OK; TALLOC_CTX *ctx = talloc_tos(); @@ -1790,8 +1816,6 @@ static void call_trans2findfirst(connection_struct *conn, requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME); info_level = SVAL(params,6); - *mask = 0; - DEBUG(3,("call_trans2findfirst: dirtype = %x, maxentries = %d, close_after_first=%d, \ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", (unsigned int)dirtype, maxentries, close_after_first, close_if_end, requires_resume_key, @@ -1864,10 +1888,10 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", if(p == NULL) { /* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */ if((directory[0] == '.') && (directory[1] == '\0')) { - pstrcpy(mask,"*"); + mask = "*"; mask_contains_wcard = True; } else { - pstrcpy(mask,directory); + mask = directory; } directory = talloc_strdup(talloc_tos(), "./"); if (!directory) { @@ -1875,7 +1899,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", return; } } else { - pstrcpy(mask,p+1); + mask = p+1; *p = 0; } @@ -1901,16 +1925,10 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd reply_doserror(req, ERRDOS, ERReasnotsupported); return; } - - if ((ea_ctx = talloc_init("findnext_ea_list")) == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } /* Pull out the list of names. */ - ea_list = read_ea_name_list(ea_ctx, pdata + 4, ea_size - 4); + ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4); if (!ea_list) { - talloc_destroy(ea_ctx); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); return; } @@ -1919,7 +1937,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd *ppdata = (char *)SMB_REALLOC( *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN); if(*ppdata == NULL ) { - talloc_destroy(ea_ctx); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } @@ -1929,7 +1946,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* Realloc the params space */ *pparams = (char *)SMB_REALLOC(*pparams, 10); if (*pparams == NULL) { - talloc_destroy(ea_ctx); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } @@ -1949,7 +1965,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd &conn->dirptr); if (!NT_STATUS_IS_OK(ntstatus)) { - talloc_destroy(ea_ctx); reply_nterror(req, ntstatus); return; } @@ -1957,13 +1972,13 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd dptr_num = dptr_dnum(conn->dirptr); DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype)); - /* We don't need to check for VOL here as this is returned by + /* We don't need to check for VOL here as this is returned by a different TRANS2 call. */ - + DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn)))); if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive)) dont_descend = True; - + p = pdata; space_remaining = max_data_bytes; out_of_space = False; @@ -1977,14 +1992,19 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd out_of_space = True; finished = False; } else { - finished = !get_lanman2_dir_entry(conn, + TALLOC_CTX *sub_ctx = talloc_stackframe(); + + finished = !get_lanman2_dir_entry(sub_ctx, + conn, req->flags2, mask,dirtype,info_level, requires_resume_key,dont_descend, &p,pdata,data_end, space_remaining, &out_of_space, &got_exact_match, - &last_entry_off, ea_list, ea_ctx); + &last_entry_off, ea_list); + + TALLOC_FREE(sub_ctx); } if (finished && out_of_space) @@ -2005,8 +2025,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd space_remaining = max_data_bytes - PTR_DIFF(p,pdata); } - - talloc_destroy(ea_ctx); /* Check if we can close the dirptr */ if(close_after_first || (finished && close_if_end)) { @@ -2014,8 +2032,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd dptr_close(&dptr_num); } - /* - * If there are no matching entries we must return ERRDOS/ERRbadfile - + /* + * If there are no matching entries we must return ERRDOS/ERRbadfile - * from observation of NT. NB. This changes to ERRDOS,ERRnofiles if * the protocol level is less than NT1. Tested with smbclient. JRA. * This should fix the OS/2 client bug #2335. @@ -2101,9 +2119,9 @@ static void call_trans2findnext(connection_struct *conn, BOOL continue_bit; BOOL mask_contains_wcard = False; char *resume_name = NULL; - pstring mask; - pstring directory; - char *p; + const char *mask = NULL; + const char *directory = NULL; + char *p = NULL; uint16 dirtype; int numentries = 0; int i, last_entry_off=0; @@ -2111,7 +2129,6 @@ static void call_trans2findnext(connection_struct *conn, BOOL dont_descend = False; BOOL out_of_space = False; int space_remaining; - TALLOC_CTX *ea_ctx = NULL; struct ea_list *ea_list = NULL; NTSTATUS ntstatus = NT_STATUS_OK; TALLOC_CTX *ctx = talloc_tos(); @@ -2131,8 +2148,6 @@ static void call_trans2findnext(connection_struct *conn, requires_resume_key = (findnext_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME); continue_bit = (findnext_flags & FLAG_TRANS2_FIND_CONTINUE); - *mask = *directory = 0; - srvstr_get_path_wcard(ctx, params, req->flags2, &resume_name, params+12, total_params - 12, STR_TERMINATE, &ntstatus, @@ -2202,21 +2217,15 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd reply_nterror(req, NT_STATUS_INVALID_PARAMETER); return; } - + if (!lp_ea_support(SNUM(conn))) { reply_doserror(req, ERRDOS, ERReasnotsupported); return; } - - if ((ea_ctx = talloc_init("findnext_ea_list")) == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } /* Pull out the list of names. */ - ea_list = read_ea_name_list(ea_ctx, pdata + 4, ea_size - 4); + ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4); if (!ea_list) { - talloc_destroy(ea_ctx); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); return; } @@ -2225,7 +2234,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd *ppdata = (char *)SMB_REALLOC( *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN); if(*ppdata == NULL) { - talloc_destroy(ea_ctx); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } @@ -2236,7 +2244,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* Realloc the params space */ *pparams = (char *)SMB_REALLOC(*pparams, 6*SIZEOFWORD); if(*pparams == NULL ) { - talloc_destroy(ea_ctx); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } @@ -2245,7 +2252,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* Check that the dptr is valid */ if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num))) { - talloc_destroy(ea_ctx); reply_doserror(req, ERRDOS, ERRnofiles); return; } @@ -2255,34 +2261,33 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* Get the wildcard mask from the dptr */ if((p = dptr_wcard(dptr_num))== NULL) { DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num)); - talloc_destroy(ea_ctx); reply_doserror(req, ERRDOS, ERRnofiles); return; } - pstrcpy(mask, p); - pstrcpy(directory,conn->dirpath); + mask = p; + directory = conn->dirpath; /* Get the attr mask from the dptr */ dirtype = dptr_attr(dptr_num); DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld)\n", - dptr_num, mask, dirtype, + dptr_num, mask, dirtype, (long)conn->dirptr, dptr_TellDir(conn->dirptr))); - /* We don't need to check for VOL here as this is returned by + /* We don't need to check for VOL here as this is returned by a different TRANS2 call. */ DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn)))); if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive)) dont_descend = True; - + p = pdata; space_remaining = max_data_bytes; out_of_space = False; - /* + /* * Seek to the correct position. We no longer use the resume key but * depend on the last file name instead. */ @@ -2299,12 +2304,12 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd if (mangle_is_mangled(resume_name, conn->params)) { char *new_resume_name = NULL; - mangle_lookup_name_from_8_3(talloc_tos(), + mangle_lookup_name_from_8_3(ctx, resume_name, &new_resume_name, conn->params); if (new_resume_name) { - pstrcpy(resume_name, new_resume_name); + resume_name = new_resume_name; } } @@ -2329,14 +2334,19 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd out_of_space = True; finished = False; } else { - finished = !get_lanman2_dir_entry(conn, + TALLOC_CTX *sub_ctx = talloc_stackframe(); + + finished = !get_lanman2_dir_entry(sub_ctx, + conn, req->flags2, mask,dirtype,info_level, requires_resume_key,dont_descend, &p,pdata,data_end, space_remaining, &out_of_space, &got_exact_match, - &last_entry_off, ea_list, ea_ctx); + &last_entry_off, ea_list); + + TALLOC_FREE(sub_ctx); } if (finished && out_of_space) @@ -2357,8 +2367,10 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd space_remaining = max_data_bytes - PTR_DIFF(p,pdata); } - - talloc_destroy(ea_ctx); + + DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", + smb_fn_name(CVAL(req->inbuf,smb_com)), + mask, directory, dirtype, numentries ) ); /* Check if we can close the dirptr */ if(close_after_request || (finished && close_if_end)) { @@ -2375,13 +2387,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd send_trans2_replies(req, params, 8, pdata, PTR_DIFF(p,pdata), max_data_bytes); - if ((! *directory) && dptr_path(dptr_num)) - slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); - - DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", - smb_fn_name(CVAL(req->inbuf,smb_com)), - mask, directory, dirtype, numentries ) ); - return; } @@ -3511,7 +3516,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, unsigned int data_size = 0; unsigned int param_size = 2; SMB_STRUCT_STAT sbuf; - pstring dos_fname; + char *dos_fname = NULL; char *fname = NULL; char *fullpathname; char *base_name; @@ -3523,7 +3528,6 @@ static void call_trans2qfilepathinfo(connection_struct *conn, struct timespec create_time_ts, mtime_ts, atime_ts; files_struct *fsp = NULL; struct file_id fileid; - TALLOC_CTX *data_ctx = NULL; struct ea_list *ea_list = NULL; uint32 access_mask = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */ char *lock_data = NULL; @@ -3712,7 +3716,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d total_data=%d\n", fname,fsp ? fsp->fnum : -1, info_level,tran_call,total_data)); - p = strrchr_m(fname,'/'); + p = strrchr_m(fname,'/'); if (!p) base_name = fname; else @@ -3754,15 +3758,9 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd return; } - if ((data_ctx = talloc_init("ea_list")) == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - /* Pull out the list of names. */ - ea_list = read_ea_name_list(data_ctx, pdata + 4, ea_size - 4); + ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4); if (!ea_list) { - talloc_destroy(data_ctx); reply_nterror( req, NT_STATUS_INVALID_PARAMETER); return; @@ -3783,16 +3781,10 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd return; } - if ((data_ctx = talloc_init("lock_request")) == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - /* Copy the lock range data. */ lock_data = (char *)TALLOC_MEMDUP( - data_ctx, pdata, total_data); + ctx, pdata, total_data); if (!lock_data) { - talloc_destroy(data_ctx); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } @@ -3803,7 +3795,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd *pparams = (char *)SMB_REALLOC(*pparams,2); if (*pparams == NULL) { - talloc_destroy(data_ctx); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } @@ -3812,7 +3803,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN; *ppdata = (char *)SMB_REALLOC(*ppdata, data_size); if (*ppdata == NULL ) { - talloc_destroy(data_ctx); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } @@ -3857,10 +3847,20 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* NT expects the name to be in an exact form of the *full* filename. See the trans2 torture test */ - if (strequal(base_name,".")) { - pstrcpy(dos_fname, "\\"); + if (ISDOT(base_name)) { + dos_fname = talloc_strdup(ctx, "\\"); + if (!dos_fname) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } } else { - pstr_sprintf(dos_fname, "\\%s", fname); + dos_fname = talloc_asprintf(ctx, + "\\%s", + fname); + if (!dos_fname) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } string_replace(dos_fname, '/', '\\'); } @@ -3894,14 +3894,14 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_INFO_IS_NAME_VALID: DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_IS_NAME_VALID\n")); if (tran_call == TRANSACT2_QFILEINFO) { - /* os/2 needs this ? really ?*/ + /* os/2 needs this ? really ?*/ reply_doserror(req, ERRDOS, ERRbadfunc); return; } data_size = 0; param_size = 0; break; - + case SMB_INFO_QUERY_EAS_FROM_LIST: { size_t total_ea_len = 0; @@ -3909,18 +3909,16 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n")); - ea_file_list = get_ea_list_from_file(data_ctx, conn, fsp, fname, &total_ea_len); + ea_file_list = get_ea_list_from_file(ctx, conn, fsp, fname, &total_ea_len); ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len); if (!ea_list || (total_ea_len > data_size)) { - talloc_destroy(data_ctx); data_size = 4; SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */ break; } - data_size = fill_ea_buffer(data_ctx, pdata, data_size, conn, ea_list); - talloc_destroy(data_ctx); + data_size = fill_ea_buffer(ctx, pdata, data_size, conn, ea_list); break; } @@ -3931,22 +3929,14 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n")); - data_ctx = talloc_init("ea_ctx"); - if (!data_ctx) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - - ea_list = get_ea_list_from_file(data_ctx, conn, fsp, fname, &total_ea_len); + ea_list = get_ea_list_from_file(ctx, conn, fsp, fname, &total_ea_len); if (!ea_list || (total_ea_len > data_size)) { - talloc_destroy(data_ctx); data_size = 4; SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */ break; } - data_size = fill_ea_buffer(data_ctx, pdata, data_size, conn, ea_list); - talloc_destroy(data_ctx); + data_size = fill_ea_buffer(ctx, pdata, data_size, conn, ea_list); break; } @@ -4219,7 +4209,12 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_QUERY_FILE_UNIX_LINK: { - pstring buffer; + char *buffer = TALLOC_SIZE(ctx, 1024); + + if (!buffer) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n")); #ifdef S_ISLNK @@ -4232,7 +4227,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd reply_unixerror(req, ERRDOS, ERRbadlink); return; #endif - len = SMB_VFS_READLINK(conn,fullpathname, buffer, sizeof(pstring)-1); /* read link */ + len = SMB_VFS_READLINK(conn,fullpathname, + buffer, 1023); if (len == -1) { reply_unixerror(req, ERRDOS, ERRnoaccess); @@ -4364,7 +4360,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case POSIX_LOCK_TYPE_UNLOCK: default: /* There's no point in asking for an unlock... */ - talloc_destroy(data_ctx); reply_nterror( req, NT_STATUS_INVALID_PARAMETER); @@ -4860,21 +4855,32 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn, /* !widelinks forces the target path to be within the share. */ /* This means we can interpret the target as a pathname. */ if (!lp_widelinks(SNUM(conn))) { - pstring rel_name; + char *rel_name = NULL; char *last_dirp = NULL; if (*link_target == '/') { /* No absolute paths allowed. */ return NT_STATUS_ACCESS_DENIED; } - pstrcpy(rel_name, newname); + rel_name = talloc_strdup(ctx,newname); + if (!rel_name) { + return NT_STATUS_NO_MEMORY; + } last_dirp = strrchr_m(rel_name, '/'); if (last_dirp) { last_dirp[1] = '\0'; } else { - pstrcpy(rel_name, "./"); + rel_name = talloc_strdup(ctx,"./"); + if (!rel_name) { + return NT_STATUS_NO_MEMORY; + } + } + rel_name = talloc_asprintf_append(ctx, + "%s", + link_target); + if (!rel_name) { + return NT_STATUS_NO_MEMORY; } - pstrcat(rel_name, link_target); status = check_name(conn, rel_name); if (!NT_STATUS_IS_OK(status)) { @@ -4945,7 +4951,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, uint32 root_fid; uint32 len; char *newname = NULL; - pstring base_name; + char *base_name = NULL; BOOL dest_has_wcard = False; NTSTATUS status = NT_STATUS_OK; char *p; @@ -4988,15 +4994,26 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, } /* Create the base directory. */ - pstrcpy(base_name, fname); + base_name = talloc_strdup(ctx, fname); + if (!base_name) { + return NT_STATUS_NO_MEMORY; + } p = strrchr_m(base_name, '/'); if (p) { p[1] = '\0'; } else { - pstrcpy(base_name, "./"); + base_name = talloc_strdup(ctx, "./"); + if (!base_name) { + return NT_STATUS_NO_MEMORY; + } } /* Append the new name. */ - pstrcat(base_name, newname); + base_name = talloc_asprintf_append(base_name, + "%s", + newname); + if (!base_name) { + return NT_STATUS_NO_MEMORY; + } if (fsp) { SMB_STRUCT_STAT sbuf; @@ -5026,7 +5043,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, } else { DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n", fname, base_name )); - status = rename_internals(conn, req, fname, base_name, 0, + status = rename_internals(ctx, conn, req, fname, base_name, 0, overwrite, False, dest_has_wcard); } diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index f9a5ba5ed6..d9c772d6b1 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -653,7 +653,11 @@ char *vfs_readdirname(connection_struct *conn, void *p) int vfs_ChDir(connection_struct *conn, const char *path) { int res; - static pstring LastDir=""; + static char *LastDir = NULL; + + if (!LastDir) { + LastDir = SMB_STRDUP(""); + } if (strcsequal(path,".")) return(0); @@ -664,8 +668,10 @@ int vfs_ChDir(connection_struct *conn, const char *path) DEBUG(4,("vfs_ChDir to %s\n",path)); res = SMB_VFS_CHDIR(conn,path); - if (!res) - pstrcpy(LastDir,path); + if (!res) { + SAFE_FREE(LastDir); + LastDir = SMB_STRDUP(path); + } return(res); } @@ -675,7 +681,7 @@ int vfs_ChDir(connection_struct *conn, const char *path) static struct { SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */ SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */ - char *dos_path; /* The pathname in DOS format. */ + char *path; /* The pathname. */ BOOL valid; } ino_list[MAX_GETWDCACHE]; @@ -710,23 +716,36 @@ static void array_promote(char *array,int elsize,int element) format. Note this can be called with conn == NULL. ********************************************************************/ -char *vfs_GetWd(connection_struct *conn, char *path) +char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) { +#ifdef PATH_MAX + char s[PATH_MAX+1]; +#else pstring s; +#endif static BOOL getwd_cache_init = False; SMB_STRUCT_STAT st, st2; int i; + char *ret = NULL; *s = 0; - if (!use_getwd_cache) - return(SMB_VFS_GETWD(conn,path)); + if (!use_getwd_cache) { + nocache: + ret = SMB_VFS_GETWD(conn,s); + if (!ret) { + DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, " + "errno %s\n",strerror(errno))); + return NULL; + } + return talloc_strdup(ctx, ret); + } /* init the cache */ if (!getwd_cache_init) { getwd_cache_init = True; for (i=0;i<MAX_GETWDCACHE;i++) { - string_set(&ino_list[i].dos_path,""); + string_set(&ino_list[i].path,""); ino_list[i].valid = False; } } @@ -737,8 +756,10 @@ char *vfs_GetWd(connection_struct *conn, char *path) if (SMB_VFS_STAT(conn, ".",&st) == -1) { /* Known to fail for root: the directory may be * NFS-mounted and exported with root_squash (so has no root access). */ - DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) )); - return(SMB_VFS_GETWD(conn,path)); + DEBUG(1,("vfs_GetWd: couldn't stat \".\" error %s " + "(NFS problem ?)\n", + strerror(errno) )); + goto nocache; } @@ -752,14 +773,19 @@ char *vfs_GetWd(connection_struct *conn, char *path) the same...) */ if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) { - if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) { + if (SMB_VFS_STAT(conn,ino_list[i].path,&st2) == 0) { if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev && (st2.st_mode & S_IFMT) == S_IFDIR) { - pstrcpy (path, ino_list[i].dos_path); + + ret = talloc_strdup(ctx, + ino_list[i].path); /* promote it for future use */ array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); - return (path); + if (ret == NULL) { + errno = ENOMEM; + } + return ret; } else { /* If the inode is different then something's changed, scrub the entry and start from scratch. */ @@ -770,22 +796,24 @@ char *vfs_GetWd(connection_struct *conn, char *path) } } - /* We don't have the information to hand so rely on traditional methods. - The very slow getcwd, which spawns a process on some systems, or the - not quite so bad getwd. */ + /* We don't have the information to hand so rely on traditional + * methods. The very slow getcwd, which spawns a process on some + * systems, or the not quite so bad getwd. */ if (!SMB_VFS_GETWD(conn,s)) { - DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno))); + DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n", + strerror(errno))); return (NULL); } - pstrcpy(path,s); + ret = talloc_strdup(ctx,s); - DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev)); + DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n", + s,(double)st.st_ino,(double)st.st_dev)); /* add it to the cache */ i = MAX_GETWDCACHE - 1; - string_set(&ino_list[i].dos_path,s); + string_set(&ino_list[i].path,s); ino_list[i].dev = st.st_dev; ino_list[i].inode = st.st_ino; ino_list[i].valid = True; @@ -793,7 +821,10 @@ char *vfs_GetWd(connection_struct *conn, char *path) /* put it at the top of the list */ array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); - return (path); + if (ret == NULL) { + errno = ENOMEM; + } + return ret; } /******************************************************************* @@ -832,18 +863,28 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) return map_nt_error_from_unix(errno); case ENOENT: { - pstring tmp_fname; - fstring last_component; + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + char *tmp_fname = NULL; + char *last_component = NULL; /* Last component didn't exist. Remove it and try and canonicalise the directory. */ - pstrcpy(tmp_fname, fname); + tmp_fname = talloc_strdup(tmp_ctx, fname); + if (!tmp_fname) { + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } p = strrchr_m(tmp_fname, '/'); if (p) { *p++ = '\0'; - fstrcpy(last_component, p); + last_component = p; } else { - fstrcpy(last_component, tmp_fname); - pstrcpy(tmp_fname, "."); + last_component = tmp_fname; + tmp_fname = talloc_strdup(tmp_ctx, + "."); + if (!tmp_fname) { + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } } #ifdef REALPATH_TAKES_NULL @@ -853,11 +894,17 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) #endif if (!resolved_name) { DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname)); + TALLOC_FREE(tmp_ctx); return map_nt_error_from_unix(errno); } - pstrcpy(tmp_fname, resolved_name); - pstrcat(tmp_fname, "/"); - pstrcat(tmp_fname, last_component); + tmp_fname = talloc_asprintf(tmp_ctx, + "%s/%s", + resolved_name, + last_component); + if (!tmp_fname) { + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } #ifdef REALPATH_TAKES_NULL SAFE_FREE(resolved_name); resolved_name = SMB_STRDUP(tmp_fname); @@ -873,6 +920,7 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) #endif resolved_name = resolved_name_buf; #endif + TALLOC_FREE(tmp_ctx); break; } default: @@ -903,7 +951,7 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) /* Check if we are allowing users to follow symlinks */ /* Patch from David Clerc <David.Clerc@cui.unige.ch> University of Geneva */ - + #ifdef S_ISLNK if (!lp_symlinks(SNUM(conn))) { SMB_STRUCT_STAT statbuf; |