#include "includes.h"
-extern file_info def_finfo;
-
/****************************************************************************
Calculate a safe next_entry_offset.
****************************************************************************/
by NT and 2 is used by OS/2
****************************************************************************/
-static size_t interpret_long_filename(struct cli_state *cli,
+static size_t interpret_long_filename(TALLOC_CTX *ctx,
+ struct cli_state *cli,
int level,
const char *p,
const char *pdata_end,
uint32 *p_resume_key,
DATA_BLOB *p_last_name_raw)
{
- file_info finfo2;
int len;
+ size_t ret;
const char *base = p;
data_blob_free(p_last_name_raw);
- if (!finfo) {
- finfo = &finfo2;
- }
-
if (p_resume_key) {
*p_resume_key = 0;
}
- memcpy(finfo,&def_finfo,sizeof(*finfo));
+ ZERO_STRUCTP(finfo);
finfo->cli = cli;
switch (level) {
len = CVAL(p, 26);
p += 27;
p += clistr_align_in(cli, p, 0);
- if (p + len + 2 > pdata_end) {
+
+ /* We can safely use +1 here (which is required by OS/2)
+ * instead of +2 as the STR_TERMINATE flag below is
+ * actually used as the length calculation.
+ * The len+2 is merely an upper bound.
+ * Due to the explicit 2 byte null termination
+ * in cli_receive_trans/cli_receive_nt_trans
+ * we know this is safe. JRA + kukks
+ */
+
+ if (p + len + 1 > pdata_end) {
return pdata_end - base;
}
+
/* the len+2 below looks strange but it is
important to cope with the differences
between win2000 and win9x for this call
(tridge) */
- p += clistr_pull(cli, finfo->name, p,
- sizeof(finfo->name),
- len+2,
- STR_TERMINATE);
+ ret = clistr_pull_talloc(ctx,
+ cli,
+ &finfo->name,
+ p,
+ len+2,
+ STR_TERMINATE);
+ if (ret == (size_t)-1) {
+ return pdata_end - base;
+ }
+ p += ret;
return PTR_DIFF(p, base);
case 2: /* this is what OS/2 uses mostly */
if (p + len + 1 > pdata_end) {
return pdata_end - base;
}
- p += clistr_pull(cli, finfo->name, p,
- sizeof(finfo->name),
- len,
- STR_NOALIGN);
+ ret = clistr_pull_talloc(ctx,
+ cli,
+ &finfo->name,
+ p,
+ len,
+ STR_NOALIGN);
+ if (ret == (size_t)-1) {
+ return pdata_end - base;
+ }
+ p += ret;
return PTR_DIFF(p, base) + 1;
case 260: /* NT uses this, but also accepts 2 */
if (p + namelen < p || p + namelen > pdata_end) {
return pdata_end - base;
}
- clistr_pull(cli, finfo->name, p,
- sizeof(finfo->name),
- namelen, 0);
+ ret = clistr_pull_talloc(ctx,
+ cli,
+ &finfo->name,
+ p,
+ namelen,
+ 0);
+ if (ret == (size_t)-1) {
+ return pdata_end - base;
+ }
/* To be robust in the face of unicode conversion failures
we need to copy the raw bytes of the last name seen here.
char *rparam=NULL, *rdata=NULL;
unsigned int param_len, data_len;
uint16 setup;
- char param[1024];
+ char *param;
const char *mnt;
uint32 resume_key = 0;
+ TALLOC_CTX *frame = talloc_stackframe();
DATA_BLOB last_name_raw = data_blob(NULL, 0);
/* NT uses 260, OS/2 uses 2. Both accept 1. */
mask = SMB_STRDUP(Mask);
if (!mask) {
+ TALLOC_FREE(frame);
return -1;
}
while (ff_eos == 0) {
+ size_t nlen = 2*(strlen(mask)+1);
+
loop_count++;
if (loop_count > 200) {
DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
break;
}
+ param = SMB_MALLOC_ARRAY(char, 12+nlen+last_name_raw.length+2);
+ if (!param) {
+ break;
+ }
+
if (First) {
setup = TRANSACT2_FINDFIRST;
SSVAL(param,0,attribute); /* attribute */
SSVAL(param,6,info_level);
SIVAL(param,8,0);
p = param+12;
- p += clistr_push(cli, param+12, mask, sizeof(param)-12,
- STR_TERMINATE);
+ p += clistr_push(cli, param+12, mask,
+ nlen, STR_TERMINATE);
} else {
setup = TRANSACT2_FINDNEXT;
SSVAL(param,0,ff_dir_handle);
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;
- if (last_name_raw.length && (last_name_raw.length < (sizeof(param)-12))) {
+ if (last_name_raw.length) {
memcpy(p, last_name_raw.data, last_name_raw.length);
p += last_name_raw.length;
} else {
- p += clistr_push(cli, param+12, mask, sizeof(param)-12, STR_TERMINATE);
+ p += clistr_push(cli, param+12, mask,
+ nlen, STR_TERMINATE);
}
}
cli->max_xmit /* data, length, max. */
#endif
)) {
+ SAFE_FREE(param);
+ TALLOC_FREE(frame);
break;
}
+ SAFE_FREE(param);
+
if (!cli_receive_trans(cli, SMBtrans2,
&rparam, ¶m_len,
&rdata, &data_len) &&
cli_is_dos_error(cli)) {
- /* we need to work around a Win95 bug - sometimes
+ /* We need to work around a Win95 bug - sometimes
it gives ERRSRV/ERRerror temprarily */
uint8 eclass;
uint32 ecode;
SAFE_FREE(rparam);
cli_dos_error(cli, &eclass, &ecode);
+
+ /*
+ * OS/2 might return "no more files",
+ * which just tells us, that searchcount is zero
+ * in this search.
+ * Guenter Kukkukk <linux@kukkukk.com>
+ */
+
+ if (eclass == ERRDOS && ecode == ERRnofiles) {
+ ff_searchcount = 0;
+ cli_reset_error(cli);
+ break;
+ }
+
if (eclass != ERRSRV || ecode != ERRerror)
break;
smb_msleep(100);
/* Last entry - fixup the last offset length. */
SIVAL(p2,0,PTR_DIFF((rdata + data_len),p2));
}
- p2 += interpret_long_filename(cli,
+ p2 += interpret_long_filename(frame,
+ cli,
info_level,
p2,
rdata_end,
&resume_key,
&last_name_raw);
+ if (!finfo.name) {
+ DEBUG(0,("cli_list_new: Error: unable to parse name from info level %d\n",
+ info_level));
+ ff_eos = 1;
+ break;
+ }
if (!First && *mask && strcsequal(finfo.name, mask)) {
DEBUG(0,("Error: Looping in FIND_NEXT as name %s has already been seen?\n",
finfo.name));
}
SAFE_FREE(mask);
- if (ff_searchcount > 0) {
+ if (ff_searchcount > 0 && ff_eos == 0 && finfo.name) {
mask = SMB_STRDUP(finfo.name);
} else {
mask = SMB_STRDUP("");
/* no connection problem. let user function add each entry */
rdata_end = dirlist + dirlist_len;
for (p=dirlist,i=0;i<total_received;i++) {
- p += interpret_long_filename(cli,
+ p += interpret_long_filename(frame,
+ cli,
info_level,
p,
rdata_end,
&finfo,
NULL,
NULL);
- fn( mnt,&finfo, Mask, state );
+ if (!finfo.name) {
+ DEBUG(0,("cli_list_new: unable to parse name from info level %d\n",
+ info_level));
+ break;
+ }
+ fn(mnt,&finfo, Mask, state);
}
}
SAFE_FREE(dirlist);
data_blob_free(&last_name_raw);
SAFE_FREE(mask);
+ TALLOC_FREE(frame);
return(total_received);
}
The length of the structure is returned.
****************************************************************************/
-static int interpret_short_filename(struct cli_state *cli, char *p,file_info *finfo)
+static bool interpret_short_filename(TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ char *p,
+ file_info *finfo)
{
-
- *finfo = def_finfo;
+ size_t ret;
+ ZERO_STRUCTP(finfo);
finfo->cli = cli;
finfo->mode = CVAL(p,21);
finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
finfo->size = IVAL(p,26);
- clistr_pull(cli, finfo->name, p+30, sizeof(finfo->name), 12, STR_ASCII);
- if (strcmp(finfo->name, "..") && strcmp(finfo->name, ".")) {
- strncpy(finfo->short_name,finfo->name, sizeof(finfo->short_name)-1);
- finfo->short_name[sizeof(finfo->short_name)-1] = '\0';
+ ret = clistr_pull_talloc(ctx,
+ cli,
+ &finfo->name,
+ p+30,
+ 12,
+ STR_ASCII);
+ if (ret == (size_t)-1) {
+ return false;
}
+ if (finfo->name) {
+ strlcpy(finfo->short_name,
+ finfo->name,
+ sizeof(finfo->short_name));
+ }
+ return true;
return(DIR_STRUCT_SIZE);
}
-
/****************************************************************************
Do a directory listing, calling fn on each file found.
this uses the old SMBsearch interface. It is needed for testing Samba,
int i;
char *dirlist = NULL;
char *mask = NULL;
+ TALLOC_CTX *frame = NULL;
ZERO_ARRAY(status);
memset(cli->outbuf,'\0',smb_size);
memset(cli->inbuf,'\0',smb_size);
- set_message(cli->outbuf,2,0,True);
+ cli_set_message(cli->outbuf,2,0,True);
SCVAL(cli->outbuf,smb_com,SMBsearch);
p = smb_buf(cli->outbuf);
*p++ = 4;
- p += clistr_push(cli, p, first?mask:"", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, first?mask:"",
+ cli->bufsize - PTR_DIFF(p,cli->outbuf),
+ STR_TERMINATE);
*p++ = 5;
if (first) {
SSVAL(p,0,0);
received = SVAL(cli->inbuf,smb_vwv0);
if (received <= 0) break;
+ /* Ensure we received enough data. */
+ if ((cli->inbuf+4+smb_len(cli->inbuf) - (smb_buf(cli->inbuf)+3)) <
+ received*DIR_STRUCT_SIZE) {
+ break;
+ }
+
first = False;
dirlist = (char *)SMB_REALLOC(
memset(cli->outbuf,'\0',smb_size);
memset(cli->inbuf,'\0',smb_size);
- set_message(cli->outbuf,2,0,True);
+ cli_set_message(cli->outbuf,2,0,True);
SCVAL(cli->outbuf,smb_com,SMBfclose);
SSVAL(cli->outbuf,smb_tid,cli->cnum);
cli_setup_packet(cli);
}
}
+ frame = talloc_stackframe();
for (p=dirlist,i=0;i<num_received;i++) {
file_info finfo;
- p += interpret_short_filename(cli, p,&finfo);
+ if (!interpret_short_filename(frame, cli, p, &finfo)) {
+ break;
+ }
+ p += DIR_STRUCT_SIZE;
fn("\\", &finfo, Mask, state);
}
+ TALLOC_FREE(frame);
SAFE_FREE(mask);
SAFE_FREE(dirlist);