diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/libsmb/clilist.c | 50 |
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); } |