Index: libsmb/clilist.c =================================================================== --- libsmb/clilist.c (revision 7146) +++ libsmb/clilist.c (working copy) @@ -31,16 +31,20 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ mnt = cli_cm_get_mntpoint( cli ); for (p=dirlist,i=0;i