The branch, v3-4-test has been updated
       via  8ac6085... Fix bug #7122 - Reading a large browselist fails (server 
returns invalid values in subsequent SMBtrans replies)
       via  026f058... Fix off-by-one error in working out the limit of the 
NetServerEnum comment.
       via  8142883... s3:smbd: use StrCaseCmp() instead of strcasecmp
       via  4e419df... s3:smbd: Fix really ugly bool vs. int bug!!!
       via  86eae5b... s3:libsmb: fix NetServerEnum3 rap calls.
       via  f37f187... s3:smbd: implement api_RNetServerEnum3
       via  2614ed6... util: added binsearch.h for binary array searches
       via  f8f6bef... s3:smbd: add/improve some DEBUG messages in 
api_RNetServerEnum2()
       via  0b6d850... s3:smbd: rename api_RNetServerEnum => api_RNetServerEnum2
      from  832fed7... Missed one check on the memcpy for bug #7063.

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-4-test


- Log -----------------------------------------------------------------
commit 8ac6085a2c7382e544888e632ff62c30f7e7a884
Author: Jeremy Allison <j...@samba.org>
Date:   Tue Feb 9 15:14:38 2010 -0800

    Fix bug #7122 - Reading a large browselist fails (server returns invalid 
values in subsequent SMBtrans replies)
    
    There are two problems:
    
    1). The server is off-by-one in the end of buffer space test.
    2). The server returns 0 in the totaldata (smb_vwv1) and totalparams 
(smb_vwv0)
    fields in the second and subsequent SMBtrans replies.
    
    This patch fixes both.
    
    Jeremy.
    (cherry picked from commit 8ddc977c1421a47bedba8d5494f7ae67692b772a)
    
    Signed-off-by: Stefan Metzmacher <me...@samba.org>

commit 026f05839b6dbdeb5be3953930a28f7650c1e1da
Author: Jeremy Allison <j...@samba.org>
Date:   Tue Feb 9 12:17:08 2010 -0800

    Fix off-by-one error in working out the limit of the NetServerEnum comment.
    
    Jeremy.
    (cherry picked from commit 9ad6f432f3f5844b4b419e7cbaf3c3e70b052d29)
    
    Signed-off-by: Stefan Metzmacher <me...@samba.org>

commit 8142883b40819b5cb92ea671bb6c89bff68d3680
Author: Stefan Metzmacher <me...@samba.org>
Date:   Tue Feb 9 18:58:36 2010 +0100

    s3:smbd: use StrCaseCmp() instead of strcasecmp
    
    metze
    (cherry picked from commit bc8242a08e1bb9489cc8171b1ec02bd2518b1857)

commit 4e419df9154c329b3376ab00d6bb55093fbfe71a
Author: Stefan Metzmacher <me...@samba.org>
Date:   Tue Feb 9 18:54:41 2010 +0100

    s3:smbd: Fix really ugly bool vs. int bug!!!
    
    A comparison function for qsort needs to return an 'int'!
    Otherwise you'll get random results depending on the compiler
    and the architecture...
    
    metze
    (cherry picked from commit 1686a5e7e7eb1b411b003cbbde5c0d28741c6d02)

commit 86eae5b4862735309313e1800be44dab2641b393
Author: Stefan Metzmacher <me...@samba.org>
Date:   Mon Feb 8 18:38:03 2010 +0100

    s3:libsmb: fix NetServerEnum3 rap calls.
    
    metze
    (cherry picked from commit 9b5198dd443a00fdad4faa1f9cdabedd81012d93)

commit f37f187070934e1046ce05d298d92ede7e6f7030
Author: Stefan Metzmacher <me...@samba.org>
Date:   Mon Feb 8 19:07:45 2010 +0100

    s3:smbd: implement api_RNetServerEnum3
    
    This is needed to support large browse lists.
    
    metze
    (cherry picked from commit 30eec0656c926d3d85a438dc28f17649b53318f8)

commit 2614ed62c8ca281d95151913ed591a86409e0566
Author: Andrew Tridgell <tri...@samba.org>
Date:   Thu Dec 10 14:35:24 2009 +1100

    util: added binsearch.h for binary array searches
    
    This was moved from the schema_query code. It will now be used in more
    than one place, so best to make it a library macro. I think there are
    quite a few places that could benefit from this.
    (cherry picked from commit 71943e8858943718affb6a3c0ded2127f07057f0)
    
    Signed-off-by: Stefan Metzmacher <me...@samba.org>
    (cherry picked from commit 448b8f35d7a7cff73d35304673302178f593c9d0)
    
    Signed-off-by: Stefan Metzmacher <me...@samba.org>

commit f8f6beff57fd58b69648633f5b1c15289015f96b
Author: Stefan Metzmacher <me...@samba.org>
Date:   Mon Feb 8 18:45:18 2010 +0100

    s3:smbd: add/improve some DEBUG messages in api_RNetServerEnum2()
    
    metze
    (cherry picked from commit 495ac4616654c9e62e14031b7439aff21e42ec91)

commit 0b6d850a553c0a558d579ab5e46f49794a015e34
Author: Stefan Metzmacher <me...@samba.org>
Date:   Fri Feb 5 16:55:15 2010 +0100

    s3:smbd: rename api_RNetServerEnum => api_RNetServerEnum2
    
    metze
    (cherry picked from commit dc58672c6588a1715698721153b35ed2d594bc67)

-----------------------------------------------------------------------

Summary of changes:
 lib/util/binsearch.h    |   68 ++++++++++++++
 source3/libsmb/clirap.c |   26 ++++-
 source3/smbd/ipc.c      |    3 +
 source3/smbd/lanman.c   |  234 ++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 314 insertions(+), 17 deletions(-)
 create mode 100644 lib/util/binsearch.h


Changeset truncated at 500 lines:

diff --git a/lib/util/binsearch.h b/lib/util/binsearch.h
new file mode 100644
index 0000000..ac83990
--- /dev/null
+++ b/lib/util/binsearch.h
@@ -0,0 +1,68 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   a generic binary search macro
+
+   Copyright (C) Andrew Tridgell 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _BINSEARCH_H
+#define _BINSEARCH_H
+
+/* a binary array search, where the array is an array of pointers to 
structures,
+   and we want to find a match for 'target' on 'field' in those structures.
+
+   Inputs:
+      array:          base pointer to an array of structures
+      arrray_size:    number of elements in the array
+      field:          the name of the field in the structure we are keying off
+      target:         the field value we are looking for
+      comparison_fn:  the comparison function
+      result:         where the result of the search is put
+
+   if the element is found, then 'result' is set to point to the found array 
element. If not,
+   then 'result' is set to NULL.
+
+   The array is assumed to be sorted by the same comparison_fn as the
+   search (with, for example, qsort)
+ */
+#define BINARY_ARRAY_SEARCH_P(array, array_size, field, target, comparison_fn, 
result) do { \
+       int32_t _b, _e; \
+       (result) = NULL; \
+       if (array_size) { for (_b = 0, _e = (array_size)-1; _b <= _e; ) { \
+               int32_t _i = (_b+_e)/2; \
+               int _r = comparison_fn(target, array[_i]->field); \
+               if (_r == 0) { (result) = array[_i]; break; } \
+               if (_r < 0) _e = _i - 1; else _b = _i + 1; \
+       }} } while (0)
+
+/*
+  like BINARY_ARRAY_SEARCH_P, but assumes that the array is an array
+  of structures, rather than pointers to structures
+
+  result points to the found structure, or NULL
+ */
+#define BINARY_ARRAY_SEARCH(array, array_size, field, target, comparison_fn, 
result) do { \
+       int32_t _b, _e; \
+       (result) = NULL; \
+       if (array_size) { for (_b = 0, _e = (array_size)-1; _b <= _e; ) {       
\
+               int32_t _i = (_b+_e)/2; \
+               int _r = comparison_fn(target, array[_i].field); \
+               if (_r == 0) { (result) = &array[_i]; break; } \
+               if (_r < 0) _e = _i - 1; else _b = _i + 1; \
+       }} } while (0)
+
+#endif
diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c
index 9705cac..2abb550 100644
--- a/source3/libsmb/clirap.c
+++ b/source3/libsmb/clirap.c
@@ -247,11 +247,9 @@ bool cli_NetServerEnum(struct cli_state *cli, char 
*workgroup, uint32 stype,
                p = param;
                SIVAL(p,0,func); /* api number */
                p += 2;
-               /* Next time through we need to use the continue api */
-               func = RAP_NetServerEnum3;
 
-               if (last_entry) {
-                       strlcpy(p,"WrLehDOz", sizeof(param)-PTR_DIFF(p,param));
+               if (func == RAP_NetServerEnum3) {
+                       strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
                } else {
                        strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
                }
@@ -270,7 +268,7 @@ bool cli_NetServerEnum(struct cli_state *cli, char 
*workgroup, uint32 stype,
                 * to continue from.
                 */
                len = push_ascii(p,
-                               last_entry ? last_entry : workgroup,
+                               workgroup,
                                sizeof(param) - PTR_DIFF(p,param) - 1,
                                STR_TERMINATE|STR_UPPER);
 
@@ -280,6 +278,22 @@ bool cli_NetServerEnum(struct cli_state *cli, char 
*workgroup, uint32 stype,
                }
                p += len;
 
+               if (func == RAP_NetServerEnum3) {
+                       len = push_ascii(p,
+                                       last_entry ? last_entry : "",
+                                       sizeof(param) - PTR_DIFF(p,param) - 1,
+                                       STR_TERMINATE);
+
+                       if (len == (size_t)-1) {
+                               SAFE_FREE(last_entry);
+                               return false;
+                       }
+                       p += len;
+               }
+
+               /* Next time through we need to use the continue api */
+               func = RAP_NetServerEnum3;
+
                if (!cli_api(cli,
                        param, PTR_DIFF(p,param), 8, /* params, length, max */
                        NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
@@ -352,7 +366,7 @@ bool cli_NetServerEnum(struct cli_state *cli, char 
*workgroup, uint32 stype,
                                comment_offset = (IVAL(p,22) & 
0xFFFF)-converter;
                                cmnt = comment_offset?(rdata+comment_offset):"";
 
-                               if (comment_offset < 0 || comment_offset > 
(int)rdrcnt) {
+                               if (comment_offset < 0 || comment_offset >= 
(int)rdrcnt) {
                                        TALLOC_FREE(frame);
                                        continue;
                                }
diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c
index 5fd756e..2cf0038 100644
--- a/source3/smbd/ipc.c
+++ b/source3/smbd/ipc.c
@@ -170,6 +170,9 @@ void send_trans_reply(connection_struct *conn,
                                           rparam, tot_param_sent, this_lparam,
                                           rdata, tot_data_sent, this_ldata);
 
+               SSVAL(req->outbuf,smb_vwv0,lparam);
+               SSVAL(req->outbuf,smb_vwv1,ldata);
+
                SSVAL(req->outbuf,smb_vwv3,this_lparam);
                SSVAL(req->outbuf,smb_vwv4,
                      smb_offset(smb_buf(req->outbuf)+1,req->outbuf));
diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c
index b15e685..40b6aca 100644
--- a/source3/smbd/lanman.c
+++ b/source3/smbd/lanman.c
@@ -26,6 +26,7 @@
    */
 
 #include "includes.h"
+#include "../lib/util/binsearch.h"
 
 #ifdef CHECK_TYPES
 #undef CHECK_TYPES
@@ -1352,9 +1353,9 @@ static int fill_srv_info(struct srv_info_struct *service,
 }
 
 
-static bool srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
+static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
 {
-       return(strcmp(s1->name,s2->name));
+       return StrCaseCmp(s1->name,s2->name);
 }
 
 /****************************************************************************
@@ -1362,7 +1363,7 @@ static bool srv_comp(struct srv_info_struct *s1,struct 
srv_info_struct *s2)
  extracted from lists saved by nmbd on the local host.
 ****************************************************************************/
 
-static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
+static bool api_RNetServerEnum2(connection_struct *conn, uint16 vuid,
                                char *param, int tpscnt,
                                char *data, int tdscnt,
                                int mdrcnt, int mprcnt, char **rdata, 
@@ -1431,6 +1432,8 @@ static bool api_RNetServerEnum(connection_struct *conn, 
uint16 vuid,
                fstrcpy(domain, lp_workgroup());
        }
 
+       DEBUG(4, ("domain [%s]\n", domain));
+
        if (lp_browse_list()) {
                total = get_server_info(servertype,&servers,domain);
        }
@@ -1453,10 +1456,10 @@ static bool api_RNetServerEnum(connection_struct *conn, 
uint16 vuid,
                        }
                        lastname = s->name;
                        data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
-                       DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
-                               s->name, s->type, s->comment, s->domain));
+                       DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
+                               i, s->name, s->type, s->comment, s->domain));
 
-                       if (data_len <= buf_len) {
+                       if (data_len < buf_len) {
                                counted++;
                                fixed_len += f_len;
                                string_len += s_len;
@@ -1489,8 +1492,8 @@ static bool api_RNetServerEnum(connection_struct *conn, 
uint16 vuid,
                        }
                        lastname = s->name;
                        fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
-                       DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
-                               s->name, s->type, s->comment, s->domain));
+                       DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
+                               i, s->name, s->type, s->comment, s->domain));
                        count2--;
                }
        }
@@ -1507,12 +1510,220 @@ static bool api_RNetServerEnum(connection_struct 
*conn, uint16 vuid,
 
        SAFE_FREE(servers);
 
-       DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
+       DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n",
                domain,uLevel,counted,counted+missed));
 
        return True;
 }
 
+static int srv_name_match(const char *n1, const char *n2)
+{
+       /*
+        * [MS-RAP] footnote <88> for Section 3.2.5.15 says:
+        *
+        *  In Windows, FirstNameToReturn need not be an exact match:
+        *  the server will return a list of servers that exist on
+        *  the network greater than or equal to the FirstNameToReturn.
+        */
+       int ret = StrCaseCmp(n1, n2);
+
+       if (ret <= 0) {
+               return 0;
+       }
+
+       return ret;
+}
+
+static bool api_RNetServerEnum3(connection_struct *conn, uint16 vuid,
+                               char *param, int tpscnt,
+                               char *data, int tdscnt,
+                               int mdrcnt, int mprcnt, char **rdata,
+                               char **rparam, int *rdata_len, int *rparam_len)
+{
+       char *str1 = get_safe_str_ptr(param, tpscnt, param, 2);
+       char *str2 = skip_string(param,tpscnt,str1);
+       char *p = skip_string(param,tpscnt,str2);
+       int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1);
+       int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0);
+       uint32 servertype = get_safe_IVAL(param,tpscnt,p,4, 0);
+       char *p2;
+       int data_len, fixed_len, string_len;
+       int f_len = 0, s_len = 0;
+       struct srv_info_struct *servers=NULL;
+       int counted=0,first=0,total=0;
+       int i,missed;
+       fstring domain;
+       fstring first_name;
+       bool domain_request;
+       bool local_request;
+
+       if (!str1 || !str2 || !p) {
+               return False;
+       }
+
+       /* If someone sets all the bits they don't really mean to set
+          DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
+          known servers. */
+
+       if (servertype == SV_TYPE_ALL) {
+               servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
+       }
+
+       /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
+          any other bit (they may just set this bit on its own) they
+          want all the locally seen servers. However this bit can be
+          set on its own so set the requested servers to be
+          ALL - DOMAIN_ENUM. */
+
+       if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & 
SV_TYPE_DOMAIN_ENUM)) {
+               servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
+       }
+
+       domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
+       local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
+
+       p += 8;
+
+       if (strcmp(str1, "WrLehDzz") != 0) {
+               return false;
+       }
+       if (!check_server_info(uLevel,str2)) {
+               return False;
+       }
+
+       DEBUG(4, ("server request level: %s %8x ", str2, servertype));
+       DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
+       DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
+
+       if (skip_string(param,tpscnt,p) == NULL) {
+               return False;
+       }
+       pull_ascii_fstring(domain, p);
+       if (domain[0] == '\0') {
+               fstrcpy(domain, lp_workgroup());
+       }
+       p = skip_string(param,tpscnt,p);
+       if (skip_string(param,tpscnt,p) == NULL) {
+               return False;
+       }
+       pull_ascii_fstring(first_name, p);
+
+       DEBUG(4, ("domain: '%s' first_name: '%s'\n",
+                 domain, first_name));
+
+       if (lp_browse_list()) {
+               total = get_server_info(servertype,&servers,domain);
+       }
+
+       data_len = fixed_len = string_len = 0;
+       missed = 0;
+
+       if (total > 0) {
+               qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
+       }
+
+       if (first_name[0] != '\0') {
+               struct srv_info_struct *first_server = NULL;
+
+               BINARY_ARRAY_SEARCH(servers, total, name, first_name,
+                                   srv_name_match, first_server);
+               if (first_server) {
+                       first = PTR_DIFF(first_server, servers) / 
sizeof(*servers);
+                       /*
+                        * The binary search may not find the exact match
+                        * so we need to search backward to find the first match
+                        *
+                        * This implements the strange matching windows
+                        * implements. (see the comment in srv_name_match().
+                        */
+                       for (;first > 0;) {
+                               int ret;
+                               ret = StrCaseCmp(first_name,
+                                                servers[first-1].name);
+                               if (ret > 0) {
+                                       break;
+                               }
+                               first--;
+                       }
+               } else {
+                       /* we should return no entries */
+                       first = total;
+               }
+       }
+
+       {
+               char *lastname=NULL;
+
+               for (i=first;i<total;i++) {
+                       struct srv_info_struct *s = &servers[i];
+
+                       if (lastname && strequal(lastname,s->name)) {
+                               continue;
+                       }
+                       lastname = s->name;
+                       data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
+                       DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
+                               i, s->name, s->type, s->comment, s->domain));
+
+                       if (data_len < buf_len) {
+                               counted++;
+                               fixed_len += f_len;
+                               string_len += s_len;
+                       } else {
+                               missed++;
+                       }
+               }
+       }
+
+       *rdata_len = fixed_len + string_len;
+       *rdata = smb_realloc_limit(*rdata,*rdata_len);
+       if (!*rdata) {
+               return False;
+       }
+
+       p2 = (*rdata) + fixed_len;      /* auxilliary data (strings) will go 
here */
+       p = *rdata;
+       f_len = fixed_len;
+       s_len = string_len;
+
+       {
+               char *lastname=NULL;
+               int count2 = counted;
+
+               for (i = first; i < total && count2;i++) {
+                       struct srv_info_struct *s = &servers[i];
+
+                       if (lastname && strequal(lastname,s->name)) {
+                               continue;
+                       }
+                       lastname = s->name;
+                       fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
+                       DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n",
+                               i, s->name, s->type, s->comment, s->domain));
+                       count2--;
+               }
+       }
+
+       *rparam_len = 8;
+       *rparam = smb_realloc_limit(*rparam,*rparam_len);
+       if (!*rparam) {
+               return False;
+       }
+       SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
+       SSVAL(*rparam,2,0);
+       SSVAL(*rparam,4,counted);
+       SSVAL(*rparam,6,counted+missed);
+
+       DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] 
counted=%d total=%d\n",
+               domain,uLevel,first,first_name,
+               first < total ? servers[first].name : "",
+               counted,counted+missed));
+
+       SAFE_FREE(servers);
+
+       return True;
+}
+
 /****************************************************************************
   command 0x34 - suspected of being a "Lookup Names" stub api
   ****************************************************************************/
@@ -1819,7 +2030,7 @@ static bool api_RNetShareEnum( connection_struct *conn, 
uint16 vuid,
                if( lp_browseable( i ) && lp_snum_ok( i ) && 
(strlen(servicename_dos) < 13)) {
                        total++;
                        data_len += 
fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0);
-                       if (data_len <= buf_len) {
+                       if (data_len < buf_len) {
                                counted++;
                                fixed_len += f_len;
                                string_len += s_len;
@@ -4628,7 +4839,8 @@ static const struct {
        {"WPrintDestGetInfo",   RAP_WPrintDestGetInfo,  api_WPrintDestGetInfo},
        {"NetRemoteTOD",        RAP_NetRemoteTOD,       api_NetRemoteTOD},
        {"WPrintQueuePurge",    RAP_WPrintQPurge,       api_WPrintQueueCtrl},
-       {"NetServerEnum",       RAP_NetServerEnum2,     api_RNetServerEnum}, /* 
anon OK */
+       {"NetServerEnum2",      RAP_NetServerEnum2,     api_RNetServerEnum2}, 
/* anon OK */
+       {"NetServerEnum3",      RAP_NetServerEnum3,     api_RNetServerEnum3}, 
/* anon OK */
        {"WAccessGetUserPerms",RAP_WAccessGetUserPerms,api_WAccessGetUserPerms},
        {"SetUserPassword",     RAP_WUserPasswordSet2,  api_SetUserPassword},
        {"WWkstaUserLogon",     RAP_WWkstaUserLogon,    api_WWkstaUserLogon},


-- 
Samba Shared Repository

Reply via email to