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/Makefile.in | 2 +- source3/include/mangle.h | 15 +- source3/lib/charcnv.c | 65 +++++ source3/param/loadparm.c | 4 - source3/printing/nt_printing.c | 39 +-- source3/rpc_server/srv_srvsvc_nt.c | 42 ++-- source3/smbd/dir.c | 36 +-- source3/smbd/filename.c | 189 ++++++++------ source3/smbd/mangle.c | 65 ++--- source3/smbd/mangle_hash.c | 201 ++++++++------- source3/smbd/mangle_hash2.c | 135 ++++++---- source3/smbd/msdfs.c | 7 +- source3/smbd/nttrans.c | 93 +++---- source3/smbd/reply.c | 489 +++++++++++++++++++++++-------------- source3/smbd/statcache.c | 128 +++++----- source3/smbd/trans2.c | 243 +++++++++++------- 16 files changed, 1069 insertions(+), 684 deletions(-) (limited to 'source3') diff --git a/source3/Makefile.in b/source3/Makefile.in index c96bb0f069..f2f6282509 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -511,7 +511,7 @@ AUTH_OBJ = auth/auth.o @AUTH_STATIC@ auth/auth_util.o auth/token_util.o \ auth/auth_compat.o auth/auth_ntlmssp.o \ $(PLAINTEXT_AUTH_OBJ) $(SLCACHE_OBJ) $(DCUTIL_OBJ) -MANGLE_OBJ = smbd/mangle.o smbd/mangle_hash.o smbd/mangle_map.o smbd/mangle_hash2.o +MANGLE_OBJ = smbd/mangle.o smbd/mangle_hash.o smbd/mangle_hash2.o SMBD_OBJ_MAIN = smbd/server.o diff --git a/source3/include/mangle.h b/source3/include/mangle.h index 3d19ef9ed4..382bf1c630 100644 --- a/source3/include/mangle.h +++ b/source3/include/mangle.h @@ -7,12 +7,17 @@ struct mangle_fns { void (*reset)(void); BOOL (*is_mangled)(const char *s, const struct share_params *p); + BOOL (*must_mangle)(const char *s, const struct share_params *p); BOOL (*is_8_3)(const char *fname, BOOL check_case, BOOL allow_wildcards, const struct share_params *p); - BOOL (*check_cache)(char *s, size_t maxlen, - const struct share_params *p); - void (*name_map)(char *OutName, BOOL need83, BOOL cache83, - int default_case, - const struct share_params *p); + BOOL (*lookup_name_from_8_3)(TALLOC_CTX *ctx, + const char *in, + char **out, /* talloced on the given context. */ + const struct share_params *p); + BOOL (*name_to_8_3)(const char *in, + char out[13], + BOOL cache83, + int default_case, + const struct share_params *p); }; #endif /* _MANGLE_H_ */ diff --git a/source3/lib/charcnv.c b/source3/lib/charcnv.c index 349fbff850..dd03a56233 100644 --- a/source3/lib/charcnv.c +++ b/source3/lib/charcnv.c @@ -804,6 +804,71 @@ char *strdup_upper(const char *s) return SMB_STRDUP(out_buffer); } +/** + talloc_strdup() a unix string to upper case. +**/ + +char *talloc_strdup_upper(TALLOC_CTX *ctx, const char *s) +{ + char *out_buffer = talloc_strdup(ctx,s); + const unsigned char *p = (const unsigned char *)s; + unsigned char *q = (unsigned char *)out_buffer; + + if (!q) { + return NULL; + } + + /* this is quite a common operation, so we want it to be + fast. We optimise for the ascii case, knowing that all our + supported multi-byte character sets are ascii-compatible + (ie. they match for the first 128 chars) */ + + while (1) { + if (*p & 0x80) + break; + *q++ = toupper_ascii(*p); + if (!*p) + break; + p++; + } + + if (*p) { + /* MB case. */ + size_t size; + smb_ucs2_t *ubuf = NULL; + + /* We're not using the ascii buffer above. */ + TALLOC_FREE(out_buffer); + + size = convert_string_talloc(ctx, CH_UNIX, CH_UTF16LE, + s, strlen(s), + (void *)&ubuf, + True); + if (size == (size_t)-1) { + return NULL; + } + + strupper_w(ubuf); + + size = convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, + ubuf, size, + (void *)&out_buffer, + True); + + /* Don't need the intermediate buffer + * anymore. + */ + + TALLOC_FREE(ubuf); + + if (size == (size_t)-1) { + return NULL; + } + } + + return out_buffer; +} + size_t unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen) { size_t size; diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 3dd94645fd..9e089cf8a2 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -370,7 +370,6 @@ typedef struct { char **szHostsdeny; char *szMagicScript; char *szMagicOutput; - char *szMangledMap; char *szVetoFiles; char *szHideFiles; char *szVetoOplockFiles; @@ -511,7 +510,6 @@ static service sDefault = { NULL, /* szHostsdeny */ NULL, /* szMagicScript */ NULL, /* szMagicOutput */ - NULL, /* szMangledMap */ NULL, /* szVetoFiles */ NULL, /* szHideFiles */ NULL, /* szVetoOplockFiles */ @@ -1122,7 +1120,6 @@ static struct parm_struct parm_table[] = { {"map system", P_BOOL, P_LOCAL, &sDefault.bMap_system, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, {"map readonly", P_ENUM, P_LOCAL, &sDefault.iMap_readonly, NULL, enum_map_readonly, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, {"mangled names", P_BOOL, P_LOCAL, &sDefault.bMangledNames, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, - {"mangled map", P_STRING, P_LOCAL, &sDefault.szMangledMap, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL | FLAG_DEPRECATED }, {"max stat cache size", P_INTEGER, P_GLOBAL, &Globals.iMaxStatCacheSize, NULL, NULL, FLAG_ADVANCED}, {"stat cache", P_BOOL, P_GLOBAL, &Globals.bStatCache, NULL, NULL, FLAG_ADVANCED}, {"store dos attributes", P_BOOL, P_LOCAL, &sDefault.bStoreDosAttributes, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, @@ -2068,7 +2065,6 @@ FN_LOCAL_STRING(lp_fstype, fstype) FN_LOCAL_LIST(lp_vfs_objects, szVfsObjects) FN_LOCAL_STRING(lp_msdfs_proxy, szMSDfsProxy) static FN_LOCAL_STRING(lp_volume, volume) -FN_LOCAL_PARM_STRING(lp_mangled_map, szMangledMap) FN_LOCAL_STRING(lp_veto_files, szVetoFiles) FN_LOCAL_STRING(lp_hide_files, szHideFiles) FN_LOCAL_STRING(lp_veto_oplocks, szVetoOplockFiles) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 944b695a9d..24729c715b 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -659,13 +659,18 @@ BOOL nt_printing_init(struct messaging_context *msg_ctx) Function to allow filename parsing "the old way". ********************************************************************/ -static void driver_unix_convert(char *name,connection_struct *conn, - char *saved_last_component, SMB_STRUCT_STAT *pst) +static void driver_unix_convert(connection_struct *conn, + pstring name, + SMB_STRUCT_STAT *pst) { + char *new_name = NULL; unix_format(name); unix_clean_name(name); trim_string(name,"/","/"); - unix_convert(conn, name, False, saved_last_component, pst); + unix_convert(conn, name, False, &new_name, NULL, pst); + if (new_name) { + pstrcpy(name, new_name); + } } /******************************************************************* @@ -1288,7 +1293,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr /* Get file version info (if available) for previous file (if it exists) */ pstrcpy(filepath, old_file); - driver_unix_convert(filepath,conn,NULL,&stat_buf); + driver_unix_convert(conn,filepath,&stat_buf); status = open_file_ntcreate(conn, NULL, filepath, &stat_buf, FILE_GENERIC_READ, @@ -1324,7 +1329,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr /* Get file version info (if available) for new file */ pstrcpy(filepath, new_file); - driver_unix_convert(filepath,conn,NULL,&stat_buf); + driver_unix_convert(conn,filepath,&stat_buf); status = open_file_ntcreate(conn, NULL, filepath, &stat_buf, FILE_GENERIC_READ, @@ -1452,7 +1457,7 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_ * deriver the cversion. */ slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in); - driver_unix_convert(driverpath,conn,NULL,&st); + driver_unix_convert(conn,driverpath,&st); if ( !vfs_file_exist( conn, driverpath, &st ) ) { *perr = WERR_BADFILE; @@ -1793,7 +1798,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract */ DEBUG(5,("Creating first directory\n")); slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion); - driver_unix_convert(new_dir, conn, NULL, &st); + driver_unix_convert(conn,new_dir,&st); create_directory(conn, new_dir); /* For each driver file, archi\filexxx.yyy, if there is a duplicate file @@ -1819,7 +1824,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->driverpath); slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - driver_unix_convert(new_name, conn, NULL, &st); + driver_unix_convert(conn,new_name,&st); if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", @@ -1835,7 +1840,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->datafile); slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - driver_unix_convert(new_name, conn, NULL, &st); + driver_unix_convert(conn,new_name,&st); if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", @@ -1853,7 +1858,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->configfile); slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - driver_unix_convert(new_name, conn, NULL, &st); + driver_unix_convert(conn,new_name,&st); if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", @@ -1872,7 +1877,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->helpfile); slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - driver_unix_convert(new_name, conn, NULL, &st); + driver_unix_convert(conn,new_name,&st); if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", @@ -1900,7 +1905,7 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->dependentfiles[i]); slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { - driver_unix_convert(new_name, conn, NULL, &st); + driver_unix_convert(conn,new_name,&st); if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE| OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) { @@ -4938,7 +4943,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct if ( *info_3->driverpath ) { if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) { pstrcpy( file, s ); - driver_unix_convert(file, conn, NULL, &st); + driver_unix_convert(conn,file,&st); DEBUG(10,("deleting driverfile [%s]\n", s)); unlink_internals(conn, NULL, 0, file, False); } @@ -4947,7 +4952,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct if ( *info_3->configfile ) { if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) { pstrcpy( file, s ); - driver_unix_convert(file, conn, NULL, &st); + driver_unix_convert(conn,file,&st); DEBUG(10,("deleting configfile [%s]\n", s)); unlink_internals(conn, NULL, 0, file, False); } @@ -4956,7 +4961,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct if ( *info_3->datafile ) { if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) { pstrcpy( file, s ); - driver_unix_convert(file, conn, NULL, &st); + driver_unix_convert(conn,file,&st); DEBUG(10,("deleting datafile [%s]\n", s)); unlink_internals(conn, NULL, 0, file, False); } @@ -4965,7 +4970,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct if ( *info_3->helpfile ) { if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) { pstrcpy( file, s ); - driver_unix_convert(file, conn, NULL, &st); + driver_unix_convert(conn,file,&st); DEBUG(10,("deleting helpfile [%s]\n", s)); unlink_internals(conn, NULL, 0, file, False); } @@ -4981,7 +4986,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct if ( (p = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) { pstrcpy( file, p ); - driver_unix_convert(file, conn, NULL, &st); + driver_unix_convert(conn,file,&st); DEBUG(10,("deleting dependent file [%s]\n", file)); unlink_internals(conn, NULL, 0, file, False); } diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c index 22eaac51a7..4be519a9a3 100644 --- a/source3/rpc_server/srv_srvsvc_nt.c +++ b/source3/rpc_server/srv_srvsvc_nt.c @@ -2047,7 +2047,7 @@ WERROR _srvsvc_NetGetFileSecurity(pipes_struct *p, struct srvsvc_NetGetFileSecur connection_struct *conn = NULL; BOOL became_user = False; WERROR status = WERR_OK; - pstring tmp_file; + char *tmp_file = NULL; ZERO_STRUCT(st); @@ -2072,26 +2072,29 @@ WERROR _srvsvc_NetGetFileSecurity(pipes_struct *p, struct srvsvc_NetGetFileSecur } became_user = True; - pstrcpy(tmp_file, r->in.file); - nt_status = unix_convert(conn, tmp_file, False, NULL, &st); + if (!r->in.file) { + status = WERR_INVALID_PARAM; + goto error_exit; + } + nt_status = unix_convert(conn, r->in.file, False, &tmp_file, NULL, &st); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(3,("_srv_net_file_query_secdesc: bad pathname %s\n", r->in.file)); status = WERR_ACCESS_DENIED; goto error_exit; } - nt_status = check_name(conn, r->in.file); + nt_status = check_name(conn, tmp_file); if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(3,("_srv_net_file_query_secdesc: can't access %s\n", r->in.file)); + DEBUG(3,("_srv_net_file_query_secdesc: can't access %s\n", tmp_file)); status = WERR_ACCESS_DENIED; goto error_exit; } - nt_status = open_file_stat(conn, NULL, r->in.file, &st, &fsp); + nt_status = open_file_stat(conn, NULL, tmp_file, &st, &fsp); if (!NT_STATUS_IS_OK(nt_status)) { /* Perhaps it is a directory */ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_IS_A_DIRECTORY)) - nt_status = open_directory(conn, NULL, r->in.file, &st, + nt_status = open_directory(conn, NULL, tmp_file, &st, READ_CONTROL_ACCESS, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, @@ -2100,7 +2103,7 @@ WERROR _srvsvc_NetGetFileSecurity(pipes_struct *p, struct srvsvc_NetGetFileSecur NULL, &fsp); if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(3,("_srv_net_file_query_secdesc: Unable to open file %s\n", r->in.file)); + DEBUG(3,("_srv_net_file_query_secdesc: Unable to open file %s\n", tmp_file)); status = WERR_ACCESS_DENIED; goto error_exit; } @@ -2109,7 +2112,7 @@ WERROR _srvsvc_NetGetFileSecurity(pipes_struct *p, struct srvsvc_NetGetFileSecur sd_size = SMB_VFS_GET_NT_ACL(fsp, fsp->fsp_name, (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd); if (sd_size == 0) { - DEBUG(3,("_srv_net_file_query_secdesc: Unable to get NT ACL for file %s\n", r->in.file)); + DEBUG(3,("_srv_net_file_query_secdesc: Unable to get NT ACL for file %s\n", tmp_file)); status = WERR_ACCESS_DENIED; goto error_exit; } @@ -2152,7 +2155,7 @@ WERROR _srvsvc_NetSetFileSecurity(pipes_struct *p, struct srvsvc_NetSetFileSecur connection_struct *conn = NULL; BOOL became_user = False; WERROR status = WERR_OK; - pstring tmp_file; + char *tmp_file = NULL; ZERO_STRUCT(st); @@ -2176,28 +2179,31 @@ WERROR _srvsvc_NetSetFileSecurity(pipes_struct *p, struct srvsvc_NetSetFileSecur } became_user = True; - pstrcpy(tmp_file, r->in.file); - nt_status = unix_convert(conn, tmp_file, False, NULL, &st); + if (!r->in.file) { + status = WERR_INVALID_PARAM; + goto error_exit; + } + nt_status = unix_convert(conn, r->in.file, False, &tmp_file, NULL, &st); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(3,("_srv_net_file_set_secdesc: bad pathname %s\n", r->in.file)); status = WERR_ACCESS_DENIED; goto error_exit; } - nt_status = check_name(conn, r->in.file); + nt_status = check_name(conn, tmp_file); if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(3,("_srv_net_file_set_secdesc: can't access %s\n", r->in.file)); + DEBUG(3,("_srv_net_file_set_secdesc: can't access %s\n", tmp_file)); status = WERR_ACCESS_DENIED; goto error_exit; } - nt_status = open_file_stat(conn, NULL, r->in.file, &st, &fsp); + nt_status = open_file_stat(conn, NULL, tmp_file, &st, &fsp); if (!NT_STATUS_IS_OK(nt_status)) { /* Perhaps it is a directory */ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_IS_A_DIRECTORY)) - nt_status = open_directory(conn, NULL, r->in.file, &st, + nt_status = open_directory(conn, NULL, tmp_file, &st, FILE_READ_ATTRIBUTES, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, @@ -2206,7 +2212,7 @@ WERROR _srvsvc_NetSetFileSecurity(pipes_struct *p, struct srvsvc_NetSetFileSecur NULL, &fsp); if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(3,("_srv_net_file_set_secdesc: Unable to open file %s\n", r->in.file)); + DEBUG(3,("_srv_net_file_set_secdesc: Unable to open file %s\n", tmp_file)); status = WERR_ACCESS_DENIED; goto error_exit; } @@ -2215,7 +2221,7 @@ WERROR _srvsvc_NetSetFileSecurity(pipes_struct *p, struct srvsvc_NetSetFileSecur nt_status = SMB_VFS_SET_NT_ACL(fsp, fsp->fsp_name, r->in.securityinformation, r->in.sd_buf.sd); if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(3,("_srv_net_file_set_secdesc: Unable to set NT ACL on file %s\n", r->in.file)); + DEBUG(3,("_srv_net_file_set_secdesc: Unable to set NT ACL on file %s\n", tmp_file)); status = WERR_ACCESS_DENIED; goto error_exit; } diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index eec8fa12ef..e602008b8f 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -380,12 +380,11 @@ static void dptr_close_oldest(BOOL old) wcard must not be zero. ****************************************************************************/ -NTSTATUS dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid, +NTSTATUS dptr_create(connection_struct *conn, const char *path, BOOL old_handle, BOOL expect_close,uint16 spid, const char *wcard, BOOL wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret) { struct dptr_struct *dptr = NULL; struct smb_Dir *dir_hnd; - const char *dir2; NTSTATUS status; DEBUG(5,("dptr_create dir=%s\n", path)); @@ -399,17 +398,12 @@ NTSTATUS dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOO return status; } - /* use a const pointer from here on */ - dir2 = path; - if (!*dir2) - dir2 = "."; - - dir_hnd = OpenDir(conn, dir2, wcard, attr); + dir_hnd = OpenDir(conn, path, wcard, attr); if (!dir_hnd) { return map_nt_error_from_unix(errno); } - string_set(&conn->dirpath,dir2); + string_set(&conn->dirpath,path); if (dirhandles_open >= MAX_OPEN_DIRECTORIES) { dptr_idleoldest(); @@ -488,7 +482,7 @@ NTSTATUS dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOO dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */ - string_set(&dptr->path,dir2); + string_set(&dptr->path,path); dptr->conn = conn; dptr->dir_hnd = dir_hnd; dptr->spid = spid; @@ -758,10 +752,15 @@ BOOL dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype) return True; } -static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask) +static BOOL mangle_mask_match(connection_struct *conn, const char *filename, + char *mask) { - mangle_map(filename,True,False,conn->params); - return mask_match_search(filename,mask,False); + char mname[13]; + + if (!name_to_8_3(filename,mname,False,conn->params)) { + return False; + } + return mask_match_search(mname,mask,False); } /**************************************************************************** @@ -806,9 +805,14 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,uint32 dirtype, pstring fn mask_match_search(filename,mask,False) || mangle_mask_match(conn,filename,mask)) { - if (!mangle_is_8_3(filename, False, conn->params)) - mangle_map(filename,True,False, - conn->params); + 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); + } pstrcpy(fname,filename); *path = 0; diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 5f9563b83c..5871fd143f 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -2,7 +2,7 @@ Unix SMB/CIFS implementation. filename handling routines Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Jeremy Allison 1999-2004 + Copyright (C) Jeremy Allison 1999-2007 Copyright (C) Ying Chen 2000 Copyright (C) Volker Lendecke 2007 @@ -37,11 +37,12 @@ static BOOL mangled_equal(const char *name1, const char *name2, const struct share_params *p) { - pstring tmpname; + char mname[13]; - pstrcpy(tmpname, name2); - mangle_map(tmpname, True, False, p); - return strequal(name1, tmpname); + if (!name_to_8_3(name2, mname, False, p)) { + return False; + } + return strequal(name1, mname); } /**************************************************************************** @@ -107,9 +108,10 @@ for nlinks = 0, which can never be true for any file). ****************************************************************************/ NTSTATUS unix_convert(connection_struct *conn, - pstring orig_path, + const char *orig_path, BOOL allow_wcard_last_component, - char *saved_last_component, + char **pp_conv_path, + char **pp_saved_last_component, SMB_STRUCT_STAT *pst) { SMB_STRUCT_STAT st; @@ -119,16 +121,20 @@ NTSTATUS unix_convert(connection_struct *conn, BOOL component_was_mangled = False; BOOL name_has_wildcard = False; NTSTATUS result; + TALLOC_CTX *ctx = talloc_tos(); SET_STAT_INVALID(*pst); - - if(saved_last_component) { - *saved_last_component = 0; + *pp_conv_path = NULL; + if(pp_saved_last_component) { + *pp_saved_last_component = NULL; } if (conn->printer) { /* we don't ever use the filenames on a printer share as a filename - so don't convert them */ + if (!(*pp_conv_path = talloc_strdup(ctx,orig_path))) { + return NT_STATUS_NO_MEMORY; + } return NT_STATUS_OK; } @@ -157,11 +163,13 @@ NTSTATUS unix_convert(connection_struct *conn, */ if (!*orig_path) { - if (!(name = SMB_STRDUP("."))) { + if (!(name = talloc_strdup(ctx,"."))) { return NT_STATUS_NO_MEMORY; } if (SMB_VFS_STAT(conn,name,&st) == 0) { *pst = st; + } else { + return map_nt_error_from_unix(errno); } DEBUG(5,("conversion finished \"\" -> %s\n",name)); goto done; @@ -183,17 +191,18 @@ NTSTATUS unix_convert(connection_struct *conn, * Ensure saved_last_component is valid even if file exists. */ - if(saved_last_component) { + if(pp_saved_last_component) { end = strrchr_m(orig_path, '/'); if (end) { - pstrcpy(saved_last_component, end + 1); + *pp_saved_last_component = talloc_strdup(ctx, end + 1); } else { - pstrcpy(saved_last_component, orig_path); + *pp_saved_last_component = talloc_strdup(ctx, + orig_path); } } - if (!(name = SMB_STRDUP(orig_path))) { - DEBUG(0, ("strdup failed\n")); + if (!(name = talloc_strdup(ctx, orig_path))) { + DEBUG(0, ("talloc_strdup failed\n")); return NT_STATUS_NO_MEMORY; } @@ -224,9 +233,9 @@ NTSTATUS unix_convert(connection_struct *conn, * building the directories with asprintf and free it. */ - if ((dirpath == NULL) && (!(dirpath = SMB_STRDUP("")))) { - DEBUG(0, ("strdup failed\n")); - SAFE_FREE(name); + if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) { + DEBUG(0, ("talloc_strdup failed\n")); + TALLOC_FREE(name); return NT_STATUS_NO_MEMORY; } @@ -264,8 +273,7 @@ NTSTATUS unix_convert(connection_struct *conn, */ if (conn->case_sensitive && - !mangle_is_mangled(name, conn->params) && - !*lp_mangled_map(conn->params)) { + !mangle_is_mangled(name, conn->params)) { goto done; } @@ -302,8 +310,14 @@ NTSTATUS unix_convert(connection_struct *conn, *end = 0; } - if (saved_last_component != 0) { - pstrcpy(saved_last_component, end ? end + 1 : start); + if (pp_saved_last_component) { + TALLOC_FREE(*pp_saved_last_component); + *pp_saved_last_component = talloc_strdup(ctx, + end ? end + 1 : start); + if (!*pp_saved_last_component) { + DEBUG(0, ("talloc failed\n")); + return NT_STATUS_NO_MEMORY; + } } /* The name cannot have a component of "." */ @@ -473,25 +487,27 @@ NTSTATUS unix_convert(connection_struct *conn, */ if (mangle_is_mangled(start, conn->params) - && mangle_check_cache_alloc(start, - &unmangled, - conn->params)) { + && mangle_lookup_name_from_8_3(ctx, + start, + &unmangled, + conn->params)) { char *tmp; size_t start_ofs = start - name; if (*dirpath != '\0') { - asprintf(&tmp, "%s/%s", dirpath, - unmangled); - SAFE_FREE(unmangled); + tmp = talloc_asprintf(ctx, + "%s/%s", dirpath, + unmangled); + TALLOC_FREE(unmangled); } else { tmp = unmangled; } if (tmp == NULL) { - DEBUG(0, ("malloc failed\n")); - result = NT_STATUS_NO_MEMORY; + DEBUG(0, ("talloc failed\n")); + return NT_STATUS_NO_MEMORY; } - SAFE_FREE(name); + TALLOC_FREE(name); name = tmp; start = name + start_ofs; end = start + strlen(start); @@ -511,18 +527,20 @@ NTSTATUS unix_convert(connection_struct *conn, size_t start_ofs = start - name; if (*dirpath != '\0') { - asprintf(&tmp, "%s/%s/%s", dirpath, - found_name, end+1); + tmp = talloc_asprintf(ctx, + "%s/%s/%s", dirpath, + found_name, end+1); } else { - asprintf(&tmp, "%s/%s", found_name, - end+1); + tmp = talloc_asprintf(ctx, + "%s/%s", found_name, + end+1); } if (tmp == NULL) { - DEBUG(0, ("asprintf failed\n")); - result = NT_STATUS_NO_MEMORY; + DEBUG(0, ("talloc_asprintf failed\n")); + return NT_STATUS_NO_MEMORY; } - SAFE_FREE(name); + TALLOC_FREE(name); name = tmp; start = name + start_ofs; end = start + strlen(found_name); @@ -532,18 +550,19 @@ NTSTATUS unix_convert(connection_struct *conn, size_t start_ofs = start - name; if (*dirpath != '\0') { - asprintf(&tmp, "%s/%s", dirpath, - found_name); + tmp = talloc_asprintf(ctx, + "%s/%s", dirpath, + found_name); } else { - tmp = SMB_STRDUP(found_name); + tmp = talloc_strdup(ctx, + found_name); } if (tmp == NULL) { - DEBUG(0, ("malloc failed\n")); - result = NT_STATUS_NO_MEMORY; - goto fail; + DEBUG(0, ("talloc failed\n")); + return NT_STATUS_NO_MEMORY; } - SAFE_FREE(name); + TALLOC_FREE(name); name = tmp; start = name + start_ofs; @@ -560,7 +579,7 @@ NTSTATUS unix_convert(connection_struct *conn, } } - SAFE_FREE(found_name); + TALLOC_FREE(found_name); } /* end else */ #ifdef DEVELOPER @@ -577,19 +596,19 @@ NTSTATUS unix_convert(connection_struct *conn, */ if (*dirpath != '\0') { - char *tmp; - - if (asprintf(&tmp, "%s/%s", dirpath, start) == -1) { - DEBUG(0, ("asprintf failed\n")); + char *tmp = talloc_asprintf(ctx, + "%s/%s", dirpath, start); + if (!tmp) { + DEBUG(0, ("talloc_asprintf failed\n")); return NT_STATUS_NO_MEMORY; } - SAFE_FREE(dirpath); + TALLOC_FREE(dirpath); dirpath = tmp; } else { - SAFE_FREE(dirpath); - if (!(dirpath = SMB_STRDUP(start))) { - DEBUG(0, ("strdup failed\n")); + TALLOC_FREE(dirpath); + if (!(dirpath = talloc_strdup(ctx,start))) { + DEBUG(0, ("talloc_strdup failed\n")); return NT_STATUS_NO_MEMORY; } } @@ -628,17 +647,23 @@ NTSTATUS unix_convert(connection_struct *conn, DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); done: - pstrcpy(orig_path, name); - SAFE_FREE(name); - SAFE_FREE(dirpath); + *pp_conv_path = name; + TALLOC_FREE(dirpath); return NT_STATUS_OK; fail: DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start)); - pstrcpy(orig_path, dirpath); - pstrcat(orig_path, "/"); - pstrcat(orig_path, start); - SAFE_FREE(name); - SAFE_FREE(dirpath); + if (*dirpath != '\0') { + *pp_conv_path = talloc_asprintf(ctx, + "%s/%s", dirpath, start); + } else { + *pp_conv_path = talloc_strdup(ctx, start); + } + if (!*pp_conv_path) { + DEBUG(0, ("talloc_asprintf failed\n")); + return NT_STATUS_NO_MEMORY; + } + TALLOC_FREE(name); + TALLOC_FREE(dirpath); return result; } @@ -649,7 +674,7 @@ NTSTATUS unix_convert(connection_struct *conn, a valid one for the user to access. ****************************************************************************/ -NTSTATUS check_name(connection_struct *conn, const pstring name) +NTSTATUS check_name(connection_struct *conn, const char *name) { if (IS_VETO_PATH(conn, name)) { /* Is it not dot or dot dot. */ @@ -682,8 +707,9 @@ static BOOL fname_equal(const char *name1, const char *name2, BOOL case_sensitive) { /* Normal filename handling */ - if (case_sensitive) + if (case_sensitive) { return(strcmp(name1,name2) == 0); + } return(strequal(name1,name2)); } @@ -701,17 +727,19 @@ static BOOL scan_directory(connection_struct *conn, const char *path, BOOL mangled; char *unmangled_name = NULL; long curpos; + TALLOC_CTX *ctx = talloc_tos(); mangled = mangle_is_mangled(name, conn->params); /* handle null paths */ - if ((path == NULL) || (*path == 0)) + if ((path == NULL) || (*path == 0)) { path = "."; + } /* * The incoming name can be mangled, and if we de-mangle it * here it will not compare correctly against the filename (name2) - * read from the directory and then mangled by the mangle_map() + * read from the directory and then mangled by the name_to_8_3() * call. We need to mangle both names or neither. * (JRA). * @@ -724,15 +752,19 @@ static BOOL scan_directory(connection_struct *conn, const char *path, */ if (mangled && !conn->case_sensitive) { - mangled = !mangle_check_cache_alloc(name, &unmangled_name, - conn->params); - name = unmangled_name; + mangled = !mangle_lookup_name_from_8_3(ctx, + name, + &unmangled_name, + conn->params); + if (mangled) { + name = unmangled_name; + } } /* open the directory */ if (!(cur_dir = OpenDir(conn, path, NULL, 0))) { DEBUG(3,("scan dir didn't open dir [%s]\n",path)); - SAFE_FREE(unmangled_name); + TALLOC_FREE(unmangled_name); return(False); } @@ -741,8 +773,7 @@ static BOOL scan_directory(connection_struct *conn, const char *path, while ((dname = ReadDirName(cur_dir, &curpos))) { /* Is it dot or dot dot. */ - if ((dname[0] == '.') && (!dname[1] || - (dname[1] == '.' && !dname[2]))) { + if (ISDOT(dname) || ISDOTDOT(dname)) { continue; } @@ -760,15 +791,19 @@ static BOOL scan_directory(connection_struct *conn, const char *path, if ((mangled && mangled_equal(name,dname,conn->params)) || fname_equal(name, dname, conn->case_sensitive)) { /* we've found the file, change it's name and return */ - *found_name = SMB_STRDUP(dname); - SAFE_FREE(unmangled_name); + *found_name = talloc_strdup(ctx,dname); + TALLOC_FREE(unmangled_name); CloseDir(cur_dir); + if (!*found_name) { + errno = ENOMEM; + return False; + } return(True); } } - SAFE_FREE(unmangled_name); + TALLOC_FREE(unmangled_name); CloseDir(cur_dir); errno = ENOENT; - return(False); + return False; } diff --git a/source3/smbd/mangle.c b/source3/smbd/mangle.c index fce86903f2..61490c444e 100644 --- a/source3/smbd/mangle.c +++ b/source3/smbd/mangle.c @@ -1,18 +1,18 @@ -/* +/* Unix SMB/CIFS implementation. Name mangling interface Copyright (C) Andrew Tridgell 2002 - + 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 . */ @@ -100,50 +100,51 @@ BOOL mangle_is_8_3_wildcards(const char *fname, BOOL check_case, return mangle_fns->is_8_3(fname, check_case, True, p); } +BOOL mangle_must_mangle(const char *fname, + const struct share_params *p) +{ + if (!lp_manglednames(p)) { + return False; + } + return mangle_fns->must_mangle(fname, p); +} + /* - try to reverse map a 8.3 name to the original filename. This doesn't have to + try to reverse map a 8.3 name to the original filename. This doesn't have to always succeed, as the directory handling code in smbd will scan the directory looking for a matching name if it doesn't. It should succeed most of the time or there will be a huge performance penalty */ -BOOL mangle_check_cache(char *s, size_t maxlen, +BOOL mangle_lookup_name_from_8_3(TALLOC_CTX *ctx, + const char *in, + char **out, /* talloced on the given context. */ const struct share_params *p) { - return mangle_fns->check_cache(s, maxlen, p); -} - -BOOL mangle_check_cache_alloc(const char *name, char **presult, - const struct share_params *p) -{ - pstring tmp; - char *result; - pstrcpy(tmp, name); - - if (!mangle_check_cache(tmp, sizeof(pstring)-1, p) - || !(result = SMB_STRDUP(tmp))) { - return False; - } - *presult = result; - return True; + return mangle_fns->lookup_name_from_8_3(ctx, in, out, p); } -/* - map a long filename to a 8.3 name. +/* + mangle a long filename to a 8.3 name. + Return True if we did mangle the name (ie. out is filled in). + False on error. + JRA. */ -void mangle_map(pstring OutName, BOOL need83, BOOL cache83, +BOOL name_to_8_3(const char *in, + char out[13], + BOOL cache83, const struct share_params *p) { /* name mangling can be disabled for speed, in which case we just truncate the string */ if (!lp_manglednames(p)) { - if (need83) { - string_truncate(OutName, 12); - } - return; + safe_strcpy(out,in,12); + return True; } - /* invoke the inane "mangled map" code */ - mangle_map_filename(OutName, p); - mangle_fns->name_map(OutName, need83, cache83, lp_defaultcase(p->service), p); + return mangle_fns->name_to_8_3(in, + out, + cache83, + lp_defaultcase(p->service), + p); } diff --git a/source3/smbd/mangle_hash.c b/source3/smbd/mangle_hash.c index 4c02d9685f..d63a980cfb 100644 --- a/source3/smbd/mangle_hash.c +++ b/source3/smbd/mangle_hash.c @@ -1,20 +1,21 @@ -/* +/* Unix SMB/CIFS implementation. Name mangling Copyright (C) Andrew Tridgell 1992-2002 Copyright (C) Simo Sorce 2001 Copyright (C) Andrew Bartlett 2002 - + 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 . */ @@ -244,14 +245,14 @@ static NTSTATUS is_8_3_w(const smb_ucs2_t *fname, BOOL allow_wildcards) if (strlen_w(fname) > 12) return NT_STATUS_UNSUCCESSFUL; - + if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0) return NT_STATUS_OK; /* Name cannot start with '.' */ if (*fname == UCS2_CHAR('.')) return NT_STATUS_UNSUCCESSFUL; - + if (!NT_STATUS_IS_OK(is_valid_name(fname, allow_wildcards, True))) goto done; @@ -293,7 +294,7 @@ static BOOL is_8_3(const char *fname, BOOL check_case, BOOL allow_wildcards, if (strlen(f) > 12) return False; - + size = push_ucs2_allocate(&ucs2name, f); if (size == (size_t)-1) { DEBUG(0,("is_8_3: internal error push_ucs2_allocate() failed!\n")); @@ -305,15 +306,13 @@ static BOOL is_8_3(const char *fname, BOOL check_case, BOOL allow_wildcards, done: SAFE_FREE(ucs2name); - if (!NT_STATUS_IS_OK(ret)) { + if (!NT_STATUS_IS_OK(ret)) { return False; } - + return True; } - - /* -------------------------------------------------------------------------- ** * Functions... */ @@ -330,10 +329,11 @@ done: * * ************************************************************************** ** */ + static void init_chartest( void ) { const unsigned char *s; - + memset( (char *)chartest, '\0', 256 ); for( s = (const unsigned char *)basechars; *s; s++ ) { @@ -360,6 +360,7 @@ static void init_chartest( void ) * * ************************************************************************** ** */ + static BOOL is_mangled(const char *s, const struct share_params *p) { char *magic; @@ -406,7 +407,8 @@ static void mangle_reset( void ) crh 07-Apr-1998 **************************************************************************/ -static void cache_mangled_name( const char mangled_name[13], char *raw_name ) +static void cache_mangled_name( const char mangled_name[13], + const char *raw_name ) { TDB_DATA data_val; char mangled_name_key[13]; @@ -459,30 +461,37 @@ static void cache_mangled_name( const char mangled_name[13], char *raw_name ) * ************************************************************************** ** */ -static BOOL check_cache( char *s, size_t maxlen, const struct share_params *p ) +static BOOL lookup_name_from_8_3(TALLOC_CTX *ctx, + const char *in, + char **out, /* talloced on the given context. */ + const struct share_params *p) { TDB_DATA data_val; - char *ext_start = NULL; char *saved_ext = NULL; + char *s = talloc_strdup(ctx, in); magic_char = lp_magicchar(p); /* If the cache isn't initialized, give up. */ - if( !tdb_mangled_cache ) - return( False ); + if(!s || !tdb_mangled_cache ) { + TALLOC_FREE(s); + return False; + } data_val = tdb_fetch_bystring(tdb_mangled_cache, s); /* If we didn't find the name *with* the extension, try without. */ if(data_val.dptr == NULL || data_val.dsize == 0) { - ext_start = strrchr( s, '.' ); + char *ext_start = strrchr( s, '.' ); if( ext_start ) { - if((saved_ext = SMB_STRDUP(ext_start)) == NULL) + if((saved_ext = talloc_strdup(ctx,ext_start)) == NULL) { + TALLOC_FREE(s); return False; + } *ext_start = '\0'; data_val = tdb_fetch_bystring(tdb_mangled_cache, s); - /* + /* * At this point s is the name without the * extension. We re-add the extension if saved_ext * is not null, before freeing saved_ext. @@ -492,31 +501,32 @@ static BOOL check_cache( char *s, size_t maxlen, const struct share_params *p ) /* Okay, if we haven't found it we're done. */ if(data_val.dptr == NULL || data_val.dsize == 0) { - if(saved_ext) { - /* Replace the saved_ext as it was truncated. */ - (void)safe_strcat( s, saved_ext, maxlen ); - SAFE_FREE(saved_ext); - } - return( False ); + TALLOC_FREE(saved_ext); + TALLOC_FREE(s); + return False; } - /* If we *did* find it, we need to copy it into the string buffer. */ - (void)safe_strcpy( s, (const char *)data_val.dptr, maxlen ); - if( saved_ext ) { - /* Replace the saved_ext as it was truncated. */ - (void)safe_strcat( s, saved_ext, maxlen ); - SAFE_FREE(saved_ext); + /* If we *did* find it, we need to talloc it on the given ctx. */ + if (saved_ext) { + *out = talloc_asprintf(ctx, "%s%s", + (char *)data_val.dptr, + saved_ext); + } else { + *out = talloc_strdup(ctx, (char *)data_val.dptr); } + + TALLOC_FREE(s); + TALLOC_FREE(saved_ext); SAFE_FREE(data_val.dptr); - return( True ); + + return *out ? True : False; } /***************************************************************************** - * do the actual mangling to 8.3 format - * the buffer must be able to hold 13 characters (including the null) - ***************************************************************************** - */ -static void to_8_3(char *s, int default_case) + Do the actual mangling to 8.3 format. +*****************************************************************************/ + +static BOOL to_8_3(const char *in, char out[13], int default_case) { int csum; char *p; @@ -524,11 +534,16 @@ static void to_8_3(char *s, int default_case) char base[9]; int baselen = 0; int extlen = 0; + char *s = SMB_STRDUP(in); extension[0] = 0; base[0] = 0; - p = strrchr(s,'.'); + if (!s) { + return False; + } + + p = strrchr(s,'.'); if( p && (strlen(p+1) < (size_t)4) ) { BOOL all_normal = ( strisnormal(p+1, default_case) ); /* XXXXXXXXX */ @@ -557,7 +572,7 @@ static void to_8_3(char *s, int default_case) extension[extlen] = 0; } } - + p = s; while( *p && baselen < 5 ) { @@ -567,79 +582,88 @@ static void to_8_3(char *s, int default_case) p++; } base[baselen] = 0; - + csum = csum % (MANGLE_BASE*MANGLE_BASE); - - (void)slprintf(s, 12, "%s%c%c%c", - base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) ); - + + memcpy(out, base, baselen); + out[baselen] = magic_char; + out[baselen+1] = mangle( csum/MANGLE_BASE ); + out[baselen+2] = mangle( csum ); + if( *extension ) { - (void)pstrcat( s, "." ); - (void)pstrcat( s, extension ); + out[baselen+3] = '.'; + safe_strcpy(&out[baselen+4], extension, 3); + } + + SAFE_FREE(s); + return True; +} + +static BOOL must_mangle(const char *name, + const struct share_params *p) +{ + smb_ucs2_t *name_ucs2 = NULL; + NTSTATUS status; + magic_char = lp_magicchar(p); + + if (push_ucs2_allocate(&name_ucs2, name) == (size_t)-1) { + DEBUG(0, ("push_ucs2_allocate failed!\n")); + return False; } + status = is_valid_name(name_ucs2, False, False); + SAFE_FREE(name_ucs2); + return NT_STATUS_IS_OK(status); } /***************************************************************************** * Convert a filename to DOS format. Return True if successful. + * Input: in Incoming name. * - * Input: OutName - Source *and* destination buffer. + * out 8.3 DOS name. * - * NOTE that OutName must point to a memory space that - * is at least 13 bytes in size! - * - * need83 - If False, name mangling will be skipped unless the - * name contains illegal characters. Mapping will still - * be done, if appropriate. This is probably used to - * signal that a client does not require name mangling, - * thus skipping the name mangling even on shares which - * have name-mangling turned on. * cache83 - If False, the mangled name cache will not be updated. * This is usually used to prevent that we overwrite * a conflicting cache entry prematurely, i.e. before * we know whether the client is really interested in the * current name. (See PR#13758). UKD. * - * Output: Returns False only if the name wanted mangling but the share does - * not have name mangling turned on. - * * **************************************************************************** */ -static void name_map(char *OutName, BOOL need83, BOOL cache83, - int default_case, const struct share_params *p) +static BOOL hash_name_to_8_3(const char *in, + char out[13], + BOOL cache83, + int default_case, + const struct share_params *p) { - smb_ucs2_t *OutName_ucs2; + smb_ucs2_t *in_ucs2 = NULL; magic_char = lp_magicchar(p); - DEBUG(5,("name_map( %s, need83 = %s, cache83 = %s)\n", OutName, - need83 ? "True" : "False", cache83 ? "True" : "False")); - - if (push_ucs2_allocate(&OutName_ucs2, OutName) == (size_t)-1) { + DEBUG(5,("hash_name_to_8_3( %s, cache83 = %s)\n", in, + cache83 ? "True" : "False")); + + if (push_ucs2_allocate(&in_ucs2, in) == (size_t)-1) { DEBUG(0, ("push_ucs2_allocate failed!\n")); - return; + return False; } - if( !need83 && !NT_STATUS_IS_OK(is_valid_name(OutName_ucs2, False, False))) - need83 = True; - - /* check if it's already in 8.3 format */ - if (need83 && !NT_STATUS_IS_OK(is_8_3_w(OutName_ucs2, False))) { - char *tmp = NULL; - - /* mangle it into 8.3 */ - if (cache83) - tmp = SMB_STRDUP(OutName); - - to_8_3(OutName, default_case); + /* If it's already 8.3, just copy. */ + if (NT_STATUS_IS_OK(is_valid_name(in_ucs2, False, False)) && + NT_STATUS_IS_OK(is_8_3_w(in_ucs2, False))) { + SAFE_FREE(in_ucs2); + safe_strcpy(out, in, 12); + return True; + } - if(tmp != NULL) { - cache_mangled_name(OutName, tmp); - SAFE_FREE(tmp); - } + SAFE_FREE(in_ucs2); + if (!to_8_3(in, out, default_case)) { + return False; } - DEBUG(5,("name_map() ==> [%s]\n", OutName)); - SAFE_FREE(OutName_ucs2); + cache_mangled_name(out, in); + + DEBUG(5,("hash_name_to_8_3(%s) ==> [%s]\n", in, out)); + return True; } /* @@ -649,9 +673,10 @@ static void name_map(char *OutName, BOOL need83, BOOL cache83, static struct mangle_fns mangle_fns = { mangle_reset, is_mangled, + must_mangle, is_8_3, - check_cache, - name_map + lookup_name_from_8_3, + hash_name_to_8_3 }; /* return the methods for this mangling implementation */ diff --git a/source3/smbd/mangle_hash2.c b/source3/smbd/mangle_hash2.c index c3db112051..73f81fe9ae 100644 --- a/source3/smbd/mangle_hash2.c +++ b/source3/smbd/mangle_hash2.c @@ -368,18 +368,23 @@ static void mangle_reset(void) /* try to find a 8.3 name in the cache, and if found then - replace the string with the original long name. + replace the string with the original long name. */ -static BOOL check_cache(char *name, size_t maxlen, const struct share_params *p) +static BOOL lookup_name_from_8_3(TALLOC_CTX *ctx, + const char *name, + char **pp_out, /* talloced on the given context. */ + const struct share_params *p) { unsigned int hash, multiplier; unsigned int i; const char *prefix; char extension[4]; + *pp_out = NULL; + /* make sure that this is a mangled name from this cache */ if (!is_mangled(name, p)) { - M_DEBUG(10,("check_cache: %s -> not mangled\n", name)); + M_DEBUG(10,("lookup_name_from_8_3: %s -> not mangled\n", name)); return False; } @@ -394,7 +399,8 @@ static BOOL check_cache(char *name, size_t maxlen, const struct share_params *p) /* now look in the prefix cache for that hash */ prefix = cache_lookup(hash); if (!prefix) { - M_DEBUG(10,("check_cache: %s -> %08X -> not found\n", name, hash)); + M_DEBUG(10,("lookup_name_from_8_3: %s -> %08X -> not found\n", + name, hash)); return False; } @@ -407,17 +413,22 @@ static BOOL check_cache(char *name, size_t maxlen, const struct share_params *p) } if (extension[0]) { - M_DEBUG(10,("check_cache: %s -> %s.%s\n", name, prefix, extension)); - slprintf(name, maxlen, "%s.%s", prefix, extension); + M_DEBUG(10,("lookup_name_from_8_3: %s -> %s.%s\n", + name, prefix, extension)); + *pp_out = talloc_asprintf(ctx, "%s.%s", prefix, extension); } else { - M_DEBUG(10,("check_cache: %s -> %s\n", name, prefix)); - safe_strcpy(name, prefix, maxlen); + M_DEBUG(10,("lookup_name_from_8_3: %s -> %s\n", name, prefix)); + *pp_out = talloc_strdup(ctx, prefix); + } + + if (!pp_out) { + M_DEBUG(0,("talloc_fail")); + return False; } return True; } - /* look for a DOS reserved name */ @@ -499,18 +510,27 @@ static BOOL is_legal_name(const char *name) return True; } +static BOOL must_mangle(const char *name, + const struct share_params *p) +{ + if (is_reserved_name(name)) { + return True; + } + return !is_legal_name(name); +} + /* the main forward mapping function, which converts a long filename to a 8.3 name - if need83 is not set then we only do the mangling if the name is illegal - as a long name - if cache83 is not set then we don't cache the result - the name parameter must be able to hold 13 bytes */ -static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case, const struct share_params *p) +static BOOL hash2_name_to_8_3(const char *name, + char new_name[13], + BOOL cache83, + int default_case, + const struct share_params *p) { char *dot_p; char lead_chars[7]; @@ -518,20 +538,14 @@ static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case, unsigned int extension_length, i; unsigned int prefix_len; unsigned int hash, v; - char new_name[13]; /* reserved names are handled specially */ if (!is_reserved_name(name)) { - /* if the name is already a valid 8.3 name then we don't need to - do anything */ - if (is_8_3(name, False, False, p)) { - return; - } - - /* if the caller doesn't strictly need 8.3 then just check for illegal - filenames */ - if (!need83 && is_legal_name(name)) { - return; + /* if the name is already a valid 8.3 name then we don't need to + * change anything */ + if (is_legal_name(name) && is_8_3(name, False, False, p)) { + safe_strcpy(new_name, name, 12); + return True; } } @@ -548,7 +562,9 @@ static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case, break; } } - if (i == 0 || i == 4) dot_p = NULL; + if (i == 0 || i == 4) { + dot_p = NULL; + } } /* the leading characters in the mangled name is taken from @@ -580,11 +596,12 @@ static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case, for (i=1; extension_length < 3 && dot_p[i]; i++) { char c = dot_p[i]; if (FLAG_CHECK(c, FLAG_ASCII)) { - extension[extension_length++] = toupper_ascii(c); + extension[extension_length++] = + toupper_ascii(c); } } } - + /* find the hash for this prefix */ v = hash = mangle_hash(name, prefix_len); @@ -593,7 +610,7 @@ static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case, new_name[i] = lead_chars[i]; } new_name[7] = base_forward(v % 36); - new_name[6] = '~'; + new_name[6] = '~'; for (i=5; i>=mangle_prefix; i--) { v = v / 36; new_name[i] = base_forward(v % 36); @@ -613,22 +630,18 @@ static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case, cache_insert(name, prefix_len, hash); } - M_DEBUG(10,("name_map: %s -> %08X -> %s (cache=%d)\n", + M_DEBUG(10,("hash2_name_to_8_3: %s -> %08X -> %s (cache=%d)\n", name, hash, new_name, cache83)); - /* and overwrite the old name */ - fstrcpy(name, new_name); - - /* all done, we've managed to mangle it */ + return True; } - -/* initialise the flags table +/* initialise the flags table we allow only a very restricted set of characters as 'ascii' in this mangling backend. This isn't a significant problem as modern clients use the 'long' filenames anyway, and those don't have these - restrictions. + restrictions. */ static void init_tables(void) { @@ -642,8 +655,8 @@ static void init_tables(void) char_flags[i] |= FLAG_ILLEGAL; } - if ((i >= '0' && i <= '9') || - (i >= 'a' && i <= 'z') || + if ((i >= '0' && i <= '9') || + (i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z')) { char_flags[i] |= (FLAG_ASCII | FLAG_BASECHAR); } @@ -663,7 +676,7 @@ static void init_tables(void) memset(base_reverse, 0, sizeof(base_reverse)); for (i=0;i<36;i++) { base_reverse[(unsigned char)base_forward(i)] = i; - } + } /* fill in the reserved names flags. These are used as a very fast filter for finding possible DOS reserved filenames */ @@ -694,9 +707,10 @@ static void init_tables(void) static struct mangle_fns mangle_fns = { mangle_reset, is_mangled, + must_mangle, is_8_3, - check_cache, - name_map + lookup_name_from_8_3, + hash2_name_to_8_3 }; /* return the methods for this mangling implementation */ @@ -729,30 +743,45 @@ static BOOL posix_is_mangled(const char *s, const struct share_params *p) return False; } -static BOOL posix_is_8_3(const char *fname, BOOL check_case, BOOL allow_wildcards, const struct share_params *p) +static BOOL posix_must_mangle(const char *s, const struct share_params *p) { return False; } -static BOOL posix_check_cache( char *s, size_t maxlen, const struct share_params *p ) +static BOOL posix_is_8_3(const char *fname, + BOOL check_case, + BOOL allow_wildcards, + const struct share_params *p) { return False; } -static void posix_name_map(char *OutName, BOOL need83, BOOL cache83, int default_case, const struct share_params *p) +static BOOL posix_lookup_name_from_8_3(TALLOC_CTX *ctx, + const char *in, + char **out, /* talloced on the given context. */ + const struct share_params *p) { - if (need83) { - memset(OutName, '\0', 13); - } + return False; +} + +static BOOL posix_name_to_8_3(const char *in, + char out[13], + BOOL cache83, + int default_case, + const struct share_params *p) +{ + memset(out, '\0', 13); + return True; } /* POSIX paths backend - no mangle. */ static struct mangle_fns posix_mangle_fns = { - posix_mangle_reset, - posix_is_mangled, - posix_is_8_3, - posix_check_cache, - posix_name_map + posix_mangle_reset, + posix_is_mangled, + posix_must_mangle, + posix_is_8_3, + posix_lookup_name_from_8_3, + posix_name_to_8_3 }; struct mangle_fns *posix_mangle_init(void) diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index 16f3cd4370..10652874c5 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -369,7 +369,8 @@ static NTSTATUS dfs_path_lookup(connection_struct *conn, char *q = NULL; SMB_STRUCT_STAT sbuf; NTSTATUS status; - pstring localpath; + pstring localpath_in; + char *localpath = NULL; pstring canon_dfspath; /* Canonicalized dfs path. (only '/' components). */ DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n", @@ -387,8 +388,8 @@ static NTSTATUS dfs_path_lookup(connection_struct *conn, * think this is needed. JRA. */ - pstrcpy(localpath, pdp->reqpath); - status = unix_convert(conn, localpath, search_flag, NULL, &sbuf); + pstrcpy(localpath_in, pdp->reqpath); + status = unix_convert(conn, localpath_in, search_flag, &localpath, NULL, &sbuf); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND)) { return status; diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index b5af173d45..735c147b8d 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -489,7 +489,8 @@ static void reply_ntcreate_and_X_quota(connection_struct *conn, void reply_ntcreate_and_X(connection_struct *conn, struct smb_request *req) { - pstring fname; + pstring fname_in; + char *fname = NULL; uint32 flags; uint32 access_mask; uint32 file_attributes; @@ -589,8 +590,8 @@ void reply_ntcreate_and_X(connection_struct *conn, if(!dir_fsp->is_directory) { - srvstr_get_path((char *)req->inbuf, req->flags2, fname, - smb_buf(req->inbuf), sizeof(fname), 0, + 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); @@ -602,7 +603,7 @@ void reply_ntcreate_and_X(connection_struct *conn, * Check to see if this is a mac fork of some kind. */ - if( is_ntfs_stream_name(fname)) { + if( is_ntfs_stream_name(fname_in)) { reply_nterror( req, NT_STATUS_OBJECT_PATH_NOT_FOUND); END_PROFILE(SMBntcreateX); @@ -625,15 +626,15 @@ void reply_ntcreate_and_X(connection_struct *conn, * Copy in the base directory name. */ - pstrcpy( fname, dir_fsp->fsp_name ); - dir_name_len = strlen(fname); + pstrcpy( fname_in, dir_fsp->fsp_name ); + dir_name_len = strlen(fname_in); /* * Ensure it ends in a '\'. */ - if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) { - pstrcat(fname, "/"); + if((fname_in[dir_name_len-1] != '\\') && (fname_in[dir_name_len-1] != '/')) { + pstrcat(fname_in, "/"); dir_name_len++; } @@ -645,10 +646,10 @@ void reply_ntcreate_and_X(connection_struct *conn, END_PROFILE(SMBntcreateX); return; } - pstrcat(fname, rel_fname); + pstrcat(fname_in, rel_fname); } else { - srvstr_get_path((char *)req->inbuf, req->flags2, fname, - smb_buf(req->inbuf), sizeof(fname), 0, + 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); @@ -660,8 +661,8 @@ void reply_ntcreate_and_X(connection_struct *conn, * Check to see if this is a mac fork of some kind. */ - if( is_ntfs_stream_name(fname)) { - enum FAKE_FILE_TYPE fake_file_type = is_fake_file(fname); + if( is_ntfs_stream_name(fname_in)) { + enum FAKE_FILE_TYPE fake_file_type = is_fake_file(fname_in); if (fake_file_type!=FAKE_FILE_TYPE_NONE) { /* * Here we go! support for changing the disk quotas --metze @@ -673,7 +674,7 @@ void reply_ntcreate_and_X(connection_struct *conn, * xp also tries a QUERY_FILE_INFO on the file and then close it */ reply_ntcreate_and_X_quota(conn, req, - fake_file_type, fname); + fake_file_type, fname_in); } else { reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND); } @@ -686,7 +687,7 @@ void reply_ntcreate_and_X(connection_struct *conn, * Now contruct the smb_open_mode value from the filename, * desired access and the share access. */ - status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname); + status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, 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, @@ -707,17 +708,17 @@ void reply_ntcreate_and_X(connection_struct *conn, /* * Ordinary file or directory. */ - + /* * Check if POSIX semantics are wanted. */ - + if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { case_state = set_posix_case_semantics(NULL, conn); file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS; } - - status = unix_convert(conn, fname, False, NULL, &sbuf); + + status = unix_convert(conn, fname_in, False, &fname, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(case_state); reply_nterror(req, status); @@ -1200,7 +1201,7 @@ static struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, } offset += next_offset; } - + return ea_list_head; } @@ -1215,7 +1216,8 @@ static void call_nt_transact_create(connection_struct *conn, char **ppdata, uint32 data_count, uint32 max_data_count) { - pstring fname; + pstring fname_in; + char *fname = NULL; char *params = *ppparams; char *data = *ppdata; /* Breakout the oplock request bits so we can set the reply bits separately. */ @@ -1334,8 +1336,8 @@ static void call_nt_transact_create(connection_struct *conn, } if(!dir_fsp->is_directory) { - srvstr_get_path(params, req->flags2, fname, - params+53, sizeof(fname), + srvstr_get_path(params, req->flags2, fname_in, + params+53, sizeof(fname_in), parameter_count-53, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { @@ -1347,7 +1349,7 @@ static void call_nt_transact_create(connection_struct *conn, * Check to see if this is a mac fork of some kind. */ - if( is_ntfs_stream_name(fname)) { + if( is_ntfs_stream_name(fname_in)) { reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND); return; @@ -1361,15 +1363,15 @@ static void call_nt_transact_create(connection_struct *conn, * Copy in the base directory name. */ - pstrcpy( fname, dir_fsp->fsp_name ); - dir_name_len = strlen(fname); + pstrcpy( fname_in, dir_fsp->fsp_name ); + dir_name_len = strlen(fname_in); /* * Ensure it ends in a '\'. */ - if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) { - pstrcat(fname, "/"); + if((fname_in[dir_name_len-1] != '\\') && (fname_in[dir_name_len-1] != '/')) { + pstrcat(fname_in, "/"); dir_name_len++; } @@ -1383,11 +1385,11 @@ static void call_nt_transact_create(connection_struct *conn, reply_nterror(req, status); return; } - pstrcat(fname, tmpname); + pstrcat(fname_in, tmpname); } } else { - srvstr_get_path(params, req->flags2, fname, params+53, - sizeof(fname), parameter_count-53, + srvstr_get_path(params, req->flags2, fname_in, params+53, + sizeof(fname_in), parameter_count-53, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -1398,7 +1400,7 @@ static void call_nt_transact_create(connection_struct *conn, * Check to see if this is a mac fork of some kind. */ - if( is_ntfs_stream_name(fname)) { + if( is_ntfs_stream_name(fname_in)) { reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND); return; } @@ -1412,7 +1414,7 @@ static void call_nt_transact_create(connection_struct *conn, /* * Ordinary file or directory. */ - + /* * Check if POSIX semantics are wanted. */ @@ -1421,9 +1423,9 @@ static void call_nt_transact_create(connection_struct *conn, case_state = set_posix_case_semantics(NULL, conn); file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS; } - + status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - fname); + fname_in); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(case_state); if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { @@ -1435,7 +1437,7 @@ static void call_nt_transact_create(connection_struct *conn, 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)) { TALLOC_FREE(case_state); reply_nterror(req, status); @@ -1776,11 +1778,15 @@ void reply_ntcancel(connection_struct *conn, struct smb_request *req) static NTSTATUS copy_internals(connection_struct *conn, struct smb_request *req, - char *oldname, char *newname, uint32 attrs) + const char *oldname_in, + const char *newname_in, + uint32 attrs) { SMB_STRUCT_STAT sbuf1, sbuf2; - pstring last_component_oldname; - pstring last_component_newname; + char *oldname = NULL; + char *newname = NULL; + char *last_component_oldname = NULL; + char *last_component_newname = NULL; files_struct *fsp1,*fsp2; uint32 fattr; int info; @@ -1794,7 +1800,8 @@ static NTSTATUS copy_internals(connection_struct *conn, return NT_STATUS_MEDIA_WRITE_PROTECTED; } - status = unix_convert(conn, oldname, False, last_component_oldname, &sbuf1); + status = unix_convert(conn, oldname_in, False, &oldname, + &last_component_oldname, &sbuf1); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -1814,7 +1821,8 @@ static NTSTATUS copy_internals(connection_struct *conn, return NT_STATUS_NO_SUCH_FILE; } - status = unix_convert(conn, newname, False, last_component_newname, &sbuf2); + status = unix_convert(conn, newname_in, False, &newname, + &last_component_newname, &sbuf2); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -1840,7 +1848,8 @@ static NTSTATUS copy_internals(connection_struct *conn, return status; } - DEBUG(10,("copy_internals: doing file copy %s to %s\n", oldname, newname)); + DEBUG(10,("copy_internals: doing file copy %s to %s\n", + oldname, newname)); status = open_file_ntcreate(conn, req, oldname, &sbuf1, FILE_READ_DATA, /* Read-only. */ 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)) { diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c index d2f09930a0..a066091b52 100644 --- a/source3/smbd/statcache.c +++ b/source3/smbd/statcache.c @@ -2,7 +2,7 @@ Unix SMB/CIFS implementation. stat cache code Copyright (C) Andrew Tridgell 1992-2000 - Copyright (C) Jeremy Allison 1999-2004 + Copyright (C) Jeremy Allison 1999-2007 Copyright (C) Andrew Bartlett 2003 Copyright (C) Volker Lendecke 2007 @@ -40,7 +40,8 @@ static TDB_CONTEXT *tdb_stat_cache; * */ -void stat_cache_add( const char *full_orig_name, const char *translated_path, +void stat_cache_add( const char *full_orig_name, + char *translated_path, BOOL case_sensitive) { size_t translated_path_length; @@ -48,9 +49,12 @@ void stat_cache_add( const char *full_orig_name, const char *translated_path, char *original_path; size_t original_path_length; size_t sc_size = lp_max_stat_cache_size(); + char saved_char; + TALLOC_CTX *ctx = talloc_tos(); - if (!lp_stat_cache()) + if (!lp_stat_cache()) { return; + } if (sc_size && (tdb_map_size(tdb_stat_cache) > sc_size*1024)) { reset_stat_cache(); @@ -73,20 +77,15 @@ void stat_cache_add( const char *full_orig_name, const char *translated_path, * would be a waste. */ - if (case_sensitive && (strcmp(full_orig_name, translated_path) == 0)) + if (case_sensitive && (strcmp(full_orig_name, translated_path) == 0)) { return; + } /* * Remove any trailing '/' characters from the * translated path. */ - /* - * To save a strdup we don't necessarily 0-terminate the translated - * path in the tdb. Instead, we do it directly after the tdb_fetch in - * stat_cache_lookup. - */ - translated_path_length = strlen(translated_path); if(translated_path[translated_path_length-1] == '/') { @@ -94,9 +93,9 @@ void stat_cache_add( const char *full_orig_name, const char *translated_path, } if(case_sensitive) { - original_path = SMB_STRDUP(full_orig_name); + original_path = talloc_strdup(ctx,full_orig_name); } else { - original_path = strdup_upper(full_orig_name); + original_path = talloc_strdup_upper(ctx,full_orig_name); } if (!original_path) { @@ -118,7 +117,7 @@ void stat_cache_add( const char *full_orig_name, const char *translated_path, (unsigned long)original_path_length, translated_path, (unsigned long)translated_path_length)); - SAFE_FREE(original_path); + TALLOC_FREE(original_path); return; } @@ -129,13 +128,17 @@ void stat_cache_add( const char *full_orig_name, const char *translated_path, original_path_length = translated_path_length; } - /* - * New entry or replace old entry. - */ + /* Ensure we're null terminated. */ + saved_char = translated_path[translated_path_length]; + translated_path[translated_path_length] = '\0'; data_val.dsize = translated_path_length + 1; data_val.dptr = (uint8 *)translated_path; + /* + * New entry or replace old entry. + */ + if (tdb_store_bystring(tdb_stat_cache, original_path, data_val, TDB_REPLACE) != 0) { DEBUG(0,("stat_cache_add: Error storing entry %s -> %s\n", @@ -148,7 +151,8 @@ void stat_cache_add( const char *full_orig_name, const char *translated_path, translated_path)); } - SAFE_FREE(original_path); + translated_path[translated_path_length] = saved_char; + TALLOC_FREE(original_path); } /** @@ -157,8 +161,10 @@ void stat_cache_add( const char *full_orig_name, const char *translated_path, * @param conn A connection struct to do the stat() with. * @param name The path we are attempting to cache, modified by this routine * to be correct as far as the cache can tell us. We assume that - * it is a malloc'ed string, we free it if necessary. - * @param dirpath The path as far as the stat cache told us. + * it is a talloc'ed string from top of stack, we free it if + * necessary. + * @param dirpath The path as far as the stat cache told us. Also talloced + * from top of stack. * @param start A pointer into name, for where to 'start' in fixing the rest * of the name up. * @param psd A stat buffer, NOT from the cache, but just a side-effect. @@ -168,8 +174,11 @@ void stat_cache_add( const char *full_orig_name, const char *translated_path, * */ -BOOL stat_cache_lookup(connection_struct *conn, char **pname, char **dirpath, - char **start, SMB_STRUCT_STAT *pst) +BOOL stat_cache_lookup(connection_struct *conn, + char **pp_name, + char **pp_dirpath, + char **pp_start, + SMB_STRUCT_STAT *pst) { char *chk_name; size_t namelen; @@ -179,15 +188,18 @@ BOOL stat_cache_lookup(connection_struct *conn, char **pname, char **dirpath, size_t translated_path_length; TDB_DATA data_val; char *name; + TALLOC_CTX *ctx = talloc_tos(); - if (!lp_stat_cache()) + *pp_dirpath = NULL; + *pp_start = *pp_name; + + if (!lp_stat_cache()) { return False; + } - name = *pname; + name = *pp_name; namelen = strlen(name); - *start = name; - DO_PROFILE_INC(statcache_lookups); /* @@ -198,14 +210,14 @@ BOOL stat_cache_lookup(connection_struct *conn, char **pname, char **dirpath, } if (conn->case_sensitive) { - chk_name = SMB_STRDUP(name); + chk_name = talloc_strdup(ctx,name); if (!chk_name) { DEBUG(0, ("stat_cache_lookup: strdup failed!\n")); return False; } } else { - chk_name = strdup_upper(name); + chk_name = talloc_strdup_upper(ctx,name); if (!chk_name) { DEBUG(0, ("stat_cache_lookup: strdup_upper failed!\n")); return False; @@ -216,8 +228,9 @@ BOOL stat_cache_lookup(connection_struct *conn, char **pname, char **dirpath, * if we uppercase. We need to treat this differently * below. */ - if (strlen(chk_name) != namelen) + if (strlen(chk_name) != namelen) { sizechanged = True; + } } while (1) { @@ -239,7 +252,7 @@ BOOL stat_cache_lookup(connection_struct *conn, char **pname, char **dirpath, * We reached the end of the name - no match. */ DO_PROFILE_INC(statcache_misses); - SAFE_FREE(chk_name); + TALLOC_FREE(chk_name); return False; } @@ -249,25 +262,25 @@ BOOL stat_cache_lookup(connection_struct *conn, char **pname, char **dirpath, * Count the number of times we have done this, we'll * need it when reconstructing the string. */ - if (sizechanged) + + if (sizechanged) { num_components++; + } if ((*chk_name == '\0') || ISDOT(chk_name) || ISDOTDOT(chk_name)) { DO_PROFILE_INC(statcache_misses); - SAFE_FREE(chk_name); + TALLOC_FREE(chk_name); return False; } } - translated_path = (char *)data_val.dptr; + translated_path = talloc_strdup(ctx,(char *)data_val.dptr); + if (!translated_path) { + smb_panic("talloc failed"); + } translated_path_length = data_val.dsize - 1; - - /* - * In stat_cache_add we did not necessarily 0-terminate the translated - * path. Do it here, where we do have a freshly malloc'ed blob. - */ - translated_path[translated_path_length] = '\0'; + SAFE_FREE(data_val.dptr); DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] " "-> [%s]\n", chk_name, translated_path )); @@ -276,50 +289,51 @@ BOOL stat_cache_lookup(connection_struct *conn, char **pname, char **dirpath, if (SMB_VFS_STAT(conn, translated_path, pst) != 0) { /* Discard this entry - it doesn't exist in the filesystem. */ tdb_delete_bystring(tdb_stat_cache, chk_name); - SAFE_FREE(chk_name); - SAFE_FREE(data_val.dptr); + TALLOC_FREE(chk_name); + TALLOC_FREE(translated_path); return False; } if (!sizechanged) { - memcpy(name, translated_path, + memcpy(*pp_name, translated_path, MIN(namelen, translated_path_length)); - } - else { + } else { if (num_components == 0) { - name = SMB_STRNDUP(translated_path, + name = talloc_strndup(ctx, translated_path, translated_path_length); } else { char *sp; sp = strnrchr_m(name, '/', num_components); if (sp) { - asprintf(&name, "%.*s%s", + name = talloc_asprintf(ctx,"%.*s%s", (int)translated_path_length, translated_path, sp); } else { - name = SMB_STRNDUP(translated_path, - translated_path_length); + name = talloc_strndup(ctx, + translated_path, + translated_path_length); } } if (name == NULL) { /* * TODO: Get us out of here with a real error message */ - smb_panic("malloc failed"); + smb_panic("talloc failed"); } - SAFE_FREE(*pname); - *pname = name; + TALLOC_FREE(*pp_name); + *pp_name = name; } /* set pointer for 'where to start' on fixing the rest of the name */ - *start = &name[translated_path_length]; - if (**start == '/') - ++*start; + *pp_start = &name[translated_path_length]; + if (**pp_start == '/') { + ++*pp_start; + } - *dirpath = translated_path; - SAFE_FREE(chk_name); + *pp_dirpath = translated_path; + TALLOC_FREE(chk_name); return (namelen == translated_path_length); } @@ -344,7 +358,7 @@ void send_stat_cache_delete_message(const char *name) void stat_cache_delete(const char *name) { - char *lname = strdup_upper(name); + char *lname = talloc_strdup_upper(talloc_tos(), name); if (!lname) { return; @@ -353,7 +367,7 @@ void stat_cache_delete(const char *name) lname, name )); tdb_delete_bystring(tdb_stat_cache, lname); - SAFE_FREE(lname); + TALLOC_FREE(lname); } /*************************************************************** diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index ed4d4554d4..59f384e8b0 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -783,7 +783,8 @@ static void call_trans2open(connection_struct *conn, int open_ofun; uint32 open_size; char *pname; - pstring fname; + pstring fname_in; + char *fname = NULL; SMB_OFF_T size=0; int fattr=0,mtime=0; SMB_INO_T inode = 0; @@ -829,8 +830,8 @@ static void call_trans2open(connection_struct *conn, return; } - srvstr_get_path(params, req->flags2, fname, pname, - sizeof(fname), total_params - 28, STR_TERMINATE, + srvstr_get_path(params, req->flags2, fname_in, pname, + sizeof(fname_in), total_params - 28, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -843,7 +844,7 @@ static void call_trans2open(connection_struct *conn, /* XXXX we need to handle passed times, sattr and flags */ - 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); return; @@ -1163,6 +1164,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, uint32 nt_extmode; /* Used for NT connections instead of mode */ BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/'); BOOL check_mangled_names = lp_manglednames(conn->params); + char mangled_name[13]; /* mangled 8.3 name. */ *fname = 0; *out_of_space = False; @@ -1215,10 +1217,15 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, * pathreal which is composed from dname. */ - pstrcpy(fname,dname); + pstrcpy(fname,dname); - /* This will mangle fname if it's an illegal name. */ - mangle_map(fname,False,True,conn->params); + /* 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)) { + continue; /* Error - couldn't mangle. */ + } + pstrcpy(fname,mangled_name); + } if(!(got_match = *got_exact_match = exact_match(conn, fname, mask))) { got_match = mask_match(fname, mask, conn->case_sensitive); @@ -1226,19 +1233,17 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, if(!got_match && check_mangled_names && !mangle_is_8_3(fname, False, conn->params)) { - pstring mangled_name; - /* * It turns out that NT matches wildcards against * both long *and* short names. This may explain some * of the wildcard wierdness from old DOS clients * that some people have been seeing.... JRA. */ - - pstrcpy(mangled_name, fname); - /* Force the mangling into 8.3. */ - mangle_map( mangled_name, True, False, conn->params); + if (!name_to_8_3( fname, mangled_name, False, conn->params)) { + continue; /* Error - couldn't mangle. */ + } + if(!(got_match = *got_exact_match = exact_match(conn, mangled_name, mask))) { got_match = mask_match(mangled_name, mask, conn->case_sensitive); } @@ -1483,10 +1488,11 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, * a Win2k client bug. JRA. */ if (!was_8_3 && check_mangled_names) { - pstring mangled_name; - pstrcpy(mangled_name, fname); - mangle_map(mangled_name,True,True, - conn->params); + if (!name_to_8_3(fname,mangled_name,True, + conn->params)) { + /* Error - mangle failed ! */ + memset(mangled_name,'\0',12); + } mangled_name[12] = 0; len = srvstr_push(base_data, flags2, p+2, mangled_name, 24, @@ -1638,10 +1644,11 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint16 flags2, * a Win2k client bug. JRA. */ if (!was_8_3 && check_mangled_names) { - pstring mangled_name; - pstrcpy(mangled_name, fname); - mangle_map(mangled_name,True,True, - conn->params); + if (!name_to_8_3(fname,mangled_name,True, + conn->params)) { + /* Error - mangle failed ! */ + memset(mangled_name,'\0',12); + } mangled_name[12] = 0; len = srvstr_push(base_data, flags2, p+2, mangled_name, 24, @@ -1754,7 +1761,8 @@ static void call_trans2findfirst(connection_struct *conn, BOOL close_if_end; BOOL requires_resume_key; int info_level; - pstring directory; + pstring directory_in; + char *directory = NULL; pstring mask; char *p; int last_entry_off=0; @@ -1784,7 +1792,7 @@ static void call_trans2findfirst(connection_struct *conn, requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME); info_level = SVAL(params,6); - *directory = *mask = 0; + *directory_in = *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", @@ -1819,15 +1827,15 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", return; } - srvstr_get_path_wcard(params, req->flags2, directory, - params+12, sizeof(directory), total_params - 12, + srvstr_get_path_wcard(params, req->flags2, directory_in, + params+12, sizeof(directory_in), total_params - 12, STR_TERMINATE, &ntstatus, &mask_contains_wcard); if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); return; } - ntstatus = resolve_dfspath_wcard(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, directory, &mask_contains_wcard); + ntstatus = resolve_dfspath_wcard(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, directory_in, &mask_contains_wcard); if (!NT_STATUS_IS_OK(ntstatus)) { if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -1838,11 +1846,12 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", return; } - ntstatus = unix_convert(conn, directory, True, NULL, &sbuf); + ntstatus = unix_convert(conn, directory_in, True, &directory, NULL, &sbuf); if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); return; } + ntstatus = check_name(conn, directory); if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); @@ -1858,7 +1867,11 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", } else { pstrcpy(mask,directory); } - pstrcpy(directory,"./"); + directory = talloc_strdup(talloc_tos(), "./"); + if (!directory) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } } else { pstrcpy(mask,p+1); *p = 0; @@ -2030,14 +2043,18 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd send_trans2_replies(req, params, 10, pdata, PTR_DIFF(p,pdata), max_data_bytes); - if ((! *directory) && dptr_path(dptr_num)) - slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); + if ((! *directory) && dptr_path(dptr_num)) { + directory = talloc_strdup(talloc_tos(),dptr_path(dptr_num)); + if (!directory) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + } + } DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", smb_fn_name(CVAL(req->inbuf,smb_com)), mask, directory, dirtype, numentries ) ); - /* + /* * Force a name mangle here to ensure that the * mask as an 8.3 name is top of the mangled cache. * The reasons for this are subtle. Don't remove @@ -2045,8 +2062,10 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd * (see PR#13758). JRA. */ - if(!mangle_is_8_3_wildcards( mask, False, conn->params)) - mangle_map(mask, True, True, conn->params); + if(!mangle_is_8_3_wildcards( mask, False, conn->params)) { + char mangled_name[13]; + name_to_8_3(mask, mangled_name, True, conn->params); + } return; } @@ -2270,14 +2289,20 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd long current_pos = 0; /* - * Remember, mangle_map is called by + * Remember, name_to_8_3 is called by * get_lanman2_dir_entry(), so the resume name * could be mangled. Ensure we check the unmangled name. */ if (mangle_is_mangled(resume_name, conn->params)) { - mangle_check_cache(resume_name, sizeof(resume_name)-1, - conn->params); + char *new_resume_name = NULL; + mangle_lookup_name_from_8_3(talloc_tos(), + resume_name, + &new_resume_name, + conn->params); + if (new_resume_name) { + pstrcpy(resume_name, new_resume_name); + } } /* @@ -3483,7 +3508,8 @@ static void call_trans2qfilepathinfo(connection_struct *conn, unsigned int data_size = 0; unsigned int param_size = 2; SMB_STRUCT_STAT sbuf; - pstring fname, dos_fname; + pstring dos_fname; + char *fname = NULL; char *fullpathname; char *base_name; char *p; @@ -3530,23 +3556,31 @@ static void call_trans2qfilepathinfo(connection_struct *conn, return; } - if(fsp && (fsp->fake_file_handle)) { + /* Initial check for valid fsp ptr. */ + if (!check_fsp_open(conn, req, fsp, ¤t_user)) { + return; + } + + fname = talloc_strdup(talloc_tos(),fsp->fsp_name); + if (!fname) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + + if(fsp->fake_file_handle) { /* * This is actually for the QUOTA_FAKE_FILE --metze */ - - pstrcpy(fname, fsp->fsp_name); + /* We know this name is ok, it's already passed the checks. */ - + } else if(fsp && (fsp->is_directory || fsp->fh->fd == -1)) { /* * This is actually a QFILEINFO on a directory * handle (returned from an NT SMB). NT5.0 seems * to do this call. JRA. */ - /* We know this name is ok, it's already passed the checks. */ - pstrcpy(fname, fsp->fsp_name); - + if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { @@ -3570,7 +3604,6 @@ static void call_trans2qfilepathinfo(connection_struct *conn, return; } - pstrcpy(fname, fsp->fsp_name); if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) { DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno))); reply_unixerror(req, ERRDOS, ERRbadfid); @@ -3581,7 +3614,9 @@ static void call_trans2qfilepathinfo(connection_struct *conn, delete_pending = get_delete_on_close_flag(fileid); access_mask = fsp->access_mask; } + } else { + pstring fname_in; NTSTATUS status = NT_STATUS_OK; /* qpathinfo */ @@ -3599,8 +3634,8 @@ static void call_trans2qfilepathinfo(connection_struct *conn, return; } - srvstr_get_path(params, req->flags2, fname, ¶ms[6], - sizeof(fname), total_params - 6, + srvstr_get_path(params, req->flags2, fname_in, ¶ms[6], + sizeof(fname_in), total_params - 6, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -3609,7 +3644,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, 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, @@ -3620,7 +3655,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, 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); return; @@ -3962,16 +3997,16 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_QUERY_FILE_ALT_NAME_INFO: case SMB_FILE_ALTERNATE_NAME_INFORMATION: { - pstring short_name; - + char mangled_name[13]; DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n")); - pstrcpy(short_name,base_name); - /* Mangle if not already 8.3 */ - if(!mangle_is_8_3(short_name, True, conn->params)) { - mangle_map(short_name,True,True,conn->params); + if (!name_to_8_3(base_name,mangled_name, + True,conn->params)) { + reply_nterror( + req, + NT_STATUS_NO_MEMORY); } len = srvstr_push(dstart, req->flags2, - pdata+4, short_name, + pdata+4, mangled_name, PTR_DIFF(dend, pdata+4), STR_UNICODE); data_size = 4 + len; @@ -4395,17 +4430,22 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd code. ****************************************************************************/ -NTSTATUS hardlink_internals(connection_struct *conn, pstring oldname, pstring newname) +NTSTATUS hardlink_internals(connection_struct *conn, + char *oldname_in, + char *newname_in) { SMB_STRUCT_STAT sbuf1, sbuf2; - pstring last_component_oldname; - pstring last_component_newname; + char *last_component_oldname = NULL; + char *last_component_newname = NULL; + char *oldname = NULL; + char *newname = NULL; NTSTATUS status = NT_STATUS_OK; ZERO_STRUCT(sbuf1); ZERO_STRUCT(sbuf2); - status = unix_convert(conn, oldname, False, last_component_oldname, &sbuf1); + status = unix_convert(conn, oldname_in, False, &oldname, + &last_component_oldname, &sbuf1); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -4420,7 +4460,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, pstring oldname, pstring ne return NT_STATUS_OBJECT_NAME_NOT_FOUND; } - status = unix_convert(conn, newname, False, last_component_newname, &sbuf2); + status = unix_convert(conn, newname_in, False, &newname, + &last_component_newname, &sbuf2); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -4882,13 +4923,15 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn, static NTSTATUS smb_file_rename_information(connection_struct *conn, struct smb_request *req, - const char *pdata, int total_data, - files_struct *fsp, pstring fname) + const char *pdata, + int total_data, + files_struct *fsp, + const char *fname) { BOOL overwrite; uint32 root_fid; uint32 len; - pstring newname; + pstring newname_in; pstring base_name; BOOL dest_has_wcard = False; NTSTATUS status = NT_STATUS_OK; @@ -4906,8 +4949,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - srvstr_get_path_wcard(pdata, req->flags2, newname, &pdata[12], - sizeof(newname), len, 0, &status, + srvstr_get_path_wcard(pdata, req->flags2, newname_in, &pdata[12], + sizeof(newname_in), len, 0, &status, &dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { return status; @@ -4915,13 +4958,13 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, status = resolve_dfspath_wcard(conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - newname, &dest_has_wcard); + newname_in, &dest_has_wcard); if (!NT_STATUS_IS_OK(status)) { return status; } /* Check the new name has no '/' characters. */ - if (strchr_m(newname, '/')) { + if (strchr_m(newname_in, '/')) { return NT_STATUS_NOT_SUPPORTED; } @@ -4934,16 +4977,19 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, pstrcpy(base_name, "./"); } /* Append the new name. */ - pstrcat(base_name, newname); + pstrcat(base_name, newname_in); if (fsp) { SMB_STRUCT_STAT sbuf; - pstring newname_last_component; + char *newname = NULL; + char *newname_last_component = NULL; ZERO_STRUCT(sbuf); - status = unix_convert(conn, newname, False, - newname_last_component, &sbuf); + status = unix_convert(conn, newname_in, False, + &newname, + &newname_last_component, + &sbuf); /* If an error we expect this to be * NT_STATUS_OBJECT_PATH_NOT_FOUND */ @@ -4961,7 +5007,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, overwrite); } else { DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n", - fname, newname )); + fname, base_name )); status = rename_internals(conn, req, fname, base_name, 0, overwrite, False, dest_has_wcard); } @@ -6121,7 +6167,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, char *pdata = *ppdata; uint16 info_level; SMB_STRUCT_STAT sbuf; - pstring fname; + char *fname = NULL; files_struct *fsp = NULL; NTSTATUS status = NT_STATUS_OK; int data_return_size = 0; @@ -6140,15 +6186,24 @@ static void call_trans2setfilepathinfo(connection_struct *conn, } fsp = file_fsp(SVAL(params,0)); - info_level = SVAL(params,2); + /* Basic check for non-null fsp. */ + if (!check_fsp_open(conn, req, fsp, ¤t_user)) { + return; + } + info_level = SVAL(params,2); - if(fsp && (fsp->is_directory || fsp->fh->fd == -1)) { + fname = talloc_strdup(talloc_tos(),fsp->fsp_name); + if (!fname) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + + if(fsp->is_directory || fsp->fh->fd == -1) { /* * This is actually a SETFILEINFO on a directory * handle (returned from an NT SMB). NT5.0 seems * to do this call. JRA. */ - pstrcpy(fname, fsp->fsp_name); if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { @@ -6163,7 +6218,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, return; } } - } else if (fsp && fsp->print_file) { + } else if (fsp->print_file) { /* * Doing a DELETE_ON_CLOSE should cancel a print job. */ @@ -6171,18 +6226,17 @@ static void call_trans2setfilepathinfo(connection_struct *conn, fsp->fh->private_options |= FILE_DELETE_ON_CLOSE; DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name )); - + SSVAL(params,0,0); send_trans2_replies(req, params, 2, *ppdata, 0, max_data_bytes); return; - } - else { + } else { reply_unixerror(req, ERRDOS, ERRbadpath); return; } - } else { + } else { /* * Original code - this is an open file. */ @@ -6190,8 +6244,6 @@ static void call_trans2setfilepathinfo(connection_struct *conn, return; } - pstrcpy(fname, fsp->fsp_name); - if (SMB_VFS_FSTAT(fsp, fsp->fh->fd, &sbuf) != 0) { DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); reply_unixerror(req, ERRDOS, ERRbadfid); @@ -6199,15 +6251,17 @@ static void call_trans2setfilepathinfo(connection_struct *conn, } } } else { + pstring fname_in; + /* set path info */ if (total_params < 7) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); return; } - info_level = SVAL(params,0); - srvstr_get_path(params, req->flags2, fname, ¶ms[6], - sizeof(fname), total_params - 6, STR_TERMINATE, + info_level = SVAL(params,0); + srvstr_get_path(params, req->flags2, fname_in, ¶ms[6], + sizeof(fname_in), total_params - 6, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -6216,7 +6270,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, 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, @@ -6228,7 +6282,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, 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); return; @@ -6550,7 +6604,8 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, { char *params = *pparams; char *pdata = *ppdata; - pstring directory; + pstring directory_in; + char *directory = NULL; SMB_STRUCT_STAT sbuf; NTSTATUS status = NT_STATUS_OK; struct ea_list *ea_list = NULL; @@ -6565,17 +6620,17 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, return; } - srvstr_get_path(params, req->flags2, directory, ¶ms[4], - sizeof(directory), total_params - 4, STR_TERMINATE, + srvstr_get_path(params, req->flags2, directory_in, ¶ms[4], + sizeof(directory_in), total_params - 4, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); return; } - DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); + DEBUG(3,("call_trans2mkdir : name = %s\n", directory_in)); - 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); return; -- cgit