removed two unneeded files after Richard backed out these changes.
[Samba.git] / source / nsswitch / winbindd_cm.c
blob7024592f5b74b00b977705d883b16280cb234472
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 /* Global list of connections. Initially a DLIST but can become a hash
64 table or whatever later. */
66 struct winbindd_cm_conn {
67 struct winbindd_cm_conn *prev, *next;
68 fstring domain;
69 fstring controller;
70 fstring pipe_name;
71 struct cli_state *cli;
72 POLICY_HND pol;
75 static struct winbindd_cm_conn *cm_conns = NULL;
77 /* Get a domain controller name. Cache positive and negative lookups so we
78 don't go to the network too often when something is badly broken. */
80 #define GET_DC_NAME_CACHE_TIMEOUT 30 /* Seconds between dc lookups */
82 struct get_dc_name_cache {
83 fstring domain_name;
84 fstring srv_name;
85 time_t lookup_time;
86 struct get_dc_name_cache *prev, *next;
89 static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out)
91 static struct get_dc_name_cache *get_dc_name_cache;
92 struct get_dc_name_cache *dcc;
93 struct in_addr *ip_list, dc_ip;
94 int count, i;
96 /* Check the cache for previous lookups */
98 for (dcc = get_dc_name_cache; dcc; dcc = dcc->next) {
100 if (!strequal(domain, dcc->domain_name))
101 continue; /* Not our domain */
103 if ((time(NULL) - dcc->lookup_time) >
104 GET_DC_NAME_CACHE_TIMEOUT) {
106 /* Cache entry has expired, delete it */
108 DEBUG(10, ("get_dc_name_cache entry expired for %s\n", domain));
110 DLIST_REMOVE(get_dc_name_cache, dcc);
111 SAFE_FREE(dcc);
113 break;
116 /* Return a positive or negative lookup for this domain */
118 if (dcc->srv_name[0]) {
119 DEBUG(10, ("returning positive get_dc_name_cache entry for %s\n", domain));
120 fstrcpy(srv_name, dcc->srv_name);
121 return True;
122 } else {
123 DEBUG(10, ("returning negative get_dc_name_cache entry for %s\n", domain));
124 return False;
128 /* Add cache entry for this lookup. */
130 DEBUG(10, ("Creating get_dc_name_cache entry for %s\n", domain));
132 if (!(dcc = (struct get_dc_name_cache *)
133 malloc(sizeof(struct get_dc_name_cache))))
134 return False;
136 ZERO_STRUCTP(dcc);
138 fstrcpy(dcc->domain_name, domain);
139 dcc->lookup_time = time(NULL);
141 DLIST_ADD(get_dc_name_cache, dcc);
143 /* Lookup domain controller name. Try the real PDC first to avoid
144 SAM sync delays */
145 if (!get_dc_list(True, domain, &ip_list, &count)) {
146 if (!get_dc_list(False, domain, &ip_list, &count)) {
147 DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
148 return False;
152 /* Pick a nice close server */
153 /* Look for DC on local net */
155 for (i = 0; i < count; i++) {
156 if (!is_local_net(ip_list[i]))
157 continue;
159 if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
160 dc_ip = ip_list[i];
161 goto done;
163 zero_ip(&ip_list[i]);
167 * Secondly try and contact a random PDC/BDC.
170 i = (sys_random() % count);
172 if (!is_zero_ip(ip_list[i]) &&
173 name_status_find(domain, 0x1c, 0x20,
174 ip_list[i], srv_name)) {
175 dc_ip = ip_list[i];
176 goto done;
178 zero_ip(&ip_list[i]); /* Tried and failed. */
180 /* Finally return first DC that we can contact */
182 for (i = 0; i < count; i++) {
183 if (is_zero_ip(ip_list[i]))
184 continue;
186 if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
187 dc_ip = ip_list[i];
188 goto done;
192 /* No-one to talk to )-: */
193 return False; /* Boo-hoo */
195 done:
196 /* We have the netbios name and IP address of a domain controller.
197 Ideally we should sent a SAMLOGON request to determine whether
198 the DC is alive and kicking. If we can catch a dead DC before
199 performing a cli_connect() we can avoid a 30-second timeout. */
201 /* We have a name so make the cache entry positive now */
203 fstrcpy(dcc->srv_name, srv_name);
205 DEBUG(3, ("cm_get_dc_name: Returning DC %s (%s) for domain %s\n", srv_name,
206 inet_ntoa(dc_ip), domain));
208 *ip_out = dc_ip;
210 SAFE_FREE(ip_list);
212 return True;
215 /* Choose between anonymous or authenticated connections. We need to use
216 an authenticated connection if DCs have the RestrictAnonymous registry
217 entry set > 0, or the "Additional restrictions for anonymous
218 connections" set in the win2k Local Security Policy.
220 Caller to free() result in domain, username, password
223 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
225 *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
226 *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
227 *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
229 if (*username && **username) {
230 if (!*domain || !**domain) {
231 *domain = smb_xstrdup(lp_workgroup());
234 DEBUG(3, ("IPC$ connections done by user %s\\%s\n", *domain, *username));
235 } else {
236 DEBUG(3, ("IPC$ connections done anonymously\n"));
237 *username = smb_xstrdup("");
238 *domain = smb_xstrdup("");
239 *password = smb_xstrdup("");
243 /* Open a new smb pipe connection to a DC on a given domain. Cache
244 negative creation attempts so we don't try and connect to broken
245 machines too often. */
247 #define FAILED_CONNECTION_CACHE_TIMEOUT 30 /* Seconds between attempts */
249 struct failed_connection_cache {
250 fstring domain_name;
251 fstring controller;
252 time_t lookup_time;
253 NTSTATUS nt_status;
254 struct failed_connection_cache *prev, *next;
257 static struct failed_connection_cache *failed_connection_cache;
259 /* Add an entry to the failed conneciton cache */
261 static void add_failed_connection_entry(struct winbindd_cm_conn *new_conn, NTSTATUS result) {
262 struct failed_connection_cache *fcc;
264 SMB_ASSERT(!NT_STATUS_IS_OK(result));
266 /* Create negative lookup cache entry for this domain and controller */
268 if (!(fcc = (struct failed_connection_cache *)
269 malloc(sizeof(struct failed_connection_cache)))) {
270 DEBUG(0, ("malloc failed in add_failed_connection_entry!\n"));
271 return;
274 ZERO_STRUCTP(fcc);
276 fstrcpy(fcc->domain_name, new_conn->domain);
277 fstrcpy(fcc->controller, new_conn->controller);
278 fcc->lookup_time = time(NULL);
279 fcc->nt_status = result;
281 DLIST_ADD(failed_connection_cache, fcc);
284 /* Open a connction to the remote server, cache failures for 30 seconds */
286 static NTSTATUS cm_open_connection(const char *domain,const char *pipe_name,
287 struct winbindd_cm_conn *new_conn)
289 struct failed_connection_cache *fcc;
290 extern pstring global_myname;
291 NTSTATUS result;
292 char *ipc_username, *ipc_domain, *ipc_password;
293 struct in_addr dc_ip;
295 ZERO_STRUCT(dc_ip);
297 fstrcpy(new_conn->domain, domain);
298 fstrcpy(new_conn->pipe_name, pipe_name);
300 /* Look for a domain controller for this domain. Negative results
301 are cached so don't bother applying the caching for this
302 function just yet. */
304 if (!cm_get_dc_name(domain, new_conn->controller, &dc_ip)) {
305 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
306 add_failed_connection_entry(new_conn, result);
307 return result;
310 /* Return false if we have tried to look up this domain and netbios
311 name before and failed. */
313 for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {
315 if (!(strequal(domain, fcc->domain_name) &&
316 strequal(new_conn->controller, fcc->controller)))
317 continue; /* Not our domain */
319 if ((time(NULL) - fcc->lookup_time) >
320 FAILED_CONNECTION_CACHE_TIMEOUT) {
322 /* Cache entry has expired, delete it */
324 DEBUG(10, ("cm_open_connection cache entry expired for %s, %s\n", domain, new_conn->controller));
326 DLIST_REMOVE(failed_connection_cache, fcc);
327 free(fcc);
329 break;
332 /* The timeout hasn't expired yet so return false */
334 DEBUG(10, ("returning negative open_connection_cache entry for %s, %s\n", domain, new_conn->controller));
336 result = fcc->nt_status;
337 SMB_ASSERT(!NT_STATUS_IS_OK(result));
338 return result;
341 /* Initialise SMB connection */
343 cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
345 DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n",
346 new_conn->controller, global_myname, ipc_domain, ipc_username));
348 result = cli_full_connection(&(new_conn->cli), global_myname, new_conn->controller,
349 &dc_ip, 0, "IPC$",
350 "IPC", ipc_username, ipc_domain,
351 ipc_password, strlen(ipc_password));
353 SAFE_FREE(ipc_username);
354 SAFE_FREE(ipc_domain);
355 SAFE_FREE(ipc_password);
357 if (!NT_STATUS_IS_OK(result)) {
358 add_failed_connection_entry(new_conn, result);
359 return result;
362 if (!cli_nt_session_open (new_conn->cli, pipe_name)) {
363 result = NT_STATUS_PIPE_NOT_AVAILABLE;
364 add_failed_connection_entry(new_conn, result);
365 cli_shutdown(new_conn->cli);
366 return result;
369 return NT_STATUS_OK;
372 /* Return true if a connection is still alive */
374 static BOOL connection_ok(struct winbindd_cm_conn *conn)
376 if (!conn) {
377 smb_panic("Invalid paramater passed to conneciton_ok(): conn was NULL!\n");
378 return False;
381 if (!conn->cli) {
382 DEBUG(0, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
383 conn->controller, conn->domain, conn->pipe_name));
384 smb_panic("connection_ok: conn->cli was null!");
385 return False;
388 if (!conn->cli->initialised) {
389 DEBUG(0, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
390 conn->controller, conn->domain, conn->pipe_name));
391 smb_panic("connection_ok: conn->cli->initialised is False!");
392 return False;
395 if (conn->cli->fd == -1) {
396 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
397 conn->controller, conn->domain, conn->pipe_name));
398 return False;
401 return True;
404 /* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
406 static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_name, struct winbindd_cm_conn **conn_out)
408 struct winbindd_cm_conn *conn, conn_temp;
409 NTSTATUS result;
411 for (conn = cm_conns; conn; conn = conn->next) {
412 if (strequal(conn->domain, domain) &&
413 strequal(conn->pipe_name, pipe_name)) {
414 if (!connection_ok(conn)) {
415 if (conn->cli) {
416 cli_shutdown(conn->cli);
418 conn_temp.next = conn->next;
419 DLIST_REMOVE(cm_conns, conn);
420 SAFE_FREE(conn);
421 conn = &conn_temp; /* Just to keep the loop moving */
422 } else {
423 break;
428 if (!conn) {
429 if (!(conn = (struct winbindd_cm_conn *) malloc(sizeof(struct winbindd_cm_conn))))
430 return NT_STATUS_NO_MEMORY;
432 ZERO_STRUCTP(conn);
434 if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, pipe_name, conn))) {
435 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
436 domain, pipe_name, nt_errstr(result)));
437 SAFE_FREE(conn);
438 return result;
440 DLIST_ADD(cm_conns, conn);
443 *conn_out = conn;
444 return NT_STATUS_OK;
447 /* Return a LSA policy handle on a domain */
449 CLI_POLICY_HND *cm_get_lsa_handle(char *domain)
451 struct winbindd_cm_conn *conn;
452 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
453 NTSTATUS result;
454 static CLI_POLICY_HND hnd;
456 /* Look for existing connections */
458 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn))) {
459 return NULL;
462 /* This *shitty* code needs scrapping ! JRA */
463 if (policy_handle_is_valid(&conn->pol)) {
464 hnd.pol = conn->pol;
465 hnd.cli = conn->cli;
466 return &hnd;
469 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
470 des_access, &conn->pol);
472 if (!NT_STATUS_IS_OK(result)) {
473 /* Hit the cache code again. This cleans out the old connection and gets a new one */
474 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
475 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn))) {
476 return NULL;
479 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
480 des_access, &conn->pol);
483 if (!NT_STATUS_IS_OK(result)) {
484 cli_shutdown(conn->cli);
485 DLIST_REMOVE(cm_conns, conn);
486 SAFE_FREE(conn);
487 return NULL;
491 hnd.pol = conn->pol;
492 hnd.cli = conn->cli;
494 return &hnd;
497 /* Return a SAM policy handle on a domain */
499 CLI_POLICY_HND *cm_get_sam_handle(char *domain)
501 struct winbindd_cm_conn *conn;
502 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
503 NTSTATUS result;
504 static CLI_POLICY_HND hnd;
506 /* Look for existing connections */
508 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn))) {
509 return NULL;
512 /* This *shitty* code needs scrapping ! JRA */
513 if (policy_handle_is_valid(&conn->pol)) {
514 hnd.pol = conn->pol;
515 hnd.cli = conn->cli;
516 return &hnd;
518 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
519 des_access, &conn->pol);
521 if (!NT_STATUS_IS_OK(result)) {
522 /* Hit the cache code again. This cleans out the old connection and gets a new one */
523 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
524 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn))) {
525 return NULL;
528 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
529 des_access, &conn->pol);
532 if (!NT_STATUS_IS_OK(result)) {
533 cli_shutdown(conn->cli);
534 DLIST_REMOVE(cm_conns, conn);
535 SAFE_FREE(conn);
536 return NULL;
540 hnd.pol = conn->pol;
541 hnd.cli = conn->cli;
543 return &hnd;
546 #if 0 /* This code now *well* out of date */
548 /* Return a SAM domain policy handle on a domain */
550 CLI_POLICY_HND *cm_get_sam_dom_handle(char *domain, DOM_SID *domain_sid)
552 struct winbindd_cm_conn *conn, *basic_conn = NULL;
553 static CLI_POLICY_HND hnd;
554 NTSTATUS result;
555 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
557 /* Look for existing connections */
559 for (conn = cm_conns; conn; conn = conn->next) {
560 if (strequal(conn->domain, domain) &&
561 strequal(conn->pipe_name, PIPE_SAMR) &&
562 conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM) {
564 if (!connection_ok(conn)) {
565 /* Shutdown cli? Free conn? Allow retry of DC? */
566 DLIST_REMOVE(cm_conns, conn);
567 return NULL;
570 goto ok;
574 /* Create a basic handle to open a domain handle from */
576 if (!cm_get_sam_handle(domain))
577 return False;
579 for (conn = cm_conns; conn; conn = conn->next) {
580 if (strequal(conn->domain, domain) &&
581 strequal(conn->pipe_name, PIPE_SAMR) &&
582 conn->pipe_data.samr.pipe_type == SAM_PIPE_BASIC)
583 basic_conn = conn;
586 if (!(conn = (struct winbindd_cm_conn *)
587 malloc(sizeof(struct winbindd_cm_conn))))
588 return NULL;
590 ZERO_STRUCTP(conn);
592 fstrcpy(conn->domain, basic_conn->domain);
593 fstrcpy(conn->controller, basic_conn->controller);
594 fstrcpy(conn->pipe_name, basic_conn->pipe_name);
596 conn->pipe_data.samr.pipe_type = SAM_PIPE_DOM;
597 conn->cli = basic_conn->cli;
599 result = cli_samr_open_domain(conn->cli, conn->cli->mem_ctx,
600 &basic_conn->pol, des_access,
601 domain_sid, &conn->pol);
603 if (!NT_STATUS_IS_OK(result))
604 return NULL;
606 /* Add to list */
608 DLIST_ADD(cm_conns, conn);
611 hnd.pol = conn->pol;
612 hnd.cli = conn->cli;
614 return &hnd;
617 /* Return a SAM policy handle on a domain user */
619 CLI_POLICY_HND *cm_get_sam_user_handle(char *domain, DOM_SID *domain_sid,
620 uint32 user_rid)
622 struct winbindd_cm_conn *conn, *basic_conn = NULL;
623 static CLI_POLICY_HND hnd;
624 NTSTATUS result;
625 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
627 /* Look for existing connections */
629 for (conn = cm_conns; conn; conn = conn->next) {
630 if (strequal(conn->domain, domain) &&
631 strequal(conn->pipe_name, PIPE_SAMR) &&
632 conn->pipe_data.samr.pipe_type == SAM_PIPE_USER &&
633 conn->pipe_data.samr.rid == user_rid) {
635 if (!connection_ok(conn)) {
636 /* Shutdown cli? Free conn? Allow retry of DC? */
637 DLIST_REMOVE(cm_conns, conn);
638 return NULL;
641 goto ok;
645 /* Create a domain handle to open a user handle from */
647 if (!cm_get_sam_dom_handle(domain, domain_sid))
648 return NULL;
650 for (conn = cm_conns; conn; conn = conn->next) {
651 if (strequal(conn->domain, domain) &&
652 strequal(conn->pipe_name, PIPE_SAMR) &&
653 conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
654 basic_conn = conn;
657 if (!basic_conn) {
658 DEBUG(0, ("No domain sam handle was created!\n"));
659 return NULL;
662 if (!(conn = (struct winbindd_cm_conn *)
663 malloc(sizeof(struct winbindd_cm_conn))))
664 return NULL;
666 ZERO_STRUCTP(conn);
668 fstrcpy(conn->domain, basic_conn->domain);
669 fstrcpy(conn->controller, basic_conn->controller);
670 fstrcpy(conn->pipe_name, basic_conn->pipe_name);
672 conn->pipe_data.samr.pipe_type = SAM_PIPE_USER;
673 conn->cli = basic_conn->cli;
674 conn->pipe_data.samr.rid = user_rid;
676 result = cli_samr_open_user(conn->cli, conn->cli->mem_ctx,
677 &basic_conn->pol, des_access, user_rid,
678 &conn->pol);
680 if (!NT_STATUS_IS_OK(result))
681 return NULL;
683 /* Add to list */
685 DLIST_ADD(cm_conns, conn);
688 hnd.pol = conn->pol;
689 hnd.cli = conn->cli;
691 return &hnd;
694 /* Return a SAM policy handle on a domain group */
696 CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid,
697 uint32 group_rid)
699 struct winbindd_cm_conn *conn, *basic_conn = NULL;
700 static CLI_POLICY_HND hnd;
701 NTSTATUS result;
702 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
704 /* Look for existing connections */
706 for (conn = cm_conns; conn; conn = conn->next) {
707 if (strequal(conn->domain, domain) &&
708 strequal(conn->pipe_name, PIPE_SAMR) &&
709 conn->pipe_data.samr.pipe_type == SAM_PIPE_GROUP &&
710 conn->pipe_data.samr.rid == group_rid) {
712 if (!connection_ok(conn)) {
713 /* Shutdown cli? Free conn? Allow retry of DC? */
714 DLIST_REMOVE(cm_conns, conn);
715 return NULL;
718 goto ok;
722 /* Create a domain handle to open a user handle from */
724 if (!cm_get_sam_dom_handle(domain, domain_sid))
725 return NULL;
727 for (conn = cm_conns; conn; conn = conn->next) {
728 if (strequal(conn->domain, domain) &&
729 strequal(conn->pipe_name, PIPE_SAMR) &&
730 conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
731 basic_conn = conn;
734 if (!basic_conn) {
735 DEBUG(0, ("No domain sam handle was created!\n"));
736 return NULL;
739 if (!(conn = (struct winbindd_cm_conn *)
740 malloc(sizeof(struct winbindd_cm_conn))))
741 return NULL;
743 ZERO_STRUCTP(conn);
745 fstrcpy(conn->domain, basic_conn->domain);
746 fstrcpy(conn->controller, basic_conn->controller);
747 fstrcpy(conn->pipe_name, basic_conn->pipe_name);
749 conn->pipe_data.samr.pipe_type = SAM_PIPE_GROUP;
750 conn->cli = basic_conn->cli;
751 conn->pipe_data.samr.rid = group_rid;
753 result = cli_samr_open_group(conn->cli, conn->cli->mem_ctx,
754 &basic_conn->pol, des_access, group_rid,
755 &conn->pol);
757 if (!NT_STATUS_IS_OK(result))
758 return NULL;
760 /* Add to list */
762 DLIST_ADD(cm_conns, conn);
765 hnd.pol = conn->pol;
766 hnd.cli = conn->cli;
768 return &hnd;
771 #endif
773 /* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
774 netlogon pipe as no handle is returned. */
776 NTSTATUS cm_get_netlogon_cli(char *domain, unsigned char *trust_passwd,
777 struct cli_state **cli)
779 NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
780 struct winbindd_cm_conn *conn;
782 if (!cli) {
783 return NT_STATUS_INVALID_PARAMETER;
786 /* Open an initial conection */
788 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn))) {
789 return result;
792 result = new_cli_nt_setup_creds(conn->cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
793 SEC_CHAN_WKSTA : SEC_CHAN_BDC, trust_passwd);
795 if (!NT_STATUS_IS_OK(result)) {
796 DEBUG(0, ("error connecting to domain password server: %s\n",
797 nt_errstr(result)));
799 /* Hit the cache code again. This cleans out the old connection and gets a new one */
800 if (conn->cli->fd == -1) {
801 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn))) {
802 return result;
805 /* Try again */
806 result = new_cli_nt_setup_creds(conn->cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
807 SEC_CHAN_WKSTA : SEC_CHAN_BDC, trust_passwd);
810 if (!NT_STATUS_IS_OK(result)) {
811 cli_shutdown(conn->cli);
812 DLIST_REMOVE(cm_conns, conn);
813 SAFE_FREE(conn);
814 return result;
818 *cli = conn->cli;
820 return result;
823 /* Dump the current connection status */
825 static void dump_conn_list(void)
827 struct winbindd_cm_conn *con;
829 DEBUG(0, ("\tDomain Controller Pipe\n"));
831 for(con = cm_conns; con; con = con->next) {
832 char *msg;
834 /* Display pipe info */
836 if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
837 DEBUG(0, ("Error: not enough memory!\n"));
838 } else {
839 DEBUG(0, ("%s\n", msg));
840 SAFE_FREE(msg);
845 void winbindd_cm_status(void)
847 /* List open connections */
849 DEBUG(0, ("winbindd connection manager status:\n"));
851 if (cm_conns)
852 dump_conn_list();
853 else
854 DEBUG(0, ("\tNo active connections\n"));