Fix bug #5953 - smbclient crashes: cli_list_new segmentation fault.
[kai/samba.git] / source3 / libsmb / clilist.c
index 2bad3e508bb741d0be3d86b674fffc8e351fdf77..cebafc6919a0d522f38f6ca6a1704a4050746a30 100644 (file)
@@ -78,9 +78,20 @@ static size_t interpret_long_filename(TALLOC_CTX *ctx,
                        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
@@ -317,7 +328,7 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
                                       &rparam, &param_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;
@@ -326,6 +337,20 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
                        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);
@@ -377,6 +402,12 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
                                                        &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));
@@ -386,7 +417,7 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
                }
 
                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("");
@@ -442,6 +473,11 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
                                                        &finfo,
                                                        NULL,
                                                        NULL);
+                       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);
                 }
         }