Remove more uses of "extern struct current_user current_user;".
[ira/wip.git] / source3 / smbd / lanman.c
index d6c76c54c137fdf1e3199d8c838964b05537a5a6..4c15f133aec0cab39fe34ffa384c98eacfa30398 100644 (file)
@@ -6,17 +6,17 @@
 
    SMB Version handling
    Copyright (C) John H Terpstra 1995-1998
-   
+
    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/>.
    */
    */
 
 #include "includes.h"
-
-extern struct current_user current_user;
-extern userdom_struct current_user_info;
+#include "smbd/globals.h"
+#include "../librpc/gen_ndr/cli_samr.h"
+#include "../librpc/gen_ndr/srv_samr.h"
+#include "../lib/util/binsearch.h"
 
 #ifdef CHECK_TYPES
 #undef CHECK_TYPES
@@ -103,9 +104,9 @@ static int CopyExpanded(connection_struct *conn,
                                lp_servicename(SNUM(conn)),
                                conn->server_info->unix_name,
                                conn->connectpath,
-                               conn->server_info->gid,
-                               get_current_username(),
-                               current_user_info.domain,
+                               conn->server_info->utok.gid,
+                               conn->server_info->sanitized_username,
+                               pdb_get_domain(conn->server_info->sam_account),
                                buf);
        if (!buf) {
                *p_space_remaining = 0;
@@ -154,9 +155,9 @@ static int StrlenExpanded(connection_struct *conn, int snum, char *s)
                                lp_servicename(SNUM(conn)),
                                conn->server_info->unix_name,
                                conn->connectpath,
-                               conn->server_info->gid,
-                               get_current_username(),
-                               current_user_info.domain,
+                               conn->server_info->utok.gid,
+                               conn->server_info->sanitized_username,
+                               pdb_get_domain(conn->server_info->sam_account),
                                buf);
        if (!buf) {
                return 0;
@@ -184,9 +185,9 @@ static char *Expand(connection_struct *conn, int snum, char *s)
                                lp_servicename(SNUM(conn)),
                                conn->server_info->unix_name,
                                conn->connectpath,
-                               conn->server_info->gid,
-                               get_current_username(),
-                               current_user_info.domain,
+                               conn->server_info->utok.gid,
+                               conn->server_info->sanitized_username,
+                               pdb_get_domain(conn->server_info->sam_account),
                                buf);
 }
 
@@ -648,18 +649,16 @@ static void fill_printq_info_52(connection_struct *conn, int snum,
 {
        int                             i;
        fstring                         location;
-       NT_PRINTER_DRIVER_INFO_LEVEL    driver;
+       struct spoolss_DriverInfo8 *driver = NULL;
        NT_PRINTER_INFO_LEVEL           *printer = NULL;
 
-       ZERO_STRUCT(driver);
-
        if ( !W_ERROR_IS_OK(get_a_printer( NULL, &printer, 2, lp_servicename(snum))) ) {
                DEBUG(3,("fill_printq_info_52: Failed to lookup printer [%s]\n", 
                        lp_servicename(snum)));
                goto err;
        }
 
-       if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, 
+       if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
                "Windows 4.0", 0)) )
        {
                DEBUG(3,("fill_printq_info_52: Failed to lookup driver [%s]\n", 
@@ -667,38 +666,38 @@ static void fill_printq_info_52(connection_struct *conn, int snum,
                goto err;
        }
 
-       trim_string(driver.info_3->driverpath, "\\print$\\WIN40\\0\\", 0);
-       trim_string(driver.info_3->datafile, "\\print$\\WIN40\\0\\", 0);
-       trim_string(driver.info_3->helpfile, "\\print$\\WIN40\\0\\", 0);
+       trim_string((char *)driver->driver_path, "\\print$\\WIN40\\0\\", 0);
+       trim_string((char *)driver->data_file, "\\print$\\WIN40\\0\\", 0);
+       trim_string((char *)driver->help_file, "\\print$\\WIN40\\0\\", 0);
 
        PACKI(desc, "W", 0x0400);                     /* don't know */
-       PACKS(desc, "z", driver.info_3->name);        /* long printer name */
-       PACKS(desc, "z", driver.info_3->driverpath);  /* Driverfile Name */
-       PACKS(desc, "z", driver.info_3->datafile);    /* Datafile name */
-       PACKS(desc, "z", driver.info_3->monitorname); /* language monitor */
+       PACKS(desc, "z", driver->driver_name);        /* long printer name */
+       PACKS(desc, "z", driver->driver_path);  /* Driverfile Name */
+       PACKS(desc, "z", driver->data_file);    /* Datafile name */
+       PACKS(desc, "z", driver->monitor_name); /* language monitor */
 
        fstrcpy(location, "\\\\%L\\print$\\WIN40\\0");
        standard_sub_basic( "", "", location, sizeof(location)-1 );
        PACKS(desc,"z", location);                          /* share to retrieve files */
 
-       PACKS(desc,"z", driver.info_3->defaultdatatype);    /* default data type */
-       PACKS(desc,"z", driver.info_3->helpfile);           /* helpfile name */
-       PACKS(desc,"z", driver.info_3->driverpath);               /* driver name */
+       PACKS(desc,"z", driver->default_datatype);    /* default data type */
+       PACKS(desc,"z", driver->help_file);           /* helpfile name */
+       PACKS(desc,"z", driver->driver_path);               /* driver name */
 
-       DEBUG(3,("Printer Driver Name: %s:\n",driver.info_3->name));
-       DEBUG(3,("Driver: %s:\n",driver.info_3->driverpath));
-       DEBUG(3,("Data File: %s:\n",driver.info_3->datafile));
-       DEBUG(3,("Language Monitor: %s:\n",driver.info_3->monitorname));
+       DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name));
+       DEBUG(3,("Driver: %s:\n",driver->driver_path));
+       DEBUG(3,("Data File: %s:\n",driver->data_file));
+       DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name));
        DEBUG(3,("Driver Location: %s:\n",location));
-       DEBUG(3,("Data Type: %s:\n",driver.info_3->defaultdatatype));
-       DEBUG(3,("Help File: %s:\n",driver.info_3->helpfile));
+       DEBUG(3,("Data Type: %s:\n",driver->default_datatype));
+       DEBUG(3,("Help File: %s:\n",driver->help_file));
        PACKI(desc,"N",count);                     /* number of files to copy */
 
-       for ( i=0; i<count && driver.info_3->dependentfiles && *driver.info_3->dependentfiles[i]; i++) 
+       for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++)
        {
-               trim_string(driver.info_3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
-               PACKS(desc,"z",driver.info_3->dependentfiles[i]);         /* driver files to copy */
-               DEBUG(3,("Dependent File: %s:\n",driver.info_3->dependentfiles[i]));
+               trim_string((char *)driver->dependent_files[i], "\\print$\\WIN40\\0\\", 0);
+               PACKS(desc,"z",driver->dependent_files[i]);         /* driver files to copy */
+               DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i]));
        }
 
        /* sanity check */
@@ -719,8 +718,7 @@ done:
        if ( printer )
                free_a_printer( &printer, 2 );
 
-       if ( driver.info_3 )
-               free_a_printer_driver( driver, 3 );
+       free_a_printer_driver(driver);
 }
 
 
@@ -809,7 +807,7 @@ static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
 static int get_printerdrivernumber(int snum)
 {
        int                             result = 0;
-       NT_PRINTER_DRIVER_INFO_LEVEL    driver;
+       struct spoolss_DriverInfo8 *driver;
        NT_PRINTER_INFO_LEVEL           *printer = NULL;
 
        ZERO_STRUCT(driver);
@@ -820,7 +818,7 @@ static int get_printerdrivernumber(int snum)
                goto done;
        }
 
-       if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, 
+       if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, printer->info_2->drivername,
                "Windows 4.0", 0)) )
        {
                DEBUG(3,("get_printerdrivernumber: Failed to lookup driver [%s]\n", 
@@ -829,15 +827,13 @@ static int get_printerdrivernumber(int snum)
        }
 
        /* count the number of files */
-       while ( driver.info_3->dependentfiles && *driver.info_3->dependentfiles[result] )
-                       result++;
-                       \
+       while (driver->dependent_files && *driver->dependent_files[result])
+               result++;
  done:
        if ( printer )
                free_a_printer( &printer, 2 );
 
-       if ( driver.info_3 )
-               free_a_printer_driver( driver, 3 );
+       free_a_printer_driver(driver);
 
        return result;
 }
@@ -879,9 +875,9 @@ static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
        /* remove any trailing username */
        if ((p = strchr_m(QueueName,'%')))
                *p = 0;
+
        DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName));
+
        /* check it's a supported varient */
        if (!prefix_ok(str1,"zWrLh"))
                return False;
@@ -902,11 +898,11 @@ static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
                SSVAL(*rparam,4,0);
                return(True);
        }
+
        snum = find_service(QueueName);
        if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
                return False;
-               
+
        if (uLevel==52) {
                count = get_printerdrivernumber(snum);
                DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
@@ -937,7 +933,7 @@ static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
        }
 
        *rdata_len = desc.usedlen;
-  
+
        /*
         * We must set the return code to ERRbuftoosmall
         * in order to support lanman style printing with Win NT/2k
@@ -945,7 +941,7 @@ static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
         */
        if (!mdrcnt && lp_disable_spoolss())
                desc.errcode = ERRbuftoosmall;
+
        *rdata_len = desc.usedlen;
        *rparam_len = 6;
        *rparam = smb_realloc_limit(*rparam,*rparam_len);
@@ -957,7 +953,7 @@ static bool api_DosPrintQGetInfo(connection_struct *conn, uint16 vuid,
        SSVALS(*rparam,0,desc.errcode);
        SSVAL(*rparam,2,0);
        SSVAL(*rparam,4,desc.neededlen);
-  
+
        DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode));
 
        SAFE_FREE(queue);
@@ -989,7 +985,7 @@ static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
        print_status_struct *status = NULL;
        int *subcntarr = NULL;
        int queuecnt = 0, subcnt = 0, succnt = 0;
+
        if (!param_format || !output_format1 || !p) {
                return False;
        }
@@ -997,7 +993,7 @@ static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
        memset((char *)&desc,'\0',sizeof(desc));
 
        DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
+
        if (!prefix_ok(param_format,"WrLeh")) {
                return False;
        }
@@ -1074,7 +1070,7 @@ static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
        }
 
        SAFE_FREE(subcntarr);
+
        *rdata_len = desc.usedlen;
        *rparam_len = 8;
        *rparam = smb_realloc_limit(*rparam,*rparam_len);
@@ -1085,7 +1081,7 @@ static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
        SSVAL(*rparam,2,0);
        SSVAL(*rparam,4,succnt);
        SSVAL(*rparam,6,queuecnt);
-  
+
        for (i = 0; i < queuecnt; i++) {
                if (queue) {
                        SAFE_FREE(queue[i]);
@@ -1094,7 +1090,7 @@ static bool api_DosPrintQEnum(connection_struct *conn, uint16 vuid,
 
        SAFE_FREE(queue);
        SAFE_FREE(status);
-  
+
        return True;
 
   err:
@@ -1157,9 +1153,9 @@ static int get_server_info(uint32 servertype,
        bool local_list_only;
        int i;
 
-       lines = file_lines_load(lock_path(SERVER_LIST), NULL, 0);
+       lines = file_lines_load(cache_path(SERVER_LIST), NULL, 0, NULL);
        if (!lines) {
-               DEBUG(4,("Can't open %s - %s\n",lock_path(SERVER_LIST),strerror(errno)));
+               DEBUG(4,("Can't open %s - %s\n",cache_path(SERVER_LIST),strerror(errno)));
                return 0;
        }
 
@@ -1189,7 +1185,7 @@ static int get_server_info(uint32 servertype,
                        *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced);
                        if (!*servers) {
                                DEBUG(0,("get_server_info: failed to enlarge servers info struct!\n"));
-                               file_lines_free(lines);
+                               TALLOC_FREE(lines);
                                return 0;
                        }
                        memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count));
@@ -1217,6 +1213,7 @@ static int get_server_info(uint32 servertype,
                        continue;
                }
                fstrcpy(s->comment, p);
+               string_truncate(s->comment, MAX_SERVER_STRING_LENGTH);
 
                s->domain[0] = '\0';
                if (!next_token_talloc(frame,&ptr,&p, NULL)) {
@@ -1251,11 +1248,11 @@ static int get_server_info(uint32 servertype,
                        DEBUG(4,("s: dom mismatch "));
                        ok = False;
                }
-    
+
                if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) {
                        ok = False;
                }
-    
+
                /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
                s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
 
@@ -1269,8 +1266,8 @@ static int get_server_info(uint32 servertype,
                                s->name, s->type, s->comment, s->domain));
                }
        }
-  
-       file_lines_free(lines);
+
+       TALLOC_FREE(lines);
        return count;
 }
 
@@ -1287,7 +1284,7 @@ static int fill_srv_info(struct srv_info_struct *service,
        char* p2;
        int l2;
        int len;
+
        switch (uLevel) {
                case 0:
                        struct_len = 16;
@@ -1298,7 +1295,7 @@ static int fill_srv_info(struct srv_info_struct *service,
                default:
                        return -1;
        }
+
        if (!buf) {
                len = 0;
                switch (uLevel) {
@@ -1311,7 +1308,7 @@ static int fill_srv_info(struct srv_info_struct *service,
                *stringspace = len;
                return struct_len + len;
        }
-  
+
        len = struct_len;
        p = *buf;
        if (*buflen < struct_len) {
@@ -1327,7 +1324,7 @@ static int fill_srv_info(struct srv_info_struct *service,
        if (!baseaddr) {
                baseaddr = p;
        }
-  
+
        switch (uLevel) {
                case 0:
                        push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE);
@@ -1354,9 +1351,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);
 }
 
 /****************************************************************************
@@ -1364,7 +1361,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, 
@@ -1419,7 +1416,7 @@ static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
        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)));
@@ -1433,6 +1430,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);
        }
@@ -1440,9 +1439,7 @@ static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
        data_len = fixed_len = string_len = 0;
        missed = 0;
 
-       if (total > 0) {
-               qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
-       }
+       TYPESAFE_QSORT(servers, total, srv_comp);
 
        {
                char *lastname=NULL;
@@ -1455,10 +1452,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));
-      
-                       if (data_len <= buf_len) {
+                       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;
@@ -1473,7 +1470,7 @@ static bool api_RNetServerEnum(connection_struct *conn, uint16 vuid,
        if (!*rdata) {
                return False;
        }
-  
+
        p2 = (*rdata) + fixed_len;      /* auxilliary data (strings) will go here */
        p = *rdata;
        f_len = fixed_len;
@@ -1491,12 +1488,12 @@ 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--;
                }
        }
-  
+
        *rparam_len = 8;
        *rparam = smb_realloc_limit(*rparam,*rparam_len);
        if (!*rparam) {
@@ -1509,12 +1506,218 @@ 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;
+
+       TYPESAFE_QSORT(servers, total, 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
   ****************************************************************************/
@@ -1543,9 +1746,9 @@ static bool api_RNetGroupGetUsers(connection_struct *conn, uint16 vuid,
        if (!prefix_ok(str1,"zWrLeh")) {
                return False;
        }
-  
+
        *rdata_len = 0;
-  
+
        *rparam_len = 8;
        *rparam = smb_realloc_limit(*rparam,*rparam_len);
        if (!*rparam) {
@@ -1573,7 +1776,9 @@ static bool check_share_info(int uLevel, char* id)
                        }
                        break;
                case 1:
-                       if (strcmp(id,"B13BWz") != 0) {
+                       /* Level-2 descriptor is allowed (and ignored) */
+                       if (strcmp(id,"B13BWz") != 0 &&
+                           strcmp(id,"B13BWzWWWzB9B") != 0) {
                                return False;
                        }
                        break;
@@ -1602,7 +1807,7 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel,
        char* p2;
        int l2;
        int len;
+
        switch( uLevel ) {
                case 0:
                        struct_len = 13;
@@ -1619,8 +1824,7 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel,
                default:
                        return -1;
        }
-  
+
        if (!buf) {
                len = 0;
 
@@ -1638,7 +1842,7 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel,
                }
                return struct_len + len;
        }
-  
+
        len = struct_len;
        p = *buf;
        if ((*buflen) < struct_len) {
@@ -1656,9 +1860,9 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel,
        if (!baseaddr) {
                baseaddr = p;
        }
-  
+
        push_ascii(p,lp_servicename(snum),13, STR_TERMINATE);
-  
+
        if (uLevel > 0) {
                int type;
 
@@ -1674,7 +1878,7 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel,
                SIVAL(p,16,PTR_DIFF(p2,baseaddr));
                len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
        }
-  
+
        if (uLevel > 1) {
                SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */
                SSVALS(p,22,-1);                /* max uses */
@@ -1683,7 +1887,7 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel,
                len += CopyAndAdvance(&p2,lp_pathname(snum),&l2);
                memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */
        }
-  
+
        if (uLevel > 2) {
                memset(p+40,0,SHPWLEN+2);
                SSVAL(p,50,0);
@@ -1694,7 +1898,7 @@ static int fill_share_info(connection_struct *conn, int snum, int uLevel,
                SSVAL(p,64,0);
                SSVAL(p,66,0);
        }
-       
+
        if (stringbuf) {
                (*buf) = p + struct_len;
                (*buflen) -= struct_len;
@@ -1721,7 +1925,7 @@ static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
        char *p = skip_string(param,tpscnt,netname);
        int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
        int snum;
-  
+
        if (!str1 || !str2 || !netname || !p) {
                return False;
        }
@@ -1730,7 +1934,7 @@ static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
        if (snum < 0) {
                return False;
        }
-  
+
        /* check it's a supported varient */
        if (!prefix_ok(str1,"zWrLh")) {
                return False;
@@ -1738,7 +1942,7 @@ static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
        if (!check_share_info(uLevel,str2)) {
                return False;
        }
+
        *rdata = smb_realloc_limit(*rdata,mdrcnt);
        if (!*rdata) {
                return False;
@@ -1748,7 +1952,7 @@ static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
        if (*rdata_len < 0) {
                return False;
        }
+
        *rparam_len = 6;
        *rparam = smb_realloc_limit(*rparam,*rparam_len);
        if (!*rparam) {
@@ -1757,7 +1961,7 @@ static bool api_RNetShareGetInfo(connection_struct *conn,uint16 vuid,
        SSVAL(*rparam,0,NERR_Success);
        SSVAL(*rparam,2,0);             /* converter word */
        SSVAL(*rparam,4,*rdata_len);
+
        return True;
 }
 
@@ -1793,7 +1997,7 @@ static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
        int i;
        int data_len, fixed_len, string_len;
        int f_len = 0, s_len = 0;
+
        if (!str1 || !str2 || !p) {
                return False;
        }
@@ -1804,7 +2008,7 @@ static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
        if (!check_share_info(uLevel,str2)) {
                return False;
        }
-  
+
        /* Ensure all the usershares are loaded. */
        become_root();
        load_registry_shares();
@@ -1822,7 +2026,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;
@@ -1837,7 +2041,7 @@ static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
        if (!*rdata) {
                return False;
        }
+
        p2 = (*rdata) + fixed_len;      /* auxiliary data (strings) will go here */
        p = *rdata;
        f_len = fixed_len;
@@ -1856,7 +2060,7 @@ static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
                        }
                }
        }
-  
+
        *rparam_len = 8;
        *rparam = smb_realloc_limit(*rparam,*rparam_len);
        if (!*rparam) {
@@ -1866,7 +2070,7 @@ static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid,
        SSVAL(*rparam,2,0);
        SSVAL(*rparam,4,counted);
        SSVAL(*rparam,6,total);
-  
+
        DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n",
                counted,total,uLevel,
                buf_len,*rdata_len,mdrcnt));
@@ -2007,7 +2211,7 @@ static bool api_RNetShareAdd(connection_struct *conn,uint16 vuid,
        SSVAL(*rparam,2,0);             /* converter word */
        SSVAL(*rparam,4,*rdata_len);
        *rdata_len = 0;
-  
+
        return True;
 
   error_exit:
@@ -2041,11 +2245,12 @@ static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
        char *str2 = skip_string(param,tpscnt,str1);
        char *p = skip_string(param,tpscnt,str2);
 
-       struct pdb_search *search;
-       struct samr_displayentry *entries;
+       uint32_t num_groups;
+       uint32_t resume_handle;
+       struct rpc_pipe_client *samr_pipe;
+       struct policy_handle samr_handle, domain_handle;
+       NTSTATUS status;
 
-       int num_entries;
        if (!str1 || !str2 || !p) {
                return False;
        }
@@ -2066,14 +2271,31 @@ static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
                return False;
        }
 
-       /* get list of domain groups SID_DOMAIN_GRP=2 */
-       become_root();
-       search = pdb_search_groups();
-       unbecome_root();
+       status = rpc_pipe_open_internal(
+               talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
+               conn->server_info, &samr_pipe);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
+                         nt_errstr(status)));
+               return false;
+       }
 
-       if (search == NULL) {
-               DEBUG(3,("api_RNetGroupEnum:failed to get group list"));
-               return False;
+       status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
+                                     SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
+                         nt_errstr(status)));
+               return false;
+       }
+
+       status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
+                                       SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
+                                       get_global_sam_sid(), &domain_handle);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
+                         nt_errstr(status)));
+               rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
+               return false;
        }
 
        resume_context = get_safe_SVAL(param,tpscnt,p,0,-1);
@@ -2081,11 +2303,6 @@ static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
        DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: "
                  "%d\n", resume_context, cli_buf_size));
 
-       become_root();
-       num_entries = pdb_search_entries(search, resume_context, 0xffffffff,
-                                        &entries);
-       unbecome_root();
-
        *rdata_len = cli_buf_size;
        *rdata = smb_realloc_limit(*rdata,*rdata_len);
        if (!*rdata) {
@@ -2094,25 +2311,63 @@ static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
 
        p = *rdata;
 
-       for(i=0; i<num_entries; i++) {
-               fstring name;
-               fstrcpy(name, entries[i].account_name);
-               if( ((PTR_DIFF(p,*rdata)+21) <= *rdata_len) ) {
+       errflags = NERR_Success;
+       num_groups = 0;
+       resume_handle = 0;
+
+       while (true) {
+               struct samr_SamArray *sam_entries;
+               uint32_t num_entries;
+
+               status = rpccli_samr_EnumDomainGroups(samr_pipe, talloc_tos(),
+                                                     &domain_handle,
+                                                     &resume_handle,
+                                                     &sam_entries, 1,
+                                                     &num_entries);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
+                                  "%s\n", nt_errstr(status)));
+                       break;
+               }
+
+               if (num_entries == 0) {
+                       DEBUG(10, ("rpccli_samr_EnumDomainGroups returned "
+                                  "no entries -- done\n"));
+                       break;
+               }
+
+               for(i=0; i<num_entries; i++) {
+                       const char *name;
+
+                       name = sam_entries->entries[i].name.string;
+
+                       if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) {
+                               /* set overflow error */
+                               DEBUG(3,("overflow on entry %d group %s\n", i,
+                                        name));
+                               errflags=234;
+                               break;
+                       }
+
                        /* truncate the name at 21 chars. */
-                       memcpy(p, name, 21); 
+                       memset(p, 0, 21);
+                       strlcpy(p, name, 21);
                        DEBUG(10,("adding entry %d group %s\n", i, p));
                        p += 21;
-                       p += 5; /* Both NT4 and W2k3SP1 do padding here.
-                                  No idea why... */
-               } else {
-                       /* set overflow error */
-                       DEBUG(3,("overflow on entry %d group %s\n", i, name));
-                       errflags=234;
+                       p += 5; /* Both NT4 and W2k3SP1 do padding here.  No
+                                * idea why... */
+                       num_groups += 1;
+               }
+
+               if (errflags != NERR_Success) {
                        break;
                }
+
+               TALLOC_FREE(sam_entries);
        }
 
-       pdb_search_destroy(search);
+       rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
+       rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
 
        *rdata_len = PTR_DIFF(p,*rdata);
 
@@ -2123,8 +2378,8 @@ static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid,
        }
        SSVAL(*rparam, 0, errflags);
        SSVAL(*rparam, 2, 0);           /* converter word */
-       SSVAL(*rparam, 4, i);   /* is this right?? */
-       SSVAL(*rparam, 6, resume_context+num_entries);  /* is this right?? */
+       SSVAL(*rparam, 4, num_groups);  /* is this right?? */
+       SSVAL(*rparam, 6, resume_context+num_groups);   /* is this right?? */
 
        return(True);
 }
@@ -2147,17 +2402,17 @@ static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
        int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1);
        const char *level_string;
        int count=0;
-       struct samu *sampw = NULL;
        bool ret = False;
-       DOM_SID *sids;
-       gid_t *gids;
-       size_t num_groups;
-       size_t i;
-       NTSTATUS result;
-       DOM_SID user_sid;
-       enum lsa_SidType type;
+       uint32_t i;
        char *endp = NULL;
-       TALLOC_CTX *mem_ctx;
+
+       struct rpc_pipe_client *samr_pipe;
+       struct policy_handle samr_handle, domain_handle, user_handle;
+       struct lsa_String name;
+       struct lsa_Strings names;
+       struct samr_Ids type, rid;
+       struct samr_RidWithAttributeArray *rids;
+       NTSTATUS status;
 
        if (!str1 || !str2 || !UserName || !p) {
                return False;
@@ -2197,59 +2452,75 @@ static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
        p = *rdata;
        endp = *rdata + *rdata_len;
 
-       mem_ctx = talloc_new(NULL);
-       if (mem_ctx == NULL) {
-               DEBUG(0, ("talloc_new failed\n"));
-               return False;
+       status = rpc_pipe_open_internal(
+               talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
+               conn->server_info, &samr_pipe);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
+                         nt_errstr(status)));
+               return false;
        }
 
-       if ( !(sampw = samu_new(mem_ctx)) ) {
-               DEBUG(0, ("samu_new() failed!\n"));
-               TALLOC_FREE(mem_ctx);
-               return False;
+       status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
+                                     SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
+                         nt_errstr(status)));
+               return false;
        }
 
-       /* Lookup the user information; This should only be one of
-          our accounts (not remote domains) */
+       status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
+                                       SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+                                       get_global_sam_sid(), &domain_handle);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
+                         nt_errstr(status)));
+               goto close_sam;
+       }
 
-       become_root();                                  /* ROOT BLOCK */
+       name.string = UserName;
 
-       if (!lookup_name(mem_ctx, UserName, LOOKUP_NAME_ALL,
-                        NULL, NULL, &user_sid, &type)) {
-               DEBUG(10, ("lookup_name(%s) failed\n", UserName));
-               goto done;
+       status = rpccli_samr_LookupNames(samr_pipe, talloc_tos(),
+                                        &domain_handle, 1, &name,
+                                        &rid, &type);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
+                         nt_errstr(status)));
+               goto close_domain;
        }
 
-       if (type != SID_NAME_USER) {
+       if (type.ids[0] != SID_NAME_USER) {
                DEBUG(10, ("%s is a %s, not a user\n", UserName,
-                          sid_type_lookup(type)));
-               goto done;
+                          sid_type_lookup(type.ids[0])));
+               goto close_domain;
        }
 
-       if ( !pdb_getsampwsid(sampw, &user_sid) ) {
-               DEBUG(10, ("pdb_getsampwsid(%s) failed for user %s\n",
-                          sid_string_dbg(&user_sid), UserName));
-               goto done;
+       status = rpccli_samr_OpenUser(samr_pipe, talloc_tos(),
+                                     &domain_handle,
+                                     SAMR_USER_ACCESS_GET_GROUPS,
+                                     rid.ids[0], &user_handle);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
+                         nt_errstr(status)));
+               goto close_domain;
        }
 
-       gids = NULL;
-       sids = NULL;
-       num_groups = 0;
-
-       result = pdb_enum_group_memberships(mem_ctx, sampw,
-                                           &sids, &gids, &num_groups);
-
-       if (!NT_STATUS_IS_OK(result)) {
-               DEBUG(10, ("pdb_enum_group_memberships failed for %s\n",
-                          UserName));
-               goto done;
+       status = rpccli_samr_GetGroupsForUser(samr_pipe, talloc_tos(),
+                                             &user_handle, &rids);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n",
+                         nt_errstr(status)));
+               goto close_user;
        }
 
-       for (i=0; i<num_groups; i++) {
-               const char *grp_name;
+       for (i=0; i<rids->count; i++) {
 
-               if ( lookup_sid(mem_ctx, &sids[i], NULL, &grp_name, NULL) ) {
-                       strlcpy(p, grp_name, PTR_DIFF(endp,p));
+               status = rpccli_samr_LookupRids(samr_pipe, talloc_tos(),
+                                               &domain_handle,
+                                               1, &rids->rids[i].rid,
+                                               &names, &type);
+               if (NT_STATUS_IS_OK(status) && (names.count == 1)) {
+                       strlcpy(p, names.names[0].string, PTR_DIFF(endp,p));
                        p += 21;
                        count++;
                }
@@ -2262,10 +2533,12 @@ static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid,
 
        ret = True;
 
-done:
-       unbecome_root();                                /* END ROOT BLOCK */
-
-       TALLOC_FREE(mem_ctx);
+ close_user:
+       rpccli_samr_Close(samr_pipe, talloc_tos(), &user_handle);
+ close_domain:
+       rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
+ close_sam:
+       rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
 
        return ret;
 }
@@ -2285,8 +2558,11 @@ static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
        int num_users=0;
        int errflags=0;
        int i, resume_context, cli_buf_size;
-       struct pdb_search *search;
-       struct samr_displayentry *users;
+       uint32_t resume_handle;
+
+       struct rpc_pipe_client *samr_pipe;
+       struct policy_handle samr_handle, domain_handle;
+       NTSTATUS status;
 
        char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
        char *str2 = skip_string(param,tpscnt,str1);
@@ -2331,40 +2607,89 @@ static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid,
        p = *rdata;
        endp = *rdata + *rdata_len;
 
-       become_root();
-       search = pdb_search_users(ACB_NORMAL);
-       unbecome_root();
-       if (search == NULL) {
-               DEBUG(0, ("api_RNetUserEnum:unable to open sam database.\n"));
-               return False;
+       status = rpc_pipe_open_internal(
+               talloc_tos(), &ndr_table_samr.syntax_id, rpc_samr_dispatch,
+               conn->server_info, &samr_pipe);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n",
+                         nt_errstr(status)));
+               return false;
        }
 
-       become_root();
-       num_users = pdb_search_entries(search, resume_context, 0xffffffff,
-                                      &users);
-       unbecome_root();
+       status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(),
+                                     SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n",
+                         nt_errstr(status)));
+               return false;
+       }
+
+       status = rpccli_samr_OpenDomain(samr_pipe, talloc_tos(), &samr_handle,
+                                       SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS,
+                                       get_global_sam_sid(), &domain_handle);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n",
+                         nt_errstr(status)));
+               rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
+               return false;
+       }
 
        errflags=NERR_Success;
 
-       for (i=0; i<num_users; i++) {
-               const char *name = users[i].account_name;
+       resume_handle = 0;
 
-               if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)&&(strlen(name)<=21)) {
-                       strlcpy(p,name,PTR_DIFF(endp,p));
-                       DEBUG(10,("api_RNetUserEnum:adding entry %d username "
-                                 "%s\n",count_sent,p));
-                       p += 21;
-                       count_sent++;
-               } else {
-                       /* set overflow error */
-                       DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
-                                 "username %s\n",count_sent,name));
-                       errflags=234;
+       while (true) {
+               struct samr_SamArray *sam_entries;
+               uint32_t num_entries;
+
+               status = rpccli_samr_EnumDomainUsers(samr_pipe, talloc_tos(),
+                                                    &domain_handle,
+                                                    &resume_handle,
+                                                    0, &sam_entries, 1,
+                                                    &num_entries);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
+                                  "%s\n", nt_errstr(status)));
+                       break;
+               }
+
+               if (num_entries == 0) {
+                       DEBUG(10, ("rpccli_samr_EnumDomainUsers returned "
+                                  "no entries -- done\n"));
+                       break;
+               }
+
+               for (i=0; i<num_entries; i++) {
+                       const char *name;
+
+                       name = sam_entries->entries[i].name.string;
+
+                       if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len)
+                          &&(strlen(name)<=21)) {
+                               strlcpy(p,name,PTR_DIFF(endp,p));
+                               DEBUG(10,("api_RNetUserEnum:adding entry %d "
+                                         "username %s\n",count_sent,p));
+                               p += 21;
+                               count_sent++;
+                       } else {
+                               /* set overflow error */
+                               DEBUG(10,("api_RNetUserEnum:overflow on entry %d "
+                                         "username %s\n",count_sent,name));
+                               errflags=234;
+                               break;
+                       }
+               }
+
+               if (errflags != NERR_Success) {
                        break;
                }
+
+               TALLOC_FREE(sam_entries);
        }
 
-       pdb_search_destroy(search);
+       rpccli_samr_Close(samr_pipe, talloc_tos(), &domain_handle);
+       rpccli_samr_Close(samr_pipe, talloc_tos(), &samr_handle);
 
        *rdata_len = PTR_DIFF(p,*rdata);
 
@@ -2500,7 +2825,7 @@ static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
         */
 
        {
-               auth_serversupplied_info *server_info = NULL;
+               struct auth_serversupplied_info *server_info = NULL;
                DATA_BLOB password = data_blob(pass1, strlen(pass1)+1);
 
                if (NT_STATUS_IS_OK(check_plaintext_password(user,password,&server_info))) {
@@ -2541,7 +2866,7 @@ static bool api_SetUserPassword(connection_struct *conn,uint16 vuid,
 
        memset((char *)pass1,'\0',sizeof(fstring));
        memset((char *)pass2,'\0',sizeof(fstring));      
-        
+
        return(True);
 }
 
@@ -2556,6 +2881,7 @@ static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
                                char **rdata,char **rparam,
                                int *rdata_len,int *rparam_len)
 {
+       struct smbd_server_connection *sconn = smbd_server_conn;
        fstring user;
        char *p = get_safe_str_ptr(param,tpscnt,param,2);
        *rparam_len = 2;
@@ -2613,7 +2939,7 @@ static bool api_SamOEMChangePassword(connection_struct *conn,uint16 vuid,
         * function.
         */
 
-       (void)map_username(user);
+       (void)map_username(sconn, user);
 
        if (NT_STATUS_IS_OK(pass_oem_change(user, (uchar*) data, (uchar *)&data[516], NULL, NULL, NULL))) {
                SSVAL(*rparam,0,NERR_Success);
@@ -2680,25 +3006,25 @@ static bool api_RDosPrintJobDel(connection_struct *conn,uint16 vuid,
        }
 
        errcode = NERR_notsupported;
-       
+
        switch (function) {
        case 81:                /* delete */ 
-               if (print_job_delete(&current_user, snum, jobid, &werr)) 
+               if (print_job_delete(conn->server_info, snum, jobid, &werr))
                        errcode = NERR_Success;
                break;
        case 82:                /* pause */
-               if (print_job_pause(&current_user, snum, jobid, &werr)) 
+               if (print_job_pause(conn->server_info, snum, jobid, &werr))
                        errcode = NERR_Success;
                break;
        case 83:                /* resume */
-               if (print_job_resume(&current_user, snum, jobid, &werr)) 
+               if (print_job_resume(conn->server_info, snum, jobid, &werr))
                        errcode = NERR_Success;
                break;
        }
 
        if (!W_ERROR_IS_OK(werr))
                errcode = W_ERROR_V(werr);
-       
+
  out:
        SSVAL(*rparam,0,errcode);       
        SSVAL(*rparam,2,0);             /* converter word */
@@ -2752,17 +3078,20 @@ static bool api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid,
 
        switch (function) {
        case 74: /* Pause queue */
-               if (print_queue_pause(&current_user, snum, &werr)) errcode = NERR_Success;
+               werr = print_queue_pause(conn->server_info, snum);
                break;
        case 75: /* Resume queue */
-               if (print_queue_resume(&current_user, snum, &werr)) errcode = NERR_Success;
+               werr = print_queue_resume(conn->server_info, snum);
                break;
        case 103: /* Purge */
-               if (print_queue_purge(&current_user, snum, &werr)) errcode = NERR_Success;
+               werr = print_queue_purge(conn->server_info, snum);
+               break;
+       default:
+               werr = WERR_NOT_SUPPORTED;
                break;
        }
 
-       if (!W_ERROR_IS_OK(werr)) errcode = W_ERROR_V(werr);
+       errcode = W_ERROR_V(werr);
 
  out:
        SSVAL(*rparam,0,errcode);
@@ -2842,9 +3171,9 @@ static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
                         sharename));
                return False;
        }
-  
+
        *rdata_len = 0;
-       
+
        /* check it's a supported varient */
        if ((strcmp(str1,"WWsTP")) || 
            (!check_printjob_info(&desc,uLevel,str2)))
@@ -2881,7 +3210,7 @@ static bool api_PrintJobInfo(connection_struct *conn, uint16 vuid,
  out:
        SSVALS(*rparam,0,errcode);
        SSVAL(*rparam,2,0);             /* converter word */
-       
+
        return(True);
 }
 
@@ -3005,14 +3334,15 @@ static bool api_RNetServerGetInfo(connection_struct *conn,uint16 vuid,
                        SIVAL(p,6,0);
                } else {
                        SIVAL(p,6,PTR_DIFF(p2,*rdata));
-                       comment = talloc_sub_advanced(ctx,
-                                               lp_servicename(SNUM(conn)),
-                                               conn->server_info->unix_name,
-                                               conn->connectpath,
-                                               conn->server_info->gid,
-                                               get_current_username(),
-                                               current_user_info.domain,
-                                               comment);
+                       comment = talloc_sub_advanced(
+                               ctx,
+                               lp_servicename(SNUM(conn)),
+                               conn->server_info->unix_name,
+                               conn->connectpath,
+                               conn->server_info->utok.gid,
+                               conn->server_info->sanitized_username,
+                               pdb_get_domain(conn->server_info->sam_account),
+                               comment);
                        if (comment) {
                                return false;
                        }
@@ -3111,7 +3441,7 @@ static bool api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid,
        p += 4;
 
        SIVAL(p,0,PTR_DIFF(p2,*rdata));
-       strlcpy(p2,current_user_info.smb_name,PTR_DIFF(endp,p2));
+       strlcpy(p2,conn->server_info->sanitized_username,PTR_DIFF(endp,p2));
        p2 = skip_string(*rdata,*rdata_len,p2);
        if (!p2) {
                return False;
@@ -3331,6 +3661,7 @@ static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
                                char **rdata,char **rparam,
                                int *rdata_len,int *rparam_len)
 {
+       struct smbd_server_connection *sconn = smbd_server_conn;
        char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
        char *str2 = skip_string(param,tpscnt,str1);
        char *UserName = skip_string(param,tpscnt,str2);
@@ -3343,10 +3674,10 @@ static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
        /* get NIS home of a previously validated user - simeon */
        /* With share level security vuid will always be zero.
           Don't depend on vuser being non-null !!. JRA */
-       user_struct *vuser = get_valid_user_struct(vuid);
+       user_struct *vuser = get_valid_user_struct(sconn, vuid);
        if(vuser != NULL) {
                DEBUG(3,("  Username of UID %d is %s\n",
-                        (int)vuser->server_info->uid,
+                        (int)vuser->server_info->utok.uid,
                         vuser->server_info->unix_name));
        }
 
@@ -3436,7 +3767,9 @@ static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
                                vuser->server_info->sam_account);
                }
                /* modelled after NTAS 3.51 reply */
-               SSVAL(p,usri11_priv,conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER); 
+               SSVAL(p,usri11_priv,
+                       (get_current_uid(conn) == (uid_t)0)?
+                       USER_PRIV_ADMIN:USER_PRIV_USER);
                SIVAL(p,usri11_auth_flags,AF_OP_PRINT);         /* auth flags */
                SIVALS(p,usri11_password_age,-1);               /* password age */
                SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
@@ -3489,7 +3822,8 @@ static bool api_RNetUserGetInfo(connection_struct *conn, uint16 vuid,
                memset(p+22,' ',16);    /* password */
                SIVALS(p,38,-1);                /* password age */
                SSVAL(p,42,
-               conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
+                       (get_current_uid(conn) == (uid_t)0)?
+                       USER_PRIV_ADMIN:USER_PRIV_USER);
                SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
                strlcpy(p2, vuser ? pdb_get_homedir(
                                vuser->server_info->sam_account) : "",
@@ -3586,6 +3920,7 @@ static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
                                char **rdata,char **rparam,
                                int *rdata_len,int *rparam_len)
 {
+       struct smbd_server_connection *sconn = smbd_server_conn;
        char *str1 = get_safe_str_ptr(param,tpscnt,param,2);
        char *str2 = skip_string(param,tpscnt,str1);
        char *p = skip_string(param,tpscnt,str2);
@@ -3594,7 +3929,7 @@ static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
        char* name;
                /* With share level security vuid will always be zero.
                   Don't depend on vuser being non-null !!. JRA */
-       user_struct *vuser = get_valid_user_struct(vuid);
+       user_struct *vuser = get_valid_user_struct(sconn, vuid);
 
        if (!str1 || !str2 || !p) {
                return False;
@@ -3602,7 +3937,7 @@ static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
 
        if(vuser != NULL) {
                DEBUG(3,("  Username of UID %d is %s\n",
-                        (int)vuser->server_info->uid,
+                        (int)vuser->server_info->utok.uid,
                         vuser->server_info->unix_name));
        }
 
@@ -3634,12 +3969,14 @@ static bool api_WWkstaUserLogon(connection_struct *conn,uint16 vuid,
        desc.buflen = mdrcnt;
        desc.subformat = NULL;
        desc.format = str2;
-  
+
        if (init_package(&desc,1,0)) {
                PACKI(&desc,"W",0);             /* code */
                PACKS(&desc,"B21",name);        /* eff. name */
                PACKS(&desc,"B","");            /* pad */
-               PACKI(&desc,"W", conn->admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
+               PACKI(&desc,"W",
+                       (get_current_uid(conn) == (uid_t)0)?
+                       USER_PRIV_ADMIN:USER_PRIV_USER);
                PACKI(&desc,"D",0);             /* auth flags XXX */
                PACKI(&desc,"W",0);             /* num logons */
                PACKI(&desc,"W",0);             /* bad pw count */
@@ -3866,11 +4203,11 @@ static bool api_WPrintJobEnumerate(connection_struct *conn, uint16 vuid,
        if (strcmp(str1,"zWrLeh") != 0) {
                return False;
        }
-    
+
        if (uLevel > 2) {
                return False;   /* defined only for uLevel 0,1,2 */
        }
-    
+
        if (!check_printjob_info(&desc,uLevel,str2)) { 
                return False;
        }
@@ -4506,7 +4843,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},
@@ -4533,6 +4871,7 @@ void api_reply(connection_struct *conn, uint16 vuid,
               int tdscnt, int tpscnt,
               int mdrcnt, int mprcnt)
 {
+       struct smbd_server_connection *sconn = smbd_server_conn;
        int api_command;
        char *rdata = NULL;
        char *rparam = NULL;
@@ -4581,7 +4920,7 @@ void api_reply(connection_struct *conn, uint16 vuid,
        /* Check whether this api call can be done anonymously */
 
        if (api_commands[i].auth_user && lp_restrict_anonymous()) {
-               user_struct *user = get_valid_user_struct(vuid);
+               user_struct *user = get_valid_user_struct(sconn, vuid);
 
                if (!user || user->server_info->guest) {
                        reply_nterror(req, NT_STATUS_ACCESS_DENIED);