summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2005-05-31 19:06:52 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 10:57:03 -0500
commit57fa7e154737df74a6a4fd9b2e3cf29917bd5ff0 (patch)
tree3d0b76cea37a413a5120c4a13e37b5f717f9b0b7
parent583b7ed6595e85e8366632dd0ab5dbfcdc1838e6 (diff)
downloadsamba-57fa7e154737df74a6a4fd9b2e3cf29917bd5ff0.tar.gz
samba-57fa7e154737df74a6a4fd9b2e3cf29917bd5ff0.tar.bz2
samba-57fa7e154737df74a6a4fd9b2e3cf29917bd5ff0.zip
r7151: Fix for bug #2698. If a unicode to unix charset conversion fails (due to buggy iconv?) we can
be left with a filename that doesn't exist on the remote machine. If we then do a findnext with this file the server gets confused and restarts from the beginning of the directory, causing directory listing loops. Fix this by keeping a copy of the "raw" filename data and length and using this as the argument to findnext. This won't fix the incorrect iconv conversion into the finfo struct but at least it ensures that directory listings always terminate. Tested against NTFS and FAT directories. Jeremy. (This used to be commit 848940d5a91b310e58d0631ead293418ea4186f0)
-rw-r--r--source3/libsmb/clilist.c50
1 files changed, 40 insertions, 10 deletions
diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c
index 892a457255..a1434338c9 100644
--- a/source3/libsmb/clilist.c
+++ b/source3/libsmb/clilist.c
@@ -31,16 +31,20 @@ extern file_info def_finfo;
by NT and 2 is used by OS/2
****************************************************************************/
-static size_t interpret_long_filename(struct cli_state *cli,
- int level,char *p,file_info *finfo, uint32 *p_resume_key)
+static size_t interpret_long_filename(struct cli_state *cli, int level,char *p,file_info *finfo,
+ uint32 *p_resume_key, DATA_BLOB *p_last_name_raw, uint32 *p_last_name_raw_len)
{
file_info finfo2;
int len;
char *base = p;
- if (!finfo) finfo = &finfo2;
+ if (!finfo) {
+ finfo = &finfo2;
+ }
- *p_resume_key = 0;
+ if (p_resume_key) {
+ *p_resume_key = 0;
+ }
memcpy(finfo,&def_finfo,sizeof(*finfo));
switch (level) {
@@ -87,7 +91,9 @@ static size_t interpret_long_filename(struct cli_state *cli,
size_t namelen, slen;
p += 4; /* next entry offset */
- *p_resume_key = IVAL(p,0);
+ if (p_resume_key) {
+ *p_resume_key = IVAL(p,0);
+ }
p += 4; /* fileindex */
/* these dates appear to arrive in a
@@ -134,6 +140,22 @@ static size_t interpret_long_filename(struct cli_state *cli,
clistr_pull(cli, finfo->name, p,
sizeof(finfo->name),
namelen, 0);
+
+ /* To be robust in the face of unicode conversion failures
+ we need to copy the raw bytes of the last name seen here.
+ Namelen doesn't include the terminating unicode null, so
+ copy it here. */
+
+ if (p_last_name_raw && p_last_name_raw_len) {
+ if (namelen + 2 > p_last_name_raw->length) {
+ memset(p_last_name_raw->data, '\0', sizeof(p_last_name_raw->length));
+ *p_last_name_raw_len = 0;
+ } else {
+ memcpy(p_last_name_raw->data, p, namelen);
+ SSVAL(p_last_name_raw->data, namelen, 0);
+ *p_last_name_raw_len = namelen + 2;
+ }
+ }
return (size_t)IVAL(base, 0);
}
}
@@ -174,6 +196,8 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
pstring param;
const char *mnt;
uint32 resume_key = 0;
+ uint32 last_name_raw_len = 0;
+ DATA_BLOB last_name_raw = data_blob(NULL, 2*sizeof(pstring));
/* NT uses 260, OS/2 uses 2. Both accept 1. */
info_level = (cli->capabilities&CAP_NT_SMBS)?260:1;
@@ -215,8 +239,12 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
can miss filenames. Use last filename continue instead. JRA */
SSVAL(param,10,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END)); /* resume required + close on end */
p = param+12;
- p += clistr_push(cli, param+12, mask, sizeof(param)-12,
- STR_TERMINATE);
+ if (last_name_raw_len && (last_name_raw_len < (sizeof(param)-12))) {
+ memcpy(p, last_name_raw.data, last_name_raw_len);
+ p += last_name_raw_len;
+ } else {
+ p += clistr_push(cli, param+12, mask, sizeof(param)-12, STR_TERMINATE);
+ }
}
param_len = PTR_DIFF(p, param);
@@ -283,7 +311,8 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
/* Last entry - fixup the last offset length. */
SIVAL(p2,0,PTR_DIFF((rdata + data_len),p2));
}
- p2 += interpret_long_filename(cli,info_level,p2,&finfo,&resume_key);
+ p2 += interpret_long_filename(cli,info_level,p2,&finfo,
+ &resume_key,&last_name_raw,&last_name_raw_len);
}
if (ff_lastname > 0) {
@@ -323,12 +352,13 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
mnt = cli_cm_get_mntpoint( cli );
for (p=dirlist,i=0;i<total_received;i++) {
- p += interpret_long_filename(cli,info_level,p,&finfo,&resume_key);
+ p += interpret_long_filename(cli,info_level,p,&finfo,NULL,NULL,NULL);
fn( mnt,&finfo, Mask, state );
}
- /* free up the dirlist buffer */
+ /* free up the dirlist buffer and last name raw blob */
SAFE_FREE(dirlist);
+ data_blob_free(&last_name_raw);
return(total_received);
}