more debug classess activated
[Samba.git] / source / nsswitch / winbindd_cm.c
blobbffa169ab1700aaa8d2822118c282686bc9bb770
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon connection manager
6 Copyright (C) Tim Potter 2001
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 We need to manage connections to domain controllers without having to
25 mess up the main winbindd code with other issues. The aim of the
26 connection manager is to:
28 - make connections to domain controllers and cache them
29 - re-establish connections when networks or servers go down
30 - centralise the policy on connection timeouts, domain controller
31 selection etc
32 - manage re-entrancy for when winbindd becomes able to handle
33 multiple outstanding rpc requests
35 Why not have connection management as part of the rpc layer like tng?
36 Good question. This code may morph into libsmb/rpc_cache.c or something
37 like that but at the moment it's simply staying as part of winbind. I
38 think the TNG architecture of forcing every user of the rpc layer to use
39 the connection caching system is a bad idea. It should be an optional
40 method of using the routines.
42 The TNG design is quite good but I disagree with some aspects of the
43 implementation. -tpot
48 TODO:
50 - I'm pretty annoyed by all the make_nmb_name() stuff. It should be
51 moved down into another function.
53 - There needs to be a utility function in libsmb/namequery.c that does
54 cm_get_dc_name()
56 - Take care when destroying cli_structs as they can be shared between
57 various sam handles.
61 #include "winbindd.h"
63 #undef DBGC_CLASS
64 #define DBGC_CLASS DBGC_WINBIND
66 /* Global list of connections. Initially a DLIST but can become a hash
67 table or whatever later. */
69 struct winbindd_cm_conn {
70 struct winbindd_cm_conn *prev, *next;
71 fstring domain;
72 fstring controller;
73 fstring pipe_name;
74 struct cli_state *cli;
75 POLICY_HND pol;
78 static struct winbindd_cm_conn *cm_conns = NULL;
80 /* Get a domain controller name. Cache positive and negative lookups so we
81 don't go to the network too often when something is badly broken. */
83 #define GET_DC_NAME_CACHE_TIMEOUT 30 /* Seconds between dc lookups */
85 struct get_dc_name_cache {
86 fstring domain_name;
87 fstring srv_name;
88 time_t lookup_time;
89 struct get_dc_name_cache *prev, *next;
92 static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out)
94 static struct get_dc_name_cache *get_dc_name_cache;
95 struct get_dc_name_cache *dcc;
96 struct in_addr *ip_list, dc_ip;
97 int count, i;
99 /* Check the cache for previous lookups */
101 for (dcc = get_dc_name_cache; dcc; dcc = dcc->next) {
103 if (!strequal(domain, dcc->domain_name))
104 continue; /* Not our domain */
106 if ((time(NULL) - dcc->lookup_time) >
107 GET_DC_NAME_CACHE_TIMEOUT) {
109 /* Cache entry has expired, delete it */
111 DEBUG(10, ("get_dc_name_cache entry expired for %s\n", domain));
113 DLIST_REMOVE(get_dc_name_cache, dcc);
114 SAFE_FREE(dcc);
116 break;
119 /* Return a positive or negative lookup for this domain */
121 if (dcc->srv_name[0]) {
122 DEBUG(10, ("returning positive get_dc_name_cache entry for %s\n", domain));
123 fstrcpy(srv_name, dcc->srv_name);
124 return True;
125 } else {
126 DEBUG(10, ("returning negative get_dc_name_cache entry for %s\n", domain));
127 return False;
131 /* Add cache entry for this lookup. */
133 DEBUG(10, ("Creating get_dc_name_cache entry for %s\n", domain));
135 if (!(dcc = (struct get_dc_name_cache *)
136 malloc(sizeof(struct get_dc_name_cache))))
137 return False;
139 ZERO_STRUCTP(dcc);
141 fstrcpy(dcc->domain_name, domain);
142 dcc->lookup_time = time(NULL);
144 DLIST_ADD(get_dc_name_cache, dcc);
146 /* Lookup domain controller name. Try the real PDC first to avoid
147 SAM sync delays */
148 if (!get_dc_list(True, domain, &ip_list, &count)) {
149 if (!get_dc_list(False, domain, &ip_list, &count)) {
150 DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
151 return False;
155 /* Pick a nice close server */
156 /* Look for DC on local net */
158 for (i = 0; i < count; i++) {
159 if (!is_local_net(ip_list[i]))
160 continue;
162 if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
163 dc_ip = ip_list[i];
164 goto done;
166 zero_ip(&ip_list[i]);
170 * Secondly try and contact a random PDC/BDC.
173 i = (sys_random() % count);
175 if (!is_zero_ip(ip_list[i]) &&
176 name_status_find(domain, 0x1c, 0x20,
177 ip_list[i], srv_name)) {
178 dc_ip = ip_list[i];
179 goto done;
181 zero_ip(&ip_list[i]); /* Tried and failed. */
183 /* Finally return first DC that we can contact */
185 for (i = 0; i < count; i++) {
186 if (is_zero_ip(ip_list[i]))
187 continue;
189 if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
190 dc_ip = ip_list[i];
191 goto done;
195 /* No-one to talk to )-: */
196 return False; /* Boo-hoo */
198 done:
199 /* We have the netbios name and IP address of a domain controller.
200 Ideally we should sent a SAMLOGON request to determine whether
201 the DC is alive and kicking. If we can catch a dead DC before
202 performing a cli_connect() we can avoid a 30-second timeout. */
204 /* We have a name so make the cache entry positive now */
206 fstrcpy(dcc->srv_name, srv_name);
208 DEBUG(3, ("cm_get_dc_name: Returning DC %s (%s) for domain %s\n", srv_name,
209 inet_ntoa(dc_ip), domain));
211 *ip_out = dc_ip;
213 SAFE_FREE(ip_list);
215 return True;
218 /* Choose between anonymous or authenticated connections. We need to use
219 an authenticated connection if DCs have the RestrictAnonymous registry
220 entry set > 0, or the "Additional restrictions for anonymous
221 connections" set in the win2k Local Security Policy.
223 Caller to free() result in domain, username, password
226 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
228 *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
229 *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
230 *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
232 if (*username && **username) {
233 if (!*domain || !**domain) {
234 *domain = smb_xstrdup(lp_workgroup());
237 DEBUG(3, ("IPC$ connections done by user %s\\%s\n", *domain, *username));
238 } else {
239 DEBUG(3, ("IPC$ connections done anonymously\n"));
240 *username = smb_xstrdup("");
241 *domain = smb_xstrdup("");
242 *password = smb_xstrdup("");
246 /* Open a new smb pipe connection to a DC on a given domain. Cache
247 negative creation attempts so we don't try and connect to broken
248 machines too often. */
250 #define FAILED_CONNECTION_CACHE_TIMEOUT 30 /* Seconds between attempts */
252 struct failed_connection_cache {
253 fstring domain_name;
254 fstring controller;
255 time_t lookup_time;
256 NTSTATUS nt_status;
257 struct failed_connection_cache *prev, *next;
260 static struct failed_connection_cache *failed_connection_cache;
262 /* Add an entry to the failed conneciton cache */
264 static void add_failed_connection_entry(struct winbindd_cm_conn *new_conn, NTSTATUS result) {
265 struct failed_connection_cache *fcc;
267 SMB_ASSERT(!NT_STATUS_IS_OK(result));
269 /* Create negative lookup cache entry for this domain and controller */
271 if (!(fcc = (struct failed_connection_cache *)
272 malloc(sizeof(struct failed_connection_cache)))) {
273 DEBUG(0, ("malloc failed in add_failed_connection_entry!\n"));
274 return;
277 ZERO_STRUCTP(fcc);
279 fstrcpy(fcc->domain_name, new_conn->domain);
280 fstrcpy(fcc->controller, new_conn->controller);
281 fcc->lookup_time = time(NULL);
282 fcc->nt_status = result;
284 DLIST_ADD(failed_connection_cache, fcc);
287 /* Open a connction to the remote server, cache failures for 30 seconds */
289 static NTSTATUS cm_open_connection(const char *domain,const char *pipe_name,
290 struct winbindd_cm_conn *new_conn)
292 struct failed_connection_cache *fcc;
293 extern pstring global_myname;
294 NTSTATUS result;
295 char *ipc_username, *ipc_domain, *ipc_password;
296 struct in_addr dc_ip;
298 ZERO_STRUCT(dc_ip);
300 fstrcpy(new_conn->domain, domain);
301 fstrcpy(new_conn->pipe_name, pipe_name);
303 /* Look for a domain controller for this domain. Negative results
304 are cached so don't bother applying the caching for this
305 function just yet. */
307 if (!cm_get_dc_name(domain, new_conn->controller, &dc_ip)) {
308 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
309 add_failed_connection_entry(new_conn, result);
310 return result;
313 /* Return false if we have tried to look up this domain and netbios
314 name before and failed. */
316 for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {
318 if (!(strequal(domain, fcc->domain_name) &&
319 strequal(new_conn->controller, fcc->controller)))
320 continue; /* Not our domain */
322 if ((time(NULL) - fcc->lookup_time) >
323 FAILED_CONNECTION_CACHE_TIMEOUT) {
325 /* Cache entry has expired, delete it */
327 DEBUG(10, ("cm_open_connection cache entry expired for %s, %s\n", domain, new_conn->controller));
329 DLIST_REMOVE(failed_connection_cache, fcc);
330 free(fcc);
332 break;
335 /* The timeout hasn't expired yet so return false */
337 DEBUG(10, ("returning negative open_connection_cache entry for %s, %s\n", domain, new_conn->controller));
339 result = fcc->nt_status;
340 SMB_ASSERT(!NT_STATUS_IS_OK(result));
341 return result;
344 /* Initialise SMB connection */
346 cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
348 DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n",
349 new_conn->controller, global_myname, ipc_domain, ipc_username));
351 result = cli_full_connection(&(new_conn->cli), global_myname, new_conn->controller,
352 &dc_ip, 0, "IPC$",
353 "IPC", ipc_username, ipc_domain,
354 ipc_password);
356 SAFE_FREE(ipc_username);
357 SAFE_FREE(ipc_domain);
358 SAFE_FREE(ipc_password);
360 if (!NT_STATUS_IS_OK(result)) {
361 add_failed_connection_entry(new_conn, result);
362 return result;
365 if (!cli_nt_session_open (new_conn->cli, pipe_name)) {
366 result = NT_STATUS_PIPE_NOT_AVAILABLE;
367 add_failed_connection_entry(new_conn, result);
368 cli_shutdown(new_conn->cli);
369 return result;
372 return NT_STATUS_OK;
375 /* Return true if a connection is still alive */
377 static BOOL connection_ok(struct winbindd_cm_conn *conn)
379 if (!conn) {
380 smb_panic("Invalid paramater passed to conneciton_ok(): conn was NULL!\n");
381 return False;
384 if (!conn->cli) {
385 DEBUG(0, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
386 conn->controller, conn->domain, conn->pipe_name));
387 smb_panic("connection_ok: conn->cli was null!");
388 return False;
391 if (!conn->cli->initialised) {
392 DEBUG(0, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
393 conn->controller, conn->domain, conn->pipe_name));
394 smb_panic("connection_ok: conn->cli->initialised is False!");
395 return False;
398 if (conn->cli->fd == -1) {
399 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
400 conn->controller, conn->domain, conn->pipe_name));
401 return False;
404 return True;
407 /* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
409 static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_name, struct winbindd_cm_conn **conn_out)
411 struct winbindd_cm_conn *conn, conn_temp;
412 NTSTATUS result;
414 for (conn = cm_conns; conn; conn = conn->next) {
415 if (strequal(conn->domain, domain) &&
416 strequal(conn->pipe_name, pipe_name)) {
417 if (!connection_ok(conn)) {
418 if (conn->cli) {
419 cli_shutdown(conn->cli);
421 ZERO_STRUCT(conn_temp);
422 conn_temp.next = conn->next;
423 DLIST_REMOVE(cm_conns, conn);
424 SAFE_FREE(conn);
425 conn = &conn_temp; /* Just to keep the loop moving */
426 } else {
427 break;
432 if (!conn) {
433 if (!(conn = malloc(sizeof(*conn))))
434 return NT_STATUS_NO_MEMORY;
436 ZERO_STRUCTP(conn);
438 if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, pipe_name, conn))) {
439 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
440 domain, pipe_name, nt_errstr(result)));
441 SAFE_FREE(conn);
442 return result;
444 DLIST_ADD(cm_conns, conn);
447 *conn_out = conn;
448 return NT_STATUS_OK;
451 /* Return a LSA policy handle on a domain */
453 CLI_POLICY_HND *cm_get_lsa_handle(char *domain)
455 struct winbindd_cm_conn *conn;
456 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
457 NTSTATUS result;
458 static CLI_POLICY_HND hnd;
460 /* Look for existing connections */
462 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn))) {
463 return NULL;
466 /* This *shitty* code needs scrapping ! JRA */
467 if (policy_handle_is_valid(&conn->pol)) {
468 hnd.pol = conn->pol;
469 hnd.cli = conn->cli;
470 return &hnd;
473 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
474 des_access, &conn->pol);
476 if (!NT_STATUS_IS_OK(result)) {
477 /* Hit the cache code again. This cleans out the old connection and gets a new one */
478 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
479 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn))) {
480 return NULL;
483 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
484 des_access, &conn->pol);
487 if (!NT_STATUS_IS_OK(result)) {
488 cli_shutdown(conn->cli);
489 DLIST_REMOVE(cm_conns, conn);
490 SAFE_FREE(conn);
491 return NULL;
495 hnd.pol = conn->pol;
496 hnd.cli = conn->cli;
498 return &hnd;
501 /* Return a SAM policy handle on a domain */
503 CLI_POLICY_HND *cm_get_sam_handle(char *domain)
505 struct winbindd_cm_conn *conn;
506 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
507 NTSTATUS result;
508 static CLI_POLICY_HND hnd;
510 /* Look for existing connections */
512 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn))) {
513 return NULL;
516 /* This *shitty* code needs scrapping ! JRA */
517 if (policy_handle_is_valid(&conn->pol)) {
518 hnd.pol = conn->pol;
519 hnd.cli = conn->cli;
520 return &hnd;
522 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
523 des_access, &conn->pol);
525 if (!NT_STATUS_IS_OK(result)) {
526 /* Hit the cache code again. This cleans out the old connection and gets a new one */
527 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
528 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn))) {
529 return NULL;
532 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
533 des_access, &conn->pol);
536 if (!NT_STATUS_IS_OK(result)) {
537 cli_shutdown(conn->cli);
538 DLIST_REMOVE(cm_conns, conn);
539 SAFE_FREE(conn);
540 return NULL;
544 hnd.pol = conn->pol;
545 hnd.cli = conn->cli;
547 return &hnd;
550 #if 0 /* This code now *well* out of date */
552 /* Return a SAM domain policy handle on a domain */
554 CLI_POLICY_HND *cm_get_sam_dom_handle(char *domain, DOM_SID *domain_sid)
556 struct winbindd_cm_conn *conn, *basic_conn = NULL;
557 static CLI_POLICY_HND hnd;
558 NTSTATUS result;
559 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
561 /* Look for existing connections */
563 for (conn = cm_conns; conn; conn = conn->next) {
564 if (strequal(conn->domain, domain) &&
565 strequal(conn->pipe_name, PIPE_SAMR) &&
566 conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM) {
568 if (!connection_ok(conn)) {
569 /* Shutdown cli? Free conn? Allow retry of DC? */
570 DLIST_REMOVE(cm_conns, conn);
571 return NULL;
574 goto ok;
578 /* Create a basic handle to open a domain handle from */
580 if (!cm_get_sam_handle(domain))
581 return False;
583 for (conn = cm_conns; conn; conn = conn->next) {
584 if (strequal(conn->domain, domain) &&
585 strequal(conn->pipe_name, PIPE_SAMR) &&
586 conn->pipe_data.samr.pipe_type == SAM_PIPE_BASIC)
587 basic_conn = conn;
590 if (!(conn = (struct winbindd_cm_conn *)
591 malloc(sizeof(struct winbindd_cm_conn))))
592 return NULL;
594 ZERO_STRUCTP(conn);
596 fstrcpy(conn->domain, basic_conn->domain);
597 fstrcpy(conn->controller, basic_conn->controller);
598 fstrcpy(conn->pipe_name, basic_conn->pipe_name);
600 conn->pipe_data.samr.pipe_type = SAM_PIPE_DOM;
601 conn->cli = basic_conn->cli;
603 result = cli_samr_open_domain(conn->cli, conn->cli->mem_ctx,
604 &basic_conn->pol, des_access,
605 domain_sid, &conn->pol);
607 if (!NT_STATUS_IS_OK(result))
608 return NULL;
610 /* Add to list */
612 DLIST_ADD(cm_conns, conn);
615 hnd.pol = conn->pol;
616 hnd.cli = conn->cli;
618 return &hnd;
621 /* Return a SAM policy handle on a domain user */
623 CLI_POLICY_HND *cm_get_sam_user_handle(char *domain, DOM_SID *domain_sid,
624 uint32 user_rid)
626 struct winbindd_cm_conn *conn, *basic_conn = NULL;
627 static CLI_POLICY_HND hnd;
628 NTSTATUS result;
629 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
631 /* Look for existing connections */
633 for (conn = cm_conns; conn; conn = conn->next) {
634 if (strequal(conn->domain, domain) &&
635 strequal(conn->pipe_name, PIPE_SAMR) &&
636 conn->pipe_data.samr.pipe_type == SAM_PIPE_USER &&
637 conn->pipe_data.samr.rid == user_rid) {
639 if (!connection_ok(conn)) {
640 /* Shutdown cli? Free conn? Allow retry of DC? */
641 DLIST_REMOVE(cm_conns, conn);
642 return NULL;
645 goto ok;
649 /* Create a domain handle to open a user handle from */
651 if (!cm_get_sam_dom_handle(domain, domain_sid))
652 return NULL;
654 for (conn = cm_conns; conn; conn = conn->next) {
655 if (strequal(conn->domain, domain) &&
656 strequal(conn->pipe_name, PIPE_SAMR) &&
657 conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
658 basic_conn = conn;
661 if (!basic_conn) {
662 DEBUG(0, ("No domain sam handle was created!\n"));
663 return NULL;
666 if (!(conn = (struct winbindd_cm_conn *)
667 malloc(sizeof(struct winbindd_cm_conn))))
668 return NULL;
670 ZERO_STRUCTP(conn);
672 fstrcpy(conn->domain, basic_conn->domain);
673 fstrcpy(conn->controller, basic_conn->controller);
674 fstrcpy(conn->pipe_name, basic_conn->pipe_name);
676 conn->pipe_data.samr.pipe_type = SAM_PIPE_USER;
677 conn->cli = basic_conn->cli;
678 conn->pipe_data.samr.rid = user_rid;
680 result = cli_samr_open_user(conn->cli, conn->cli->mem_ctx,
681 &basic_conn->pol, des_access, user_rid,
682 &conn->pol);
684 if (!NT_STATUS_IS_OK(result))
685 return NULL;
687 /* Add to list */
689 DLIST_ADD(cm_conns, conn);
692 hnd.pol = conn->pol;
693 hnd.cli = conn->cli;
695 return &hnd;
698 /* Return a SAM policy handle on a domain group */
700 CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid,
701 uint32 group_rid)
703 struct winbindd_cm_conn *conn, *basic_conn = NULL;
704 static CLI_POLICY_HND hnd;
705 NTSTATUS result;
706 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
708 /* Look for existing connections */
710 for (conn = cm_conns; conn; conn = conn->next) {
711 if (strequal(conn->domain, domain) &&
712 strequal(conn->pipe_name, PIPE_SAMR) &&
713 conn->pipe_data.samr.pipe_type == SAM_PIPE_GROUP &&
714 conn->pipe_data.samr.rid == group_rid) {
716 if (!connection_ok(conn)) {
717 /* Shutdown cli? Free conn? Allow retry of DC? */
718 DLIST_REMOVE(cm_conns, conn);
719 return NULL;
722 goto ok;
726 /* Create a domain handle to open a user handle from */
728 if (!cm_get_sam_dom_handle(domain, domain_sid))
729 return NULL;
731 for (conn = cm_conns; conn; conn = conn->next) {
732 if (strequal(conn->domain, domain) &&
733 strequal(conn->pipe_name, PIPE_SAMR) &&
734 conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
735 basic_conn = conn;
738 if (!basic_conn) {
739 DEBUG(0, ("No domain sam handle was created!\n"));
740 return NULL;
743 if (!(conn = (struct winbindd_cm_conn *)
744 malloc(sizeof(struct winbindd_cm_conn))))
745 return NULL;
747 ZERO_STRUCTP(conn);
749 fstrcpy(conn->domain, basic_conn->domain);
750 fstrcpy(conn->controller, basic_conn->controller);
751 fstrcpy(conn->pipe_name, basic_conn->pipe_name);
753 conn->pipe_data.samr.pipe_type = SAM_PIPE_GROUP;
754 conn->cli = basic_conn->cli;
755 conn->pipe_data.samr.rid = group_rid;
757 result = cli_samr_open_group(conn->cli, conn->cli->mem_ctx,
758 &basic_conn->pol, des_access, group_rid,
759 &conn->pol);
761 if (!NT_STATUS_IS_OK(result))
762 return NULL;
764 /* Add to list */
766 DLIST_ADD(cm_conns, conn);
769 hnd.pol = conn->pol;
770 hnd.cli = conn->cli;
772 return &hnd;
775 #endif
777 /* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
778 netlogon pipe as no handle is returned. */
780 NTSTATUS cm_get_netlogon_cli(char *domain, unsigned char *trust_passwd,
781 struct cli_state **cli)
783 NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
784 struct winbindd_cm_conn *conn;
786 if (!cli) {
787 return NT_STATUS_INVALID_PARAMETER;
790 /* Open an initial conection */
792 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn))) {
793 return result;
796 result = new_cli_nt_setup_creds(conn->cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
797 SEC_CHAN_WKSTA : SEC_CHAN_BDC, trust_passwd);
799 if (!NT_STATUS_IS_OK(result)) {
800 DEBUG(0, ("error connecting to domain password server: %s\n",
801 nt_errstr(result)));
803 /* Hit the cache code again. This cleans out the old connection and gets a new one */
804 if (conn->cli->fd == -1) {
805 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn))) {
806 return result;
809 /* Try again */
810 result = new_cli_nt_setup_creds(conn->cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
811 SEC_CHAN_WKSTA : SEC_CHAN_BDC, trust_passwd);
814 if (!NT_STATUS_IS_OK(result)) {
815 cli_shutdown(conn->cli);
816 DLIST_REMOVE(cm_conns, conn);
817 SAFE_FREE(conn);
818 return result;
822 *cli = conn->cli;
824 return result;
827 /* Dump the current connection status */
829 static void dump_conn_list(void)
831 struct winbindd_cm_conn *con;
833 DEBUG(0, ("\tDomain Controller Pipe\n"));
835 for(con = cm_conns; con; con = con->next) {
836 char *msg;
838 /* Display pipe info */
840 if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
841 DEBUG(0, ("Error: not enough memory!\n"));
842 } else {
843 DEBUG(0, ("%s\n", msg));
844 SAFE_FREE(msg);
849 void winbindd_cm_status(void)
851 /* List open connections */
853 DEBUG(0, ("winbindd connection manager status:\n"));
855 if (cm_conns)
856 dump_conn_list();
857 else
858 DEBUG(0, ("\tNo active connections\n"));