merge of get_dc_name()-like code from APP_HEAD; better support password server =...
[Samba/gbeck.git] / source3 / nsswitch / winbindd_cm.c
blob075da1e2b2e9a47b41c902ef30f53de4c813ce50
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon connection manager
6 Copyright (C) Tim Potter 2001
7 Copyright (C) Andrew Bartlett 2002
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 We need to manage connections to domain controllers without having to
26 mess up the main winbindd code with other issues. The aim of the
27 connection manager is to:
29 - make connections to domain controllers and cache them
30 - re-establish connections when networks or servers go down
31 - centralise the policy on connection timeouts, domain controller
32 selection etc
33 - manage re-entrancy for when winbindd becomes able to handle
34 multiple outstanding rpc requests
36 Why not have connection management as part of the rpc layer like tng?
37 Good question. This code may morph into libsmb/rpc_cache.c or something
38 like that but at the moment it's simply staying as part of winbind. I
39 think the TNG architecture of forcing every user of the rpc layer to use
40 the connection caching system is a bad idea. It should be an optional
41 method of using the routines.
43 The TNG design is quite good but I disagree with some aspects of the
44 implementation. -tpot
49 TODO:
51 - I'm pretty annoyed by all the make_nmb_name() stuff. It should be
52 moved down into another function.
54 - There needs to be a utility function in libsmb/namequery.c that does
55 cm_get_dc_name()
57 - Take care when destroying cli_structs as they can be shared between
58 various sam handles.
62 #include "winbindd.h"
64 #undef DBGC_CLASS
65 #define DBGC_CLASS DBGC_WINBIND
67 /* Global list of connections. Initially a DLIST but can become a hash
68 table or whatever later. */
70 struct winbindd_cm_conn {
71 struct winbindd_cm_conn *prev, *next;
72 fstring domain;
73 fstring controller;
74 fstring pipe_name;
75 struct cli_state *cli;
76 POLICY_HND pol;
79 static struct winbindd_cm_conn *cm_conns = NULL;
81 /* Get a domain controller name. Cache positive and negative lookups so we
82 don't go to the network too often when something is badly broken. */
84 #define GET_DC_NAME_CACHE_TIMEOUT 30 /* Seconds between dc lookups */
86 struct get_dc_name_cache {
87 fstring domain_name;
88 fstring srv_name;
89 time_t lookup_time;
90 struct get_dc_name_cache *prev, *next;
95 find the DC for a domain using methods appropriate for a ADS domain
97 static BOOL cm_ads_find_dc(const char *domain, struct in_addr *dc_ip, fstring srv_name)
99 ADS_STRUCT *ads;
100 const char *realm = domain;
102 if (strcasecmp(realm, lp_workgroup()) == 0) {
103 realm = lp_realm();
106 ads = ads_init(realm, domain, NULL);
107 if (!ads) {
108 return False;
111 /* we don't need to bind, just connect */
112 ads->auth.flags |= ADS_AUTH_NO_BIND;
114 DEBUG(4,("cm_ads_find_dc: domain=%s\n", domain));
116 #ifdef HAVE_ADS
117 /* a full ads_connect() is actually overkill, as we don't srictly need
118 to do the SASL auth in order to get the info we need, but libads
119 doesn't offer a better way right now */
120 ads_connect(ads);
121 #endif
123 if (!ads->config.realm) {
124 return False;
127 fstrcpy(srv_name, ads->config.ldap_server_name);
128 strupper(srv_name);
129 *dc_ip = ads->ldap_ip;
130 ads_destroy(&ads);
132 DEBUG(4,("cm_ads_find_dc: using server='%s' IP=%s\n",
133 srv_name, inet_ntoa(*dc_ip)));
135 return True;
140 static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out)
142 static struct get_dc_name_cache *get_dc_name_cache;
143 struct get_dc_name_cache *dcc;
144 struct in_addr dc_ip;
145 BOOL ret;
147 /* Check the cache for previous lookups */
149 for (dcc = get_dc_name_cache; dcc; dcc = dcc->next) {
151 if (!strequal(domain, dcc->domain_name))
152 continue; /* Not our domain */
154 if ((time(NULL) - dcc->lookup_time) >
155 GET_DC_NAME_CACHE_TIMEOUT) {
157 /* Cache entry has expired, delete it */
159 DEBUG(10, ("get_dc_name_cache entry expired for %s\n", domain));
161 DLIST_REMOVE(get_dc_name_cache, dcc);
162 SAFE_FREE(dcc);
164 break;
167 /* Return a positive or negative lookup for this domain */
169 if (dcc->srv_name[0]) {
170 DEBUG(10, ("returning positive get_dc_name_cache entry for %s\n", domain));
171 fstrcpy(srv_name, dcc->srv_name);
172 return True;
173 } else {
174 DEBUG(10, ("returning negative get_dc_name_cache entry for %s\n", domain));
175 return False;
179 /* Add cache entry for this lookup. */
181 DEBUG(10, ("Creating get_dc_name_cache entry for %s\n", domain));
183 if (!(dcc = (struct get_dc_name_cache *)
184 malloc(sizeof(struct get_dc_name_cache))))
185 return False;
187 ZERO_STRUCTP(dcc);
189 fstrcpy(dcc->domain_name, domain);
190 dcc->lookup_time = time(NULL);
192 DLIST_ADD(get_dc_name_cache, dcc);
194 zero_ip(&dc_ip);
196 ret = False;
197 if (lp_security() == SEC_ADS) {
198 ret = cm_ads_find_dc(domain, &dc_ip, srv_name);
200 if (!ret) {
201 /* fall back on rpc methods if the ADS methods fail */
202 ret = rpc_find_dc(domain, srv_name, &dc_ip);
205 if (!ret) {
206 return False;
209 /* We have a name so make the cache entry positive now */
210 fstrcpy(dcc->srv_name, srv_name);
212 DEBUG(3, ("cm_get_dc_name: Returning DC %s (%s) for domain %s\n", srv_name,
213 inet_ntoa(dc_ip), domain));
215 *ip_out = dc_ip;
217 return True;
220 /* Choose between anonymous or authenticated connections. We need to use
221 an authenticated connection if DCs have the RestrictAnonymous registry
222 entry set > 0, or the "Additional restrictions for anonymous
223 connections" set in the win2k Local Security Policy.
225 Caller to free() result in domain, username, password
228 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
230 *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
231 *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
232 *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
234 if (*username && **username) {
236 if (!*domain || !**domain)
237 *domain = smb_xstrdup(lp_workgroup());
239 if (!*password || !**password)
240 *password = smb_xstrdup("");
242 DEBUG(3, ("IPC$ connections done by user %s\\%s\n",
243 *domain, *username));
245 } else {
246 DEBUG(3, ("IPC$ connections done anonymously\n"));
247 *username = smb_xstrdup("");
248 *domain = smb_xstrdup("");
249 *password = smb_xstrdup("");
253 /* Open a new smb pipe connection to a DC on a given domain. Cache
254 negative creation attempts so we don't try and connect to broken
255 machines too often. */
257 #define FAILED_CONNECTION_CACHE_TIMEOUT 30 /* Seconds between attempts */
259 struct failed_connection_cache {
260 fstring domain_name;
261 fstring controller;
262 time_t lookup_time;
263 NTSTATUS nt_status;
264 struct failed_connection_cache *prev, *next;
267 static struct failed_connection_cache *failed_connection_cache;
269 /* Add an entry to the failed conneciton cache */
271 static void add_failed_connection_entry(struct winbindd_cm_conn *new_conn,
272 NTSTATUS result)
274 struct failed_connection_cache *fcc;
276 SMB_ASSERT(!NT_STATUS_IS_OK(result));
278 /* Check we already aren't in the cache */
280 for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {
281 if (strequal(fcc->domain_name, new_conn->domain)) {
282 DEBUG(10, ("domain %s already tried and failed\n",
283 fcc->domain_name));
284 return;
288 /* Create negative lookup cache entry for this domain and controller */
290 if (!(fcc = (struct failed_connection_cache *)
291 malloc(sizeof(struct failed_connection_cache)))) {
292 DEBUG(0, ("malloc failed in add_failed_connection_entry!\n"));
293 return;
296 ZERO_STRUCTP(fcc);
298 fstrcpy(fcc->domain_name, new_conn->domain);
299 fstrcpy(fcc->controller, new_conn->controller);
300 fcc->lookup_time = time(NULL);
301 fcc->nt_status = result;
303 DLIST_ADD(failed_connection_cache, fcc);
306 /* Open a connction to the remote server, cache failures for 30 seconds */
308 static NTSTATUS cm_open_connection(const char *domain, const int pipe_index,
309 struct winbindd_cm_conn *new_conn)
311 struct failed_connection_cache *fcc;
312 NTSTATUS result;
313 char *ipc_username, *ipc_domain, *ipc_password;
314 struct in_addr dc_ip;
315 int i;
316 BOOL retry = True;
318 ZERO_STRUCT(dc_ip);
320 fstrcpy(new_conn->domain, domain);
321 fstrcpy(new_conn->pipe_name, get_pipe_name_from_index(pipe_index));
323 /* Look for a domain controller for this domain. Negative results
324 are cached so don't bother applying the caching for this
325 function just yet. */
327 if (!cm_get_dc_name(domain, new_conn->controller, &dc_ip)) {
328 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
329 add_failed_connection_entry(new_conn, result);
330 return result;
333 /* Return false if we have tried to look up this domain and netbios
334 name before and failed. */
336 for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {
338 if (!(strequal(domain, fcc->domain_name) &&
339 strequal(new_conn->controller, fcc->controller)))
340 continue; /* Not our domain */
342 if ((time(NULL) - fcc->lookup_time) >
343 FAILED_CONNECTION_CACHE_TIMEOUT) {
345 /* Cache entry has expired, delete it */
347 DEBUG(10, ("cm_open_connection cache entry expired for %s, %s\n", domain, new_conn->controller));
349 DLIST_REMOVE(failed_connection_cache, fcc);
350 free(fcc);
352 break;
355 /* The timeout hasn't expired yet so return false */
357 DEBUG(10, ("returning negative open_connection_cache entry for %s, %s\n", domain, new_conn->controller));
359 result = fcc->nt_status;
360 SMB_ASSERT(!NT_STATUS_IS_OK(result));
361 return result;
364 /* Initialise SMB connection */
366 cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
368 DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n",
369 new_conn->controller, global_myname(), ipc_domain, ipc_username));
371 for (i = 0; retry && (i < 3); i++) {
373 if (!secrets_named_mutex(new_conn->controller, 10)) {
374 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n", new_conn->controller));
375 continue;
378 result = cli_full_connection(&new_conn->cli, global_myname(), new_conn->controller,
379 &dc_ip, 0, "IPC$", "IPC", ipc_username, ipc_domain,
380 ipc_password, 0, &retry);
382 secrets_named_mutex_release(new_conn->controller);
384 if (NT_STATUS_IS_OK(result))
385 break;
388 SAFE_FREE(ipc_username);
389 SAFE_FREE(ipc_domain);
390 SAFE_FREE(ipc_password);
392 if (!NT_STATUS_IS_OK(result)) {
393 add_failed_connection_entry(new_conn, result);
394 return result;
397 if ( !cli_nt_session_open (new_conn->cli, pipe_index) ) {
398 result = NT_STATUS_PIPE_NOT_AVAILABLE;
400 * only cache a failure if we are not trying to open the
401 * **win2k** specific lsarpc UUID. This could be an NT PDC
402 * and therefore a failure is normal. This should probably
403 * be abstracted to a check for 2k specific pipes and wondering
404 * if the PDC is an NT4 box. but since there is only one 2k
405 * specific UUID right now, i'm not going to bother. --jerry
407 if ( !is_win2k_pipe(pipe_index) )
408 add_failed_connection_entry(new_conn, result);
409 cli_shutdown(new_conn->cli);
410 return result;
413 return NT_STATUS_OK;
416 /* Return true if a connection is still alive */
418 static BOOL connection_ok(struct winbindd_cm_conn *conn)
420 if (!conn) {
421 smb_panic("Invalid paramater passed to conneciton_ok(): conn was NULL!\n");
422 return False;
425 if (!conn->cli) {
426 DEBUG(0, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
427 conn->controller, conn->domain, conn->pipe_name));
428 smb_panic("connection_ok: conn->cli was null!");
429 return False;
432 if (!conn->cli->initialised) {
433 DEBUG(0, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
434 conn->controller, conn->domain, conn->pipe_name));
435 smb_panic("connection_ok: conn->cli->initialised is False!");
436 return False;
439 if (conn->cli->fd == -1) {
440 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
441 conn->controller, conn->domain, conn->pipe_name));
442 return False;
445 return True;
448 /* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
450 static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_name, struct winbindd_cm_conn **conn_out)
452 struct winbindd_cm_conn *conn, conn_temp;
453 NTSTATUS result;
455 for (conn = cm_conns; conn; conn = conn->next) {
456 if (strequal(conn->domain, domain) &&
457 strequal(conn->pipe_name, pipe_name)) {
458 if (!connection_ok(conn)) {
459 if (conn->cli) {
460 cli_shutdown(conn->cli);
462 ZERO_STRUCT(conn_temp);
463 conn_temp.next = conn->next;
464 DLIST_REMOVE(cm_conns, conn);
465 SAFE_FREE(conn);
466 conn = &conn_temp; /* Just to keep the loop moving */
467 } else {
468 break;
473 if (!conn) {
474 if (!(conn = malloc(sizeof(*conn))))
475 return NT_STATUS_NO_MEMORY;
477 ZERO_STRUCTP(conn);
479 if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
480 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
481 domain, pipe_name, nt_errstr(result)));
482 SAFE_FREE(conn);
483 return result;
485 DLIST_ADD(cm_conns, conn);
488 *conn_out = conn;
489 return NT_STATUS_OK;
493 /**********************************************************************************
494 **********************************************************************************/
496 BOOL cm_check_for_native_mode_win2k( const char *domain )
498 NTSTATUS result;
499 struct winbindd_cm_conn conn;
500 DS_DOMINFO_CTR ctr;
501 BOOL ret = False;
503 ZERO_STRUCT( conn );
504 ZERO_STRUCT( ctr );
507 if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) )
509 DEBUG(5, ("cm_check_for_native_mode_win2k: Could not open a connection to %s for PIPE_LSARPC (%s)\n",
510 domain, nt_errstr(result)));
511 return False;
514 if ( conn.cli ) {
515 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli,
516 conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) )
518 ret = False;
519 goto done;
523 if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING)
524 && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
526 ret = True;
529 done:
530 if ( conn.cli )
531 cli_shutdown( conn.cli );
533 return ret;
538 /* Return a LSA policy handle on a domain */
540 CLI_POLICY_HND *cm_get_lsa_handle(const char *domain)
542 struct winbindd_cm_conn *conn;
543 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
544 NTSTATUS result;
545 static CLI_POLICY_HND hnd;
547 /* Look for existing connections */
549 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn))) {
550 return NULL;
553 /* This *shitty* code needs scrapping ! JRA */
554 if (policy_handle_is_valid(&conn->pol)) {
555 hnd.pol = conn->pol;
556 hnd.cli = conn->cli;
557 return &hnd;
560 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
561 des_access, &conn->pol);
563 if (!NT_STATUS_IS_OK(result)) {
564 /* Hit the cache code again. This cleans out the old connection and gets a new one */
565 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
566 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn))) {
567 return NULL;
570 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
571 des_access, &conn->pol);
574 if (!NT_STATUS_IS_OK(result)) {
575 cli_shutdown(conn->cli);
576 DLIST_REMOVE(cm_conns, conn);
577 SAFE_FREE(conn);
578 return NULL;
582 hnd.pol = conn->pol;
583 hnd.cli = conn->cli;
585 return &hnd;
588 /* Return a SAM policy handle on a domain */
590 CLI_POLICY_HND *cm_get_sam_handle(char *domain)
592 struct winbindd_cm_conn *conn;
593 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
594 NTSTATUS result;
595 static CLI_POLICY_HND hnd;
597 /* Look for existing connections */
599 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn))) {
600 return NULL;
603 /* This *shitty* code needs scrapping ! JRA */
604 if (policy_handle_is_valid(&conn->pol)) {
605 hnd.pol = conn->pol;
606 hnd.cli = conn->cli;
607 return &hnd;
609 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
610 des_access, &conn->pol);
612 if (!NT_STATUS_IS_OK(result)) {
613 /* Hit the cache code again. This cleans out the old connection and gets a new one */
614 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
615 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn))) {
616 return NULL;
619 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
620 des_access, &conn->pol);
623 if (!NT_STATUS_IS_OK(result)) {
624 cli_shutdown(conn->cli);
625 DLIST_REMOVE(cm_conns, conn);
626 SAFE_FREE(conn);
627 return NULL;
631 hnd.pol = conn->pol;
632 hnd.cli = conn->cli;
634 return &hnd;
637 #if 0 /* This code now *well* out of date */
639 /* Return a SAM domain policy handle on a domain */
641 CLI_POLICY_HND *cm_get_sam_dom_handle(char *domain, DOM_SID *domain_sid)
643 struct winbindd_cm_conn *conn, *basic_conn = NULL;
644 static CLI_POLICY_HND hnd;
645 NTSTATUS result;
646 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
648 /* Look for existing connections */
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) {
655 if (!connection_ok(conn)) {
656 /* Shutdown cli? Free conn? Allow retry of DC? */
657 DLIST_REMOVE(cm_conns, conn);
658 return NULL;
661 goto ok;
665 /* Create a basic handle to open a domain handle from */
667 if (!cm_get_sam_handle(domain))
668 return False;
670 for (conn = cm_conns; conn; conn = conn->next) {
671 if (strequal(conn->domain, domain) &&
672 strequal(conn->pipe_name, PIPE_SAMR) &&
673 conn->pipe_data.samr.pipe_type == SAM_PIPE_BASIC)
674 basic_conn = conn;
677 if (!(conn = (struct winbindd_cm_conn *)
678 malloc(sizeof(struct winbindd_cm_conn))))
679 return NULL;
681 ZERO_STRUCTP(conn);
683 fstrcpy(conn->domain, basic_conn->domain);
684 fstrcpy(conn->controller, basic_conn->controller);
685 fstrcpy(conn->pipe_name, basic_conn->pipe_name);
687 conn->pipe_data.samr.pipe_type = SAM_PIPE_DOM;
688 conn->cli = basic_conn->cli;
690 result = cli_samr_open_domain(conn->cli, conn->cli->mem_ctx,
691 &basic_conn->pol, des_access,
692 domain_sid, &conn->pol);
694 if (!NT_STATUS_IS_OK(result))
695 return NULL;
697 /* Add to list */
699 DLIST_ADD(cm_conns, conn);
702 hnd.pol = conn->pol;
703 hnd.cli = conn->cli;
705 return &hnd;
708 /* Return a SAM policy handle on a domain user */
710 CLI_POLICY_HND *cm_get_sam_user_handle(char *domain, DOM_SID *domain_sid,
711 uint32 user_rid)
713 struct winbindd_cm_conn *conn, *basic_conn = NULL;
714 static CLI_POLICY_HND hnd;
715 NTSTATUS result;
716 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
718 /* Look for existing connections */
720 for (conn = cm_conns; conn; conn = conn->next) {
721 if (strequal(conn->domain, domain) &&
722 strequal(conn->pipe_name, PIPE_SAMR) &&
723 conn->pipe_data.samr.pipe_type == SAM_PIPE_USER &&
724 conn->pipe_data.samr.rid == user_rid) {
726 if (!connection_ok(conn)) {
727 /* Shutdown cli? Free conn? Allow retry of DC? */
728 DLIST_REMOVE(cm_conns, conn);
729 return NULL;
732 goto ok;
736 /* Create a domain handle to open a user handle from */
738 if (!cm_get_sam_dom_handle(domain, domain_sid))
739 return NULL;
741 for (conn = cm_conns; conn; conn = conn->next) {
742 if (strequal(conn->domain, domain) &&
743 strequal(conn->pipe_name, PIPE_SAMR) &&
744 conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
745 basic_conn = conn;
748 if (!basic_conn) {
749 DEBUG(0, ("No domain sam handle was created!\n"));
750 return NULL;
753 if (!(conn = (struct winbindd_cm_conn *)
754 malloc(sizeof(struct winbindd_cm_conn))))
755 return NULL;
757 ZERO_STRUCTP(conn);
759 fstrcpy(conn->domain, basic_conn->domain);
760 fstrcpy(conn->controller, basic_conn->controller);
761 fstrcpy(conn->pipe_name, basic_conn->pipe_name);
763 conn->pipe_data.samr.pipe_type = SAM_PIPE_USER;
764 conn->cli = basic_conn->cli;
765 conn->pipe_data.samr.rid = user_rid;
767 result = cli_samr_open_user(conn->cli, conn->cli->mem_ctx,
768 &basic_conn->pol, des_access, user_rid,
769 &conn->pol);
771 if (!NT_STATUS_IS_OK(result))
772 return NULL;
774 /* Add to list */
776 DLIST_ADD(cm_conns, conn);
779 hnd.pol = conn->pol;
780 hnd.cli = conn->cli;
782 return &hnd;
785 /* Return a SAM policy handle on a domain group */
787 CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid,
788 uint32 group_rid)
790 struct winbindd_cm_conn *conn, *basic_conn = NULL;
791 static CLI_POLICY_HND hnd;
792 NTSTATUS result;
793 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
795 /* Look for existing connections */
797 for (conn = cm_conns; conn; conn = conn->next) {
798 if (strequal(conn->domain, domain) &&
799 strequal(conn->pipe_name, PIPE_SAMR) &&
800 conn->pipe_data.samr.pipe_type == SAM_PIPE_GROUP &&
801 conn->pipe_data.samr.rid == group_rid) {
803 if (!connection_ok(conn)) {
804 /* Shutdown cli? Free conn? Allow retry of DC? */
805 DLIST_REMOVE(cm_conns, conn);
806 return NULL;
809 goto ok;
813 /* Create a domain handle to open a user handle from */
815 if (!cm_get_sam_dom_handle(domain, domain_sid))
816 return NULL;
818 for (conn = cm_conns; conn; conn = conn->next) {
819 if (strequal(conn->domain, domain) &&
820 strequal(conn->pipe_name, PIPE_SAMR) &&
821 conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
822 basic_conn = conn;
825 if (!basic_conn) {
826 DEBUG(0, ("No domain sam handle was created!\n"));
827 return NULL;
830 if (!(conn = (struct winbindd_cm_conn *)
831 malloc(sizeof(struct winbindd_cm_conn))))
832 return NULL;
834 ZERO_STRUCTP(conn);
836 fstrcpy(conn->domain, basic_conn->domain);
837 fstrcpy(conn->controller, basic_conn->controller);
838 fstrcpy(conn->pipe_name, basic_conn->pipe_name);
840 conn->pipe_data.samr.pipe_type = SAM_PIPE_GROUP;
841 conn->cli = basic_conn->cli;
842 conn->pipe_data.samr.rid = group_rid;
844 result = cli_samr_open_group(conn->cli, conn->cli->mem_ctx,
845 &basic_conn->pol, des_access, group_rid,
846 &conn->pol);
848 if (!NT_STATUS_IS_OK(result))
849 return NULL;
851 /* Add to list */
853 DLIST_ADD(cm_conns, conn);
856 hnd.pol = conn->pol;
857 hnd.cli = conn->cli;
859 return &hnd;
862 #endif
864 /* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
865 netlogon pipe as no handle is returned. */
867 NTSTATUS cm_get_netlogon_cli(const char *domain, const unsigned char *trust_passwd,
868 struct cli_state **cli)
870 NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
871 struct winbindd_cm_conn *conn;
872 uint32 neg_flags = 0x000001ff;
874 if (!cli) {
875 return NT_STATUS_INVALID_PARAMETER;
878 /* Open an initial conection */
880 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn))) {
881 return result;
884 result = cli_nt_setup_creds(conn->cli, get_sec_chan(), trust_passwd, &neg_flags, 2);
886 if (!NT_STATUS_IS_OK(result)) {
887 DEBUG(0, ("error connecting to domain password server: %s\n",
888 nt_errstr(result)));
890 /* Hit the cache code again. This cleans out the old connection and gets a new one */
891 if (conn->cli->fd == -1) {
892 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn))) {
893 return result;
896 /* Try again */
897 result = cli_nt_setup_creds( conn->cli, get_sec_chan(),trust_passwd, &neg_flags, 2);
900 if (!NT_STATUS_IS_OK(result)) {
901 cli_shutdown(conn->cli);
902 DLIST_REMOVE(cm_conns, conn);
903 SAFE_FREE(conn);
904 return result;
908 *cli = conn->cli;
910 return result;
913 /* Dump the current connection status */
915 static void dump_conn_list(void)
917 struct winbindd_cm_conn *con;
919 DEBUG(0, ("\tDomain Controller Pipe\n"));
921 for(con = cm_conns; con; con = con->next) {
922 char *msg;
924 /* Display pipe info */
926 if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
927 DEBUG(0, ("Error: not enough memory!\n"));
928 } else {
929 DEBUG(0, ("%s\n", msg));
930 SAFE_FREE(msg);
935 void winbindd_cm_status(void)
937 /* List open connections */
939 DEBUG(0, ("winbindd connection manager status:\n"));
941 if (cm_conns)
942 dump_conn_list();
943 else
944 DEBUG(0, ("\tNo active connections\n"));