Removed version number from file header.
[ira/wip.git] / source3 / nsswitch / winbindd_cm.c
index 68a46e368342ec33553d303c6d9633fc863ee3d7..c1b5b27af8955986e900108a31e9c50eea6fab4c 100644 (file)
@@ -1,6 +1,5 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 3.0
+   Unix SMB/CIFS implementation.
 
    Winbind daemon connection manager
 
@@ -13,7 +12,7 @@
    
    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
+   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
        - make connections to domain controllers and cache them
        - re-establish connections when networks or servers go down
        - centralise the policy on connection timeouts, domain controller
-         selection etc
+        selection etc
        - manage re-entrancy for when winbindd becomes able to handle
-         multiple outstanding rpc requests
+        multiple outstanding rpc requests
   
    Why not have connection management as part of the rpc layer like tng?
    Good question.  This code may morph into libsmb/rpc_cache.c or something
-   like that but at the moment it's simply staying as part of winbind.  I
+   like that but at the moment it's simply staying as part of winbind. I
    think the TNG architecture of forcing every user of the rpc layer to use
-   the connection caching system is a bad idea.  It should be an optional
+   the connection caching system is a bad idea.         It should be an optional
    method of using the routines.
 
    The TNG design is quite good but I disagree with some aspects of the
 
 #include "winbindd.h"
 
-/* Global list of connections.  Initially a DLIST but can become a hash
+/* Global list of connections. Initially a DLIST but can become a hash
    table or whatever later. */
 
 struct winbindd_cm_conn {
-        struct winbindd_cm_conn *prev, *next;
-        fstring domain;
-        fstring controller;
-        fstring pipe_name;
-        struct cli_state *cli;
-        POLICY_HND pol;
+       struct winbindd_cm_conn *prev, *next;
+       fstring domain;
+       fstring controller;
+       fstring pipe_name;
+       struct cli_state *cli;
+       POLICY_HND pol;
 };
 
-struct winbindd_cm_conn *cm_conns = NULL;
+static struct winbindd_cm_conn *cm_conns = NULL;
 
 /* Get a domain controller name.  Cache positive and negative lookups so we
    don't go to the network too often when something is badly broken. */
@@ -81,98 +80,161 @@ struct winbindd_cm_conn *cm_conns = NULL;
 #define GET_DC_NAME_CACHE_TIMEOUT 30 /* Seconds between dc lookups */
 
 struct get_dc_name_cache {
-        fstring domain_name;
-        fstring srv_name;
-        time_t lookup_time;
-        struct get_dc_name_cache *prev, *next;
+       fstring domain_name;
+       fstring srv_name;
+       time_t lookup_time;
+       struct get_dc_name_cache *prev, *next;
 };
 
 static BOOL cm_get_dc_name(char *domain, fstring srv_name)
 {
-        static struct get_dc_name_cache *get_dc_name_cache;
-        struct get_dc_name_cache *dcc;
+       static struct get_dc_name_cache *get_dc_name_cache;
+       struct get_dc_name_cache *dcc;
        struct in_addr *ip_list, dc_ip;
-       extern pstring global_myname;
        int count, i;
 
-        /* Check the cache for previous lookups */
+       /* Check the cache for previous lookups */
 
-        for (dcc = get_dc_name_cache; dcc; dcc = dcc->next) {
+       for (dcc = get_dc_name_cache; dcc; dcc = dcc->next) {
 
-                if (!strequal(domain, dcc->domain_name))
-                        continue; /* Not our domain */
+               if (!strequal(domain, dcc->domain_name))
+                       continue; /* Not our domain */
 
-                if ((time(NULL) - dcc->lookup_time) > GET_DC_NAME_CACHE_TIMEOUT) {
+               if ((time(NULL) - dcc->lookup_time) > 
+                   GET_DC_NAME_CACHE_TIMEOUT) {
 
-                        /* Cache entry has expired, delete it */
+                       /* Cache entry has expired, delete it */
 
-                        DEBUG(10, ("get_dc_name_cache entry expired for %s\n",
-                                   domain));
+                       DEBUG(10, ("get_dc_name_cache entry expired for %s\n", domain));
 
-                        DLIST_REMOVE(get_dc_name_cache, dcc);
-                        free(dcc);
+                       DLIST_REMOVE(get_dc_name_cache, dcc);
+                       SAFE_FREE(dcc);
 
-                        break;
-                }
+                       break;
+               }
 
-                /* Return a positive or negative lookup for this domain */
+               /* Return a positive or negative lookup for this domain */
 
-                if (dcc->srv_name[0]) {
-                        DEBUG(10, ("returning positive get_dc_name_cache "
-                                   "entry for %s\n", domain));
-                        fstrcpy(srv_name, dcc->srv_name);
-                        return True;
-                } else {
-                        DEBUG(10, ("returning negative get_dc_name_cache "
-                                   "entry for %s\n", domain));
-                        return False;
-                }
-        }
+               if (dcc->srv_name[0]) {
+                       DEBUG(10, ("returning positive get_dc_name_cache entry for %s\n", domain));
+                       fstrcpy(srv_name, dcc->srv_name);
+                       return True;
+               } else {
+                       DEBUG(10, ("returning negative get_dc_name_cache entry for %s\n", domain));
+                       return False;
+               }
+       }
 
-        /* Add cache entry for this lookup. */
+       /* Add cache entry for this lookup. */
 
-        DEBUG(10, ("Creating get_dc_name_cache entry for %s\n", domain));
+       DEBUG(10, ("Creating get_dc_name_cache entry for %s\n", domain));
 
-        if (!(dcc = (struct get_dc_name_cache *)
-             malloc(sizeof(struct get_dc_name_cache))))
-                return False;
+       if (!(dcc = (struct get_dc_name_cache *) 
+             malloc(sizeof(struct get_dc_name_cache))))
+               return False;
 
-        ZERO_STRUCTP(dcc);
+       ZERO_STRUCTP(dcc);
 
-        fstrcpy(dcc->domain_name, domain);
-        dcc->lookup_time = time(NULL);
+       fstrcpy(dcc->domain_name, domain);
+       dcc->lookup_time = time(NULL);
 
-        DLIST_ADD(get_dc_name_cache, dcc);
+       DLIST_ADD(get_dc_name_cache, dcc);
 
        /* Lookup domain controller name */
                
-       if (!get_dc_list(False, domain, &ip_list, &count))
+       if (!get_dc_list(False, domain, &ip_list, &count)) {
+               DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
                return False;
+       }
+
+       /* Pick a nice close server */
+          
+       if (strequal(lp_passwordserver(), "*")) {
                
-       /* Firstly choose a PDC/BDC who has the same network address as any
-          of our interfaces. */
-       
+               /* Look for DC on local net */
+
+               for (i = 0; i < count; i++) {
+                       if (is_local_net(ip_list[i]) &&
+                           name_status_find(domain, 0x1c, 0x20,
+                                            ip_list[i], srv_name)) {
+                               dc_ip = ip_list[i];
+                               goto done;
+                       }
+                       zero_ip(&ip_list[i]);
+               }
+
+               /* Look for other DCs */
+
+               for (i = 0; i < count; i++) {
+                       if (!is_zero_ip(ip_list[i]) &&
+                           name_status_find(domain, 0x1c, 0x20,
+                                            ip_list[i], srv_name)) {
+                               dc_ip = ip_list[i];
+                               goto done;
+                       }
+               }
+
+               /* No-one to talk to )-: */
+
+               return False;
+       }
+
+       /* Return first DC that we can contact */
+
        for (i = 0; i < count; i++) {
-               if(is_local_net(ip_list[i]))
-                       goto got_ip;
+               if (name_status_find(domain, 0x1c, 0x20, ip_list[i],
+                                    srv_name)) {
+                       dc_ip = ip_list[i];
+                       goto done;
+               }
        }
+
+       return False;           /* Boo-hoo */
        
-       i = (sys_random() % count);
-       
- got_ip:
-       dc_ip = ip_list[i];
-       SAFE_FREE(ip_list);
-               
-       if (!lookup_pdc_name(global_myname, domain, &dc_ip, srv_name))
-               return False;
+ done:
+       /* We have the netbios name and IP address of a domain controller.
+          Ideally we should sent a SAMLOGON request to determine whether
+          the DC is alive and kicking.  If we can catch a dead DC before
+          performing a cli_connect() we can avoid a 30-second timeout. */
+
+       /* We have a name so make the cache entry positive now */
 
-        /* We have a name so make the cache entry positive now */
+       fstrcpy(dcc->srv_name, srv_name);
 
-        fstrcpy(dcc->srv_name, srv_name);
+       DEBUG(3, ("Returning DC %s (%s) for domain %s\n", srv_name,
+                 inet_ntoa(dc_ip), domain));
 
        return True;
 }
 
+/* Choose between anonymous or authenticated connections.  We need to use
+   an authenticated connection if DCs have the RestrictAnonymous registry
+   entry set > 0, or the "Additional restrictions for anonymous
+   connections" set in the win2k Local Security Policy. */
+
+void cm_init_creds(struct ntuser_creds *creds)
+{
+       char *username, *password;
+
+       ZERO_STRUCTP(creds);
+
+       creds->pwd.null_pwd = True; /* anonymoose */
+
+       username = secrets_fetch(SECRETS_AUTH_USER, NULL);
+       password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
+
+       if (username && *username) {
+               pwd_set_cleartext(&creds->pwd, password);
+
+               fstrcpy(creds->user_name, username);
+               fstrcpy(creds->domain, lp_workgroup());
+
+               DEBUG(3, ("IPC$ connections done %s\\%s\n", creds->domain,
+                         creds->user_name));
+       } else 
+               DEBUG(3, ("IPC$ connections done anonymously\n"));
+}
+
 /* Open a new smb pipe connection to a DC on a given domain.  Cache
    negative creation attempts so we don't try and connect to broken
    machines too often. */
@@ -180,236 +242,229 @@ static BOOL cm_get_dc_name(char *domain, fstring srv_name)
 #define OPEN_CONNECTION_CACHE_TIMEOUT 30 /* Seconds between attempts */
 
 struct open_connection_cache {
-        fstring domain_name;
-        fstring controller;
-        time_t lookup_time;
-        struct open_connection_cache *prev, *next;
+       fstring domain_name;
+       fstring controller;
+       time_t lookup_time;
+       struct open_connection_cache *prev, *next;
 };
 
 static BOOL cm_open_connection(char *domain, char *pipe_name,
-                               struct winbindd_cm_conn *new_conn)
+                              struct winbindd_cm_conn *new_conn)
 {
-        static struct open_connection_cache *open_connection_cache;
-        struct open_connection_cache *occ;
+       static struct open_connection_cache *open_connection_cache;
+       struct open_connection_cache *occ;
        struct nmb_name calling, called;
-        extern pstring global_myname;
-        fstring dest_host;
-        struct in_addr dest_ip;
-        BOOL result = False;
-        struct ntuser_creds creds;
+       extern pstring global_myname;
+       fstring dest_host;
+       struct in_addr dest_ip;
+       BOOL result = False;
+       struct ntuser_creds creds;
 
-        fstrcpy(new_conn->domain, domain);
-        fstrcpy(new_conn->pipe_name, pipe_name);
-        
-        /* Look for a domain controller for this domain.  Negative results
-           are cached so don't bother applying the caching for this
-           function just yet.  */
+       fstrcpy(new_conn->domain, domain);
+       fstrcpy(new_conn->pipe_name, pipe_name);
+       
+       /* Look for a domain controller for this domain.  Negative results
+          are cached so don't bother applying the caching for this
+          function just yet.  */
 
-        if (!cm_get_dc_name(domain, new_conn->controller))
-                goto done;
+       if (!cm_get_dc_name(domain, new_conn->controller))
+               goto done;
 
-        /* Return false if we have tried to look up this domain and netbios
-           name before and failed. */
+       /* Return false if we have tried to look up this domain and netbios
+          name before and failed. */
 
-        for (occ = open_connection_cache; occ; occ = occ->next) {
-                
-                if (!(strequal(domain, occ->domain_name) &&
-                      strequal(new_conn->controller, occ->controller)))
-                        continue; /* Not our domain */
+       for (occ = open_connection_cache; occ; occ = occ->next) {
+               
+               if (!(strequal(domain, occ->domain_name) &&
+                     strequal(new_conn->controller, occ->controller)))
+                       continue; /* Not our domain */
 
-                if ((time(NULL) - occ->lookup_time) > OPEN_CONNECTION_CACHE_TIMEOUT) {
-                        /* Cache entry has expired, delete it */
+               if ((time(NULL) - occ->lookup_time) > 
+                   OPEN_CONNECTION_CACHE_TIMEOUT) {
 
-                        DEBUG(10, ("cm_open_connection cache entry expired "
-                                   "for %s, %s\n", domain,
-                                   new_conn->controller));
+                       /* Cache entry has expired, delete it */
 
-                        DLIST_REMOVE(open_connection_cache, occ);
-                        free(occ);
+                       DEBUG(10, ("cm_open_connection cache entry expired for %s, %s\n", domain, new_conn->controller));
 
-                        break;
-                }
+                       DLIST_REMOVE(open_connection_cache, occ);
+                       free(occ);
 
-                /* The timeout hasn't expired yet so return false */
+                       break;
+               }
 
-                DEBUG(10, ("returning negative open_connection_cache entry "
-                           "for %s, %s\n", domain, new_conn->controller));
+               /* The timeout hasn't expired yet so return false */
 
-                goto done;
-        }
+               DEBUG(10, ("returning negative open_connection_cache entry for %s, %s\n", domain, new_conn->controller));
 
-        /* Initialise SMB connection */
+               goto done;
+       }
 
-        if (!(new_conn->cli = cli_initialise(NULL)))
-                goto done;
+       /* Initialise SMB connection */
+
+       if (!(new_conn->cli = cli_initialise(NULL)))
+               goto done;
 
        if (!resolve_srv_name(new_conn->controller, dest_host, &dest_ip))
                goto done;
 
-       make_nmb_name(&called, dns_to_netbios_name(new_conn->controller), 
-                      0x20);
+       make_nmb_name(&called, dns_to_netbios_name(new_conn->controller), 0x20);
        make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
 
-       ZERO_STRUCT(creds);
-       creds.pwd.null_pwd = 1;
+       cm_init_creds(&creds);
 
        cli_init_creds(new_conn->cli, &creds);
 
        if (!cli_establish_connection(new_conn->cli, new_conn->controller, 
-                                      &dest_ip, &calling, &called, "IPC$", 
-                                      "IPC", False, True))
+                                     &dest_ip, &calling, &called, "IPC$", 
+                                     "IPC", False, True))
                goto done;
 
        if (!cli_nt_session_open (new_conn->cli, pipe_name))
                goto done;
 
-        result = True;
+       result = True;
 
  done:
-        /* Create negative lookup cache entry for this domain and
-           controller */
 
-        if (!result) {
-                if (!(occ = (struct open_connection_cache *)
-                      malloc(sizeof(struct open_connection_cache))))
-                        return False;
+       /* Create negative lookup cache entry for this domain and controller */
 
-                ZERO_STRUCTP(occ);
+       if (!result) {
+               if (!(occ = (struct open_connection_cache *)
+                     malloc(sizeof(struct open_connection_cache))))
+                       return False;
 
-                fstrcpy(occ->domain_name, domain);
-                fstrcpy(occ->controller, new_conn->controller);
-                occ->lookup_time = time(NULL);
+               ZERO_STRUCTP(occ);
 
-                DLIST_ADD(open_connection_cache, occ);
-        }
+               fstrcpy(occ->domain_name, domain);
+               fstrcpy(occ->controller, new_conn->controller);
+               occ->lookup_time = time(NULL);
+               
+               DLIST_ADD(open_connection_cache, occ);
+       }
 
-        if (!result && new_conn->cli)
-                cli_shutdown(new_conn->cli);
+       if (!result && new_conn->cli)
+               cli_shutdown(new_conn->cli);
 
-        return result;
+       return result;
 }
 
 /* Return true if a connection is still alive */
 
 static BOOL connection_ok(struct winbindd_cm_conn *conn)
 {
-        if (!conn->cli->initialised)
-                return False;
+       if (!conn->cli->initialised)
+               return False;
 
-        if (conn->cli->fd == -1)
-                return False;
+       if (conn->cli->fd == -1)
+               return False;
        
-        return True;
+       return True;
 }
 
 /* Return a LSA policy handle on a domain */
 
 CLI_POLICY_HND *cm_get_lsa_handle(char *domain)
 {
-        struct winbindd_cm_conn *conn;
-        uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
-        NTSTATUS result;
-        static CLI_POLICY_HND hnd;
+       struct winbindd_cm_conn *conn;
+       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+       NTSTATUS result;
+       static CLI_POLICY_HND hnd;
 
-        /* Look for existing connections */
+       /* Look for existing connections */
 
-        for (conn = cm_conns; conn; conn = conn->next) {
-                if (strequal(conn->domain, domain) &&
-                    strequal(conn->pipe_name, PIPE_LSARPC)) {
+       for (conn = cm_conns; conn; conn = conn->next) {
+               if (strequal(conn->domain, domain) && 
+                   strequal(conn->pipe_name, PIPE_LSARPC)) {
 
-                        if (!connection_ok(conn)) {
-                                DLIST_REMOVE(cm_conns, conn);
-                                return NULL;
-                        }
+                       if (!connection_ok(conn)) {
+                               DLIST_REMOVE(cm_conns, conn);
+                               return NULL;
+                       }
 
-                        goto ok;
-                }
-        }
+                       goto ok;
+               }
+       }
 
-        /* Create a new one */
+       /* Create a new one */
 
-        if (!(conn = (struct winbindd_cm_conn *)
-              malloc(sizeof(struct winbindd_cm_conn))))
-                return NULL;
+       if (!(conn = (struct winbindd_cm_conn *) malloc(sizeof(struct winbindd_cm_conn))))
+               return NULL;
 
-        ZERO_STRUCTP(conn);
+       ZERO_STRUCTP(conn);
 
-        if (!cm_open_connection(domain, PIPE_LSARPC, conn)) {
-                DEBUG(3, ("Could not connect to a dc for domain %s\n",
-                          domain));
-                return NULL;
-        }
+       if (!cm_open_connection(domain, PIPE_LSARPC, conn)) {
+               DEBUG(3, ("Could not connect to a dc for domain %s\n", domain));
+               return NULL;
+       }
 
-        result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
-                                     des_access, &conn->pol);
+       result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
+                                    des_access, &conn->pol);
 
-        if (!NT_STATUS_IS_OK(result))
-                return NULL;
+       if (!NT_STATUS_IS_OK(result))
+               return NULL;
 
-        /* Add to list */
+       /* Add to list */
 
-        DLIST_ADD(cm_conns, conn);
+       DLIST_ADD(cm_conns, conn);
 
  ok:
-        hnd.pol = conn->pol;
-        hnd.cli = conn->cli;
+       hnd.pol = conn->pol;
+       hnd.cli = conn->cli;
 
-        return &hnd;
+       return &hnd;
 }
 
 /* Return a SAM policy handle on a domain */
 
 CLI_POLICY_HND *cm_get_sam_handle(char *domain)
 { 
-        struct winbindd_cm_conn *conn;
-        uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
-        NTSTATUS result;
-        static CLI_POLICY_HND hnd;
+       struct winbindd_cm_conn *conn;
+       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+       NTSTATUS result;
+       static CLI_POLICY_HND hnd;
 
-        /* Look for existing connections */
+       /* Look for existing connections */
 
-        for (conn = cm_conns; conn; conn = conn->next) {
-                if (strequal(conn->domain, domain) &&
-                    strequal(conn->pipe_name, PIPE_SAMR)) {
+       for (conn = cm_conns; conn; conn = conn->next) {
+               if (strequal(conn->domain, domain) && strequal(conn->pipe_name, PIPE_SAMR)) {
 
-                        if (!connection_ok(conn)) {
-                                DLIST_REMOVE(cm_conns, conn);
-                                return NULL;
-                        }
+                       if (!connection_ok(conn)) {
+                               DLIST_REMOVE(cm_conns, conn);
+                               return NULL;
+                       }
 
-                        goto ok;
-                }
-        }
+                       goto ok;
+               }
+       }
 
-        /* Create a new one */
+       /* Create a new one */
 
-        if (!(conn = (struct winbindd_cm_conn *)
-              malloc(sizeof(struct winbindd_cm_conn))))
-                return NULL;
+       if (!(conn = (struct winbindd_cm_conn *) 
+             malloc(sizeof(struct winbindd_cm_conn))))
+               return NULL;
 
-        ZERO_STRUCTP(conn);
+       ZERO_STRUCTP(conn);
 
-        if (!cm_open_connection(domain, PIPE_SAMR, conn)) {
-                DEBUG(3, ("Could not connect to a dc for domain %s\n",
-                          domain));
-                return NULL;
-        }
+       if (!cm_open_connection(domain, PIPE_SAMR, conn)) {
+               DEBUG(3, ("Could not connect to a dc for domain %s\n", domain));
+               return NULL;
+       }
 
-        result = cli_samr_connect(conn->cli, conn->cli->mem_ctx, des_access, 
-                                  &conn->pol);
+       result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
+                                 des_access, &conn->pol);
 
-        if (!NT_STATUS_IS_OK(result))
-                return NULL;
+       if (!NT_STATUS_IS_OK(result))
+               return NULL;
 
-        /* Add to list */
+       /* Add to list */
 
-        DLIST_ADD(cm_conns, conn);
+       DLIST_ADD(cm_conns, conn);
 
  ok:
-        hnd.pol = conn->pol;
-        hnd.cli = conn->cli;
+       hnd.pol = conn->pol;
+       hnd.cli = conn->cli;
 
-        return &hnd;        
+       return &hnd;        
 }
 
 #if 0
@@ -418,220 +473,220 @@ CLI_POLICY_HND *cm_get_sam_handle(char *domain)
 
 CLI_POLICY_HND *cm_get_sam_dom_handle(char *domain, DOM_SID *domain_sid)
 {
-        struct winbindd_cm_conn *conn, *basic_conn = NULL;
-        static CLI_POLICY_HND hnd;
-        NTSTATUS result;
-        uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+       struct winbindd_cm_conn *conn, *basic_conn = NULL;
+       static CLI_POLICY_HND hnd;
+       NTSTATUS result;
+       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
 
-        /* Look for existing connections */
+       /* Look for existing connections */
 
-        for (conn = cm_conns; conn; conn = conn->next) {
-                if (strequal(conn->domain, domain) &&
-                    strequal(conn->pipe_name, PIPE_SAMR) &&
-                    conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM) {
+       for (conn = cm_conns; conn; conn = conn->next) {
+               if (strequal(conn->domain, domain) &&
+                   strequal(conn->pipe_name, PIPE_SAMR) &&
+                   conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM) {
 
-                        if (!connection_ok(conn)) {
-                                DLIST_REMOVE(cm_conns, conn);
-                                return NULL;
-                        }
+                       if (!connection_ok(conn)) {
+                               DLIST_REMOVE(cm_conns, conn);
+                               return NULL;
+                       }
 
-                        goto ok;
-                }
-        }
+                       goto ok;
+               }
+       }
 
-        /* Create a basic handle to open a domain handle from */
+       /* Create a basic handle to open a domain handle from */
 
-        if (!cm_get_sam_handle(domain))
-                return False;
+       if (!cm_get_sam_handle(domain))
+               return False;
 
-        for (conn = cm_conns; conn; conn = conn->next) {
-                if (strequal(conn->domain, domain) &&
-                    strequal(conn->pipe_name, PIPE_SAMR) &&
-                    conn->pipe_data.samr.pipe_type == SAM_PIPE_BASIC)
-                        basic_conn = conn;
-        }
-        
-        if (!(conn = (struct winbindd_cm_conn *)
-              malloc(sizeof(struct winbindd_cm_conn))))
-                return NULL;
-        
-        ZERO_STRUCTP(conn);
+       for (conn = cm_conns; conn; conn = conn->next) {
+               if (strequal(conn->domain, domain) &&
+                   strequal(conn->pipe_name, PIPE_SAMR) &&
+                   conn->pipe_data.samr.pipe_type == SAM_PIPE_BASIC)
+                       basic_conn = conn;
+       }
+       
+       if (!(conn = (struct winbindd_cm_conn *)
+             malloc(sizeof(struct winbindd_cm_conn))))
+               return NULL;
+       
+       ZERO_STRUCTP(conn);
 
-        fstrcpy(conn->domain, basic_conn->domain);
-        fstrcpy(conn->controller, basic_conn->controller);
-        fstrcpy(conn->pipe_name, basic_conn->pipe_name);
+       fstrcpy(conn->domain, basic_conn->domain);
+       fstrcpy(conn->controller, basic_conn->controller);
+       fstrcpy(conn->pipe_name, basic_conn->pipe_name);
 
-        conn->pipe_data.samr.pipe_type = SAM_PIPE_DOM;
-        conn->cli = basic_conn->cli;
+       conn->pipe_data.samr.pipe_type = SAM_PIPE_DOM;
+       conn->cli = basic_conn->cli;
 
-        result = cli_samr_open_domain(conn->cli, conn->cli->mem_ctx,
-                                      &basic_conn->pol, des_access, 
-                                      domain_sid, &conn->pol);
+       result = cli_samr_open_domain(conn->cli, conn->cli->mem_ctx,
+                                     &basic_conn->pol, des_access, 
+                                     domain_sid, &conn->pol);
 
-        if (!NT_STATUS_IS_OK(result))
-                return NULL;
+       if (!NT_STATUS_IS_OK(result))
+               return NULL;
 
-        /* Add to list */
+       /* Add to list */
 
-        DLIST_ADD(cm_conns, conn);
+       DLIST_ADD(cm_conns, conn);
 
  ok:
-        hnd.pol = conn->pol;
-        hnd.cli = conn->cli;
+       hnd.pol = conn->pol;
+       hnd.cli = conn->cli;
 
-        return &hnd;
+       return &hnd;
 }
 
 /* Return a SAM policy handle on a domain user */
 
 CLI_POLICY_HND *cm_get_sam_user_handle(char *domain, DOM_SID *domain_sid,
-                                       uint32 user_rid)
+                                      uint32 user_rid)
 {
-        struct winbindd_cm_conn *conn, *basic_conn = NULL;
-        static CLI_POLICY_HND hnd;
-        NTSTATUS result;
-        uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
-
-        /* Look for existing connections */
-
-        for (conn = cm_conns; conn; conn = conn->next) {
-                if (strequal(conn->domain, domain) &&
-                    strequal(conn->pipe_name, PIPE_SAMR) &&
-                    conn->pipe_data.samr.pipe_type == SAM_PIPE_USER &&
-                    conn->pipe_data.samr.rid == user_rid) {
-
-                        if (!connection_ok(conn)) {
-                                DLIST_REMOVE(cm_conns, conn);
-                                return NULL;
-                        }
-                
-                        goto ok;
-                }
-        }
-
-        /* Create a domain handle to open a user handle from */
-
-        if (!cm_get_sam_dom_handle(domain, domain_sid))
-                return NULL;
-
-        for (conn = cm_conns; conn; conn = conn->next) {
-                if (strequal(conn->domain, domain) &&
-                    strequal(conn->pipe_name, PIPE_SAMR) &&
-                    conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
-                        basic_conn = conn;
-        }
-        
-        if (!basic_conn) {
-                DEBUG(0, ("No domain sam handle was created!\n"));
-                return NULL;
-        }
-
-        if (!(conn = (struct winbindd_cm_conn *)
-              malloc(sizeof(struct winbindd_cm_conn))))
-                return NULL;
-        
-        ZERO_STRUCTP(conn);
-
-        fstrcpy(conn->domain, basic_conn->domain);
-        fstrcpy(conn->controller, basic_conn->controller);
-        fstrcpy(conn->pipe_name, basic_conn->pipe_name);
-        
-        conn->pipe_data.samr.pipe_type = SAM_PIPE_USER;
-        conn->cli = basic_conn->cli;
-        conn->pipe_data.samr.rid = user_rid;
-
-        result = cli_samr_open_user(conn->cli, conn->cli->mem_ctx,
-                                    &basic_conn->pol, des_access, user_rid,
-                                    &conn->pol);
-
-        if (!NT_STATUS_IS_OK(result))
-                return NULL;
-
-        /* Add to list */
-
-        DLIST_ADD(cm_conns, conn);
+       struct winbindd_cm_conn *conn, *basic_conn = NULL;
+       static CLI_POLICY_HND hnd;
+       NTSTATUS result;
+       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+
+       /* Look for existing connections */
+
+       for (conn = cm_conns; conn; conn = conn->next) {
+               if (strequal(conn->domain, domain) &&
+                   strequal(conn->pipe_name, PIPE_SAMR) &&
+                   conn->pipe_data.samr.pipe_type == SAM_PIPE_USER &&
+                   conn->pipe_data.samr.rid == user_rid) {
+
+                       if (!connection_ok(conn)) {
+                               DLIST_REMOVE(cm_conns, conn);
+                               return NULL;
+                       }
+               
+                       goto ok;
+               }
+       }
+
+       /* Create a domain handle to open a user handle from */
+
+       if (!cm_get_sam_dom_handle(domain, domain_sid))
+               return NULL;
+
+       for (conn = cm_conns; conn; conn = conn->next) {
+               if (strequal(conn->domain, domain) &&
+                   strequal(conn->pipe_name, PIPE_SAMR) &&
+                   conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
+                       basic_conn = conn;
+       }
+       
+       if (!basic_conn) {
+               DEBUG(0, ("No domain sam handle was created!\n"));
+               return NULL;
+       }
+
+       if (!(conn = (struct winbindd_cm_conn *)
+             malloc(sizeof(struct winbindd_cm_conn))))
+               return NULL;
+       
+       ZERO_STRUCTP(conn);
+
+       fstrcpy(conn->domain, basic_conn->domain);
+       fstrcpy(conn->controller, basic_conn->controller);
+       fstrcpy(conn->pipe_name, basic_conn->pipe_name);
+       
+       conn->pipe_data.samr.pipe_type = SAM_PIPE_USER;
+       conn->cli = basic_conn->cli;
+       conn->pipe_data.samr.rid = user_rid;
+
+       result = cli_samr_open_user(conn->cli, conn->cli->mem_ctx,
+                                   &basic_conn->pol, des_access, user_rid,
+                                   &conn->pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               return NULL;
+
+       /* Add to list */
+
+       DLIST_ADD(cm_conns, conn);
 
  ok:
-        hnd.pol = conn->pol;
-        hnd.cli = conn->cli;
+       hnd.pol = conn->pol;
+       hnd.cli = conn->cli;
 
-        return &hnd;
+       return &hnd;
 }
 
 /* Return a SAM policy handle on a domain group */
 
 CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid,
-                                        uint32 group_rid)
+                                       uint32 group_rid)
 {
-        struct winbindd_cm_conn *conn, *basic_conn = NULL;
-        static CLI_POLICY_HND hnd;
-        NTSTATUS result;
-        uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
-
-        /* Look for existing connections */
-
-        for (conn = cm_conns; conn; conn = conn->next) {
-                if (strequal(conn->domain, domain) &&
-                    strequal(conn->pipe_name, PIPE_SAMR) &&
-                    conn->pipe_data.samr.pipe_type == SAM_PIPE_GROUP &&
-                    conn->pipe_data.samr.rid == group_rid) {
-
-                        if (!connection_ok(conn)) {
-                                DLIST_REMOVE(cm_conns, conn);
-                                return NULL;
-                        }
-                
-                        goto ok;
-                }
-        }
-
-        /* Create a domain handle to open a user handle from */
-
-        if (!cm_get_sam_dom_handle(domain, domain_sid))
-                return NULL;
-
-        for (conn = cm_conns; conn; conn = conn->next) {
-                if (strequal(conn->domain, domain) &&
-                    strequal(conn->pipe_name, PIPE_SAMR) &&
-                    conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
-                        basic_conn = conn;
-        }
-        
-        if (!basic_conn) {
-                DEBUG(0, ("No domain sam handle was created!\n"));
-                return NULL;
-        }
-
-        if (!(conn = (struct winbindd_cm_conn *)
-              malloc(sizeof(struct winbindd_cm_conn))))
-                return NULL;
-        
-        ZERO_STRUCTP(conn);
-
-        fstrcpy(conn->domain, basic_conn->domain);
-        fstrcpy(conn->controller, basic_conn->controller);
-        fstrcpy(conn->pipe_name, basic_conn->pipe_name);
-        
-        conn->pipe_data.samr.pipe_type = SAM_PIPE_GROUP;
-        conn->cli = basic_conn->cli;
-        conn->pipe_data.samr.rid = group_rid;
-
-        result = cli_samr_open_group(conn->cli, conn->cli->mem_ctx,
-                                    &basic_conn->pol, des_access, group_rid,
-                                    &conn->pol);
-
-        if (!NT_STATUS_IS_OK(result))
-                return NULL;
-
-        /* Add to list */
-
-        DLIST_ADD(cm_conns, conn);
+       struct winbindd_cm_conn *conn, *basic_conn = NULL;
+       static CLI_POLICY_HND hnd;
+       NTSTATUS result;
+       uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
+
+       /* Look for existing connections */
+
+       for (conn = cm_conns; conn; conn = conn->next) {
+               if (strequal(conn->domain, domain) &&
+                   strequal(conn->pipe_name, PIPE_SAMR) &&
+                   conn->pipe_data.samr.pipe_type == SAM_PIPE_GROUP &&
+                   conn->pipe_data.samr.rid == group_rid) {
+
+                       if (!connection_ok(conn)) {
+                               DLIST_REMOVE(cm_conns, conn);
+                               return NULL;
+                       }
+               
+                       goto ok;
+               }
+       }
+
+       /* Create a domain handle to open a user handle from */
+
+       if (!cm_get_sam_dom_handle(domain, domain_sid))
+               return NULL;
+
+       for (conn = cm_conns; conn; conn = conn->next) {
+               if (strequal(conn->domain, domain) &&
+                   strequal(conn->pipe_name, PIPE_SAMR) &&
+                   conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
+                       basic_conn = conn;
+       }
+       
+       if (!basic_conn) {
+               DEBUG(0, ("No domain sam handle was created!\n"));
+               return NULL;
+       }
+
+       if (!(conn = (struct winbindd_cm_conn *)
+             malloc(sizeof(struct winbindd_cm_conn))))
+               return NULL;
+       
+       ZERO_STRUCTP(conn);
+
+       fstrcpy(conn->domain, basic_conn->domain);
+       fstrcpy(conn->controller, basic_conn->controller);
+       fstrcpy(conn->pipe_name, basic_conn->pipe_name);
+       
+       conn->pipe_data.samr.pipe_type = SAM_PIPE_GROUP;
+       conn->cli = basic_conn->cli;
+       conn->pipe_data.samr.rid = group_rid;
+
+       result = cli_samr_open_group(conn->cli, conn->cli->mem_ctx,
+                                   &basic_conn->pol, des_access, group_rid,
+                                   &conn->pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               return NULL;
+
+       /* Add to list */
+
+       DLIST_ADD(cm_conns, conn);
 
  ok:
-        hnd.pol = conn->pol;
-        hnd.cli = conn->cli;
+       hnd.pol = conn->pol;
+       hnd.cli = conn->cli;
 
-        return &hnd;
+       return &hnd;
 }
 
 #endif
@@ -639,64 +694,66 @@ CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid,
 /* Get a handle on a netlogon pipe.  This is a bit of a hack to re-use the
    netlogon pipe as no handle is returned. */
 
-struct cli_state *cm_get_netlogon_cli(char *domain, unsigned char *trust_passwd)
+NTSTATUS cm_get_netlogon_cli(char *domain, unsigned char *trust_passwd,
+                            struct cli_state **cli)
 {
-        struct winbindd_cm_conn conn;
-        NTSTATUS result;
+       struct winbindd_cm_conn conn;
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
 
-        /* Open an initial conection */
+       /* Open an initial conection */
 
-        ZERO_STRUCT(conn);
+       ZERO_STRUCT(conn);
 
-        if (!cm_open_connection(domain, PIPE_NETLOGON, &conn)) {
-                DEBUG(3, ("Could not open a connection to %s\n", domain));
-                return NULL;
-        }
+       if (!cm_open_connection(domain, PIPE_NETLOGON, &conn)) {
+               DEBUG(3, ("Could not open a connection to %s\n", domain));
+               return result;
+       }
 
-        result = cli_nt_setup_creds(conn.cli, trust_passwd);
+       result = new_cli_nt_setup_creds(conn.cli, trust_passwd);
 
-        if (!NT_STATUS_IS_OK(result)) {
-                DEBUG(0, ("error connecting to domain password server: %s\n",
-                          get_nt_error_msg(result)));
-                cli_shutdown(conn.cli);
-                return NULL;
-        }
+       if (!NT_STATUS_IS_OK(result)) {
+               DEBUG(0, ("error connecting to domain password server: %s\n",
+                       get_nt_error_msg(result)));
+                       cli_shutdown(conn.cli);
+                       return result;
+       }
 
-        /* We only want the client handle from this structure */
+       if (cli)
+               *cli = conn.cli;
 
-        return conn.cli;
+       return result;
 }
 
 /* Dump the current connection status */
 
 static void dump_conn_list(void)
 {
-        struct winbindd_cm_conn *con;
+       struct winbindd_cm_conn *con;
 
-        DEBUG(0, ("\tDomain          Controller      Pipe\n"));
+       DEBUG(0, ("\tDomain          Controller      Pipe\n"));
 
-        for(con = cm_conns; con; con = con->next) {
-                char *msg;
+       for(con = cm_conns; con; con = con->next) {
+               char *msg;
 
-                /* Display pipe info */
-                
-                asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, 
-                         con->controller, con->pipe_name);
-                
-                DEBUG(0, ("%s\n", msg));
-                free(msg);
-        }
+               /* Display pipe info */
+               
+               if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
+                       DEBUG(0, ("Error: not enough memory!\n"));
+               } else {
+                       DEBUG(0, ("%s\n", msg));
+                       SAFE_FREE(msg);
+               }
+       }
 }
 
 void winbindd_cm_status(void)
 {
-        /* List open connections */
-
-        DEBUG(0, ("winbindd connection manager status:\n"));
+       /* List open connections */
 
-        if (cm_conns)
-                dump_conn_list();
-        else
-                DEBUG(0, ("\tNo active connections\n"));
+       DEBUG(0, ("winbindd connection manager status:\n"));
 
+       if (cm_conns)
+               dump_conn_list();
+       else
+               DEBUG(0, ("\tNo active connections\n"));
 }