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
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
51 - I'm pretty annoyed by all the make_nmb_name() stuff. It should be
52 moved down into another function.
54 - Take care when destroying cli_structs as they can be shared between
63 #define DBGC_CLASS DBGC_WINBIND
65 /* Global list of connections. Initially a DLIST but can become a hash
66 table or whatever later. */
68 struct winbindd_cm_conn {
69 struct winbindd_cm_conn *prev, *next;
73 struct cli_state *cli;
77 static struct winbindd_cm_conn *cm_conns = NULL;
79 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain,
80 const char *pipe_name,
81 struct winbindd_cm_conn **conn_out);
83 /* Choose between anonymous or authenticated connections. We need to use
84 an authenticated connection if DCs have the RestrictAnonymous registry
85 entry set > 0, or the "Additional restrictions for anonymous
86 connections" set in the win2k Local Security Policy.
88 Caller to free() result in domain, username, password
91 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
93 *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
94 *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
95 *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
97 if (*username && **username) {
99 if (!*domain || !**domain)
100 *domain = smb_xstrdup(lp_workgroup());
102 if (!*password || !**password)
103 *password = smb_xstrdup("");
105 DEBUG(3, ("IPC$ connections done by user %s\\%s\n",
106 *domain, *username));
109 DEBUG(3, ("IPC$ connections done anonymously\n"));
110 *username = smb_xstrdup("");
111 *domain = smb_xstrdup("");
112 *password = smb_xstrdup("");
117 setup for schannel on any pipes opened on this connection
119 static NTSTATUS setup_schannel( struct cli_state *cli, const char *domain )
122 uchar trust_password[16];
123 uint32 sec_channel_type;
127 /* use the domain trust password if we're on a DC
128 and this is not our domain */
130 if ( IS_DC && !strequal(domain, lp_workgroup()) ) {
133 if ( !secrets_fetch_trusted_domain_password( domain,
136 return NT_STATUS_UNSUCCESSFUL;
139 sec_channel_type = SEC_CHAN_DOMAIN;
140 E_md4hash(pass, trust_password);
144 if (!secrets_fetch_trust_account_password(lp_workgroup(),
145 trust_password, NULL, &sec_channel_type))
147 return NT_STATUS_UNSUCCESSFUL;
151 ret = cli_nt_setup_netsec(cli, sec_channel_type,
152 AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, trust_password);
157 static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
158 fstring dcname, struct in_addr *dc_ip)
160 struct winbindd_domain *our_domain;
162 struct winbindd_cm_conn *conn;
174 if ((our_domain = find_our_domain()) == NULL)
177 result = get_connection_from_cache(our_domain, PIPE_NETLOGON, &conn);
178 if (!NT_STATUS_IS_OK(result))
181 if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL)
184 result = cli_netlogon_getdcname(conn->cli, mem_ctx, domain->name, tmp);
186 talloc_destroy(mem_ctx);
188 if (!NT_STATUS_IS_OK(result))
191 /* cli_netlogon_getdcname gives us a name with \\ */
193 if (*p == '\\') p+=1;
194 if (*p == '\\') p+=1;
198 if (!resolve_name(dcname, dc_ip, 0x20))
204 /************************************************************************
205 Given a fd with a just-connected TCP connection to a DC, open a connection
207 ************************************************************************/
209 static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
211 const int pipe_index,
212 const char *controller,
213 struct cli_state **cli,
216 char *machine_password, *machine_krb5_principal;
217 char *ipc_username, *ipc_domain, *ipc_password;
220 BOOL add_failed_connection = True;
222 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
224 struct sockaddr peeraddr;
225 socklen_t peeraddr_len;
227 struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
229 machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL,
232 if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(),
234 SAFE_FREE(machine_password);
235 return NT_STATUS_NO_MEMORY;
238 cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
242 got_mutex = secrets_named_mutex(controller,
243 WINBIND_SERVER_MUTEX_WAIT_TIME);
246 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n",
248 result = NT_STATUS_POSSIBLE_DEADLOCK;
252 if ((*cli = cli_initialise(NULL)) == NULL) {
253 DEBUG(1, ("Could not cli_initialize\n"));
254 result = NT_STATUS_NO_MEMORY;
258 (*cli)->timeout = 10000; /* 10 seconds */
260 fstrcpy((*cli)->desthost, controller);
261 (*cli)->use_kerberos = True;
263 peeraddr_len = sizeof(peeraddr);
265 if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
266 (peeraddr_len != sizeof(struct sockaddr_in)) ||
267 (peeraddr_in->sin_family != PF_INET))
269 DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
273 if (ntohs(peeraddr_in->sin_port) == 139) {
274 struct nmb_name calling;
275 struct nmb_name called;
277 make_nmb_name(&calling, global_myname(), 0x0);
278 make_nmb_name(&called, "*SMBSERVER", 0x20);
280 if (!cli_session_request(*cli, &calling, &called)) {
281 DEBUG(8, ("cli_session_request failed for %s\n",
287 cli_setup_signing_state(*cli, Undefined);
289 if (!cli_negprot(*cli)) {
290 DEBUG(1, ("cli_negprot failed\n"));
297 if ((lp_security() == SEC_ADS)
298 && ((*cli)->protocol >= PROTOCOL_NT1 &&
299 (*cli)->capabilities & CAP_EXTENDED_SECURITY)) {
301 ADS_STATUS ads_status;
302 (*cli)->use_kerberos = True;
303 DEBUG(5, ("connecting to %s from %s with kerberos principal "
304 "[%s]\n", controller, global_myname(),
305 machine_krb5_principal));
307 ads_status = cli_session_setup_spnego(*cli,
308 machine_krb5_principal,
312 if (!ADS_ERR_OK(ads_status))
313 DEBUG(4,("failed kerberos session setup with %s\n",
314 ads_errstr(ads_status)));
316 result = ads_ntstatus(ads_status);
319 if (NT_STATUS_IS_OK(result))
320 goto session_setup_done;
322 /* Fall back to non-kerberos session setup */
324 (*cli)->use_kerberos = False;
326 if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
327 (strlen(ipc_username) > 0)) {
329 /* Only try authenticated if we have a username */
331 DEBUG(5, ("connecting to %s from %s with username "
332 "[%s]\\[%s]\n", controller, global_myname(),
333 ipc_domain, ipc_username));
335 if (cli_session_setup(*cli, ipc_username,
336 ipc_password, strlen(ipc_password)+1,
337 ipc_password, strlen(ipc_password)+1,
339 DEBUG(5, ("authenticated session setup failed\n"));
340 goto session_setup_done;
344 /* Fall back to anonymous connection, this might fail later */
346 if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) {
347 DEBUG(5, ("Connected anonymously\n"));
348 goto session_setup_done;
351 result = cli_nt_error(*cli);
353 if (NT_STATUS_IS_OK(result))
354 result = NT_STATUS_UNSUCCESSFUL;
356 /* We can't session setup */
362 if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
364 result = cli_nt_error(*cli);
366 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
368 if (NT_STATUS_IS_OK(result))
369 result = NT_STATUS_UNSUCCESSFUL;
375 secrets_named_mutex_release(controller);
379 if (domain->primary || IS_DC) {
380 NTSTATUS status = setup_schannel( *cli, domain->name );
381 if (!NT_STATUS_IS_OK(status)) {
382 DEBUG(3,("schannel refused - continuing without "
383 "schannel (%s)\n", nt_errstr(status)));
387 /* set the domain if empty; needed for schannel connections */
388 if ( !*(*cli)->domain )
389 fstrcpy( (*cli)->domain, domain->name );
391 if ( !cli_nt_session_open (*cli, pipe_index) ) {
393 result = NT_STATUS_PIPE_NOT_AVAILABLE;
395 /* This might be a NT4 DC */
396 if ( is_win2k_pipe(pipe_index) )
397 add_failed_connection = False;
403 result = NT_STATUS_OK;
404 add_failed_connection = False;
408 secrets_named_mutex_release(controller);
410 SAFE_FREE(machine_password);
411 SAFE_FREE(machine_krb5_principal);
412 SAFE_FREE(ipc_username);
413 SAFE_FREE(ipc_domain);
414 SAFE_FREE(ipc_password);
416 if (add_failed_connection)
417 add_failed_connection_entry(domain->name, controller, result);
427 static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
428 const char *dcname, struct in_addr ip,
429 struct dc_name_ip **dcs, int *num)
431 if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname)))
434 *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
439 fstrcpy((*dcs)[*num].name, dcname);
440 (*dcs)[*num].ip = ip;
445 static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
446 struct in_addr ip, uint16 port,
447 struct sockaddr_in **addrs, int *num)
449 *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
454 (*addrs)[*num].sin_family = PF_INET;
455 putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
456 (*addrs)[*num].sin_port = htons(port);
462 /*******************************************************************
463 convert an ip to a name
464 *******************************************************************/
466 static void dcip_to_name( const char *domainname, const char *realm, struct in_addr ip, fstring name )
468 /* try node status request first */
470 if ( name_status_find(domainname, 0x1c, 0x20, ip, name) )
473 /* backup in case the ads stuff fails */
475 fstrcpy( name, inet_ntoa(ip) );
478 /* for active directory servers, try to get the ldap server name.
479 None of these failure should be considered critical for now */
481 if ( lp_security() == SEC_ADS )
486 ads = ads_init( realm, domainname, NULL );
487 ads->auth.flags |= ADS_AUTH_NO_BIND;
489 if ( !ads_try_connect( ads, inet_ntoa(ip), LDAP_PORT ) ) {
494 status = ads_server_info(ads);
495 if ( !ADS_ERR_OK(status) ) {
500 fstrcpy(name, ads->config.ldap_server_name);
510 /*******************************************************************
511 Retreive a list of IP address for domain controllers. Fill in
512 the dcs[] with results.
513 *******************************************************************/
515 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
516 struct dc_name_ip **dcs, int *num_dcs)
520 struct ip_service *ip_list = NULL;
526 is_our_domain = strequal(domain->name, lp_workgroup());
529 && get_dc_name_via_netlogon(domain, dcname, &ip)
530 && add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs) )
536 && must_use_pdc(domain->name)
537 && get_pdc_ip(domain->name, &ip))
539 if (add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip), ip, dcs, num_dcs))
543 /* try standard netbios queries first */
545 get_sorted_dc_list(domain->name, &ip_list, &iplist_size, False);
547 /* check for security = ads and use DNS if we can */
549 if ( iplist_size==0 && lp_security() == SEC_ADS )
550 get_sorted_dc_list(domain->alt_name, &ip_list, &iplist_size, True);
552 /* now add to the dc array. We'll wait until the last minute
553 to look up the name of the DC. But we fill in the char* for
554 the ip now in to make the failed connection cache work */
556 for ( i=0; i<iplist_size; i++ ) {
557 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip),
558 ip_list[i].ip, dcs, num_dcs);
561 SAFE_FREE( ip_list );
566 static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
567 const struct winbindd_domain *domain,
568 fstring dcname, struct sockaddr_in *addr, int *fd)
570 struct dc_name_ip *dcs = NULL;
573 const char **dcnames = NULL;
576 struct sockaddr_in *addrs = NULL;
581 if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
584 for (i=0; i<num_dcs; i++) {
586 add_string_to_array(mem_ctx, dcs[i].name,
587 &dcnames, &num_dcnames);
588 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
591 add_string_to_array(mem_ctx, dcs[i].name,
592 &dcnames, &num_dcnames);
593 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
597 if ((num_dcnames == 0) || (num_dcnames != num_addrs))
600 if ( !open_any_socket_out(addrs, num_addrs, 10000, &fd_index, fd) )
602 for (i=0; i<num_dcs; i++) {
603 add_failed_connection_entry(domain->name,
604 dcs[i].name, NT_STATUS_UNSUCCESSFUL);
609 *addr = addrs[fd_index];
611 /* if we have no name on the server or just an IP address for
612 the name, now try to get the name */
614 if ( is_ipaddress(dcnames[fd_index]) || *dcnames[fd_index] == '\0' )
615 dcip_to_name( domain->name, domain->alt_name, addr->sin_addr, dcname );
617 fstrcpy(dcname, dcnames[fd_index]);
622 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
623 const int pipe_index,
624 struct winbindd_cm_conn *new_conn)
631 if ((mem_ctx = talloc_init("cm_open_connection")) == NULL)
632 return NT_STATUS_NO_MEMORY;
634 for (retries = 0; retries < 3; retries++) {
639 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
641 if ((strlen(domain->dcname) > 0) &&
642 NT_STATUS_IS_OK(check_negative_conn_cache(domain->name,
645 if (!open_any_socket_out(&domain->dcaddr, 1, 10000,
652 !find_new_dc(mem_ctx, domain, domain->dcname,
653 &domain->dcaddr, &fd))
656 new_conn->cli = NULL;
658 result = cm_prepare_connection(domain, fd, pipe_index,
660 &new_conn->cli, &retry);
662 if (NT_STATUS_IS_OK(result)) {
663 fstrcpy(new_conn->domain, domain->name);
664 /* Initialise SMB connection */
665 fstrcpy(new_conn->pipe_name,
666 get_pipe_name_from_index(pipe_index));
674 talloc_destroy(mem_ctx);
678 /************************************************************************
679 Wrapper around statuc cm_open_connection to retreive a freshly
680 setup cli_state struct
681 ************************************************************************/
683 NTSTATUS cm_fresh_connection(struct winbindd_domain *domain, const int pipe_index,
684 struct cli_state **cli)
687 struct winbindd_cm_conn conn;
689 result = cm_open_connection( domain, pipe_index, &conn );
691 if ( NT_STATUS_IS_OK(result) )
697 /* Return true if a connection is still alive */
699 static BOOL connection_ok(struct winbindd_cm_conn *conn)
702 smb_panic("Invalid parameter passed to connection_ok(): conn was NULL!\n");
707 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
708 conn->controller, conn->domain, conn->pipe_name));
712 if (!conn->cli->initialised) {
713 DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
714 conn->controller, conn->domain, conn->pipe_name));
718 if (conn->cli->fd == -1) {
719 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
720 conn->controller, conn->domain, conn->pipe_name));
727 /* Search the cache for a connection. If there is a broken one,
728 shut it down properly and return NULL. */
730 static void find_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
731 struct winbindd_cm_conn **conn_out)
733 struct winbindd_cm_conn *conn;
735 for (conn = cm_conns; conn; ) {
736 if (strequal(conn->domain, domain->name) &&
737 strequal(conn->pipe_name, pipe_name)) {
738 if (!connection_ok(conn)) {
739 /* Dead connection - remove it. */
740 struct winbindd_cm_conn *conn_temp = conn->next;
742 cli_shutdown(conn->cli);
743 DLIST_REMOVE(cm_conns, conn);
745 conn = conn_temp; /* Keep the loop moving */
757 /* Initialize a new connection up to the RPC BIND. */
759 static NTSTATUS new_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
760 struct winbindd_cm_conn **conn_out)
762 struct winbindd_cm_conn *conn;
765 if (!(conn = SMB_MALLOC_P(struct winbindd_cm_conn)))
766 return NT_STATUS_NO_MEMORY;
770 if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
771 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
772 domain->name, pipe_name, nt_errstr(result)));
776 DLIST_ADD(cm_conns, conn);
782 /* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
784 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const char *pipe_name,
785 struct winbindd_cm_conn **conn_out)
787 find_cm_connection(domain, pipe_name, conn_out);
789 if (*conn_out != NULL)
792 return new_cm_connection(domain, pipe_name, conn_out);
795 /**********************************************************************************
796 We can 'sense' certain things about the DC by it's replies to certain questions.
798 This tells us if this particular remote server is Active Directory, and if it is
800 **********************************************************************************/
802 void set_dc_type_and_flags( struct winbindd_domain *domain )
805 struct winbindd_cm_conn conn;
807 TALLOC_CTX *mem_ctx = NULL;
812 domain->native_mode = False;
813 domain->active_directory = False;
815 if (domain->internal) {
816 domain->initialized = True;
820 if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
821 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n",
822 domain->name, nt_errstr(result)));
823 domain->initialized = True;
828 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli,
829 conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
834 if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING)
835 && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
836 domain->native_mode = True;
838 /* Cheat - shut down the DS pipe, and open LSA */
840 cli_nt_session_close(conn.cli);
842 if ( cli_nt_session_open (conn.cli, PI_LSARPC) ) {
843 char *domain_name = NULL;
844 char *dns_name = NULL;
845 DOM_SID *dom_sid = NULL;
847 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n", domain->name);
849 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
853 result = cli_lsa_open_policy2(conn.cli, mem_ctx, True,
854 SEC_RIGHTS_MAXIMUM_ALLOWED,
857 if (NT_STATUS_IS_OK(result)) {
858 /* This particular query is exactly what Win2k clients use
859 to determine that the DC is active directory */
860 result = cli_lsa_query_info_policy2(conn.cli, mem_ctx,
867 if (NT_STATUS_IS_OK(result)) {
869 fstrcpy(domain->name, domain_name);
872 fstrcpy(domain->alt_name, dns_name);
875 sid_copy(&domain->sid, dom_sid);
877 domain->active_directory = True;
880 result = cli_lsa_open_policy(conn.cli, mem_ctx, True,
881 SEC_RIGHTS_MAXIMUM_ALLOWED,
884 if (!NT_STATUS_IS_OK(result))
887 result = cli_lsa_query_info_policy(conn.cli, mem_ctx,
888 &conn.pol, 5, &domain_name,
891 if (NT_STATUS_IS_OK(result)) {
893 fstrcpy(domain->name, domain_name);
896 sid_copy(&domain->sid, dom_sid);
903 DEBUG(3,("add_trusted_domain: %s is an %s %s domain\n", domain->name,
904 domain->active_directory ? "ADS" : "NT4",
905 domain->native_mode ? "native mode" :
906 ((domain->active_directory && !domain->native_mode) ? "mixed mode" : "")));
908 /* close the connection; no other calls use this pipe and it is called only
909 on reestablishing the domain list --jerry */
912 cli_shutdown( conn.cli );
914 talloc_destroy(mem_ctx);
916 domain->initialized = True;
923 /* Return a LSA policy handle on a domain */
925 NTSTATUS cm_get_lsa_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
927 struct winbindd_cm_conn *conn;
928 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
930 static CLI_POLICY_HND hnd;
932 /* Look for existing connections */
934 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
937 /* This *shitty* code needs scrapping ! JRA */
939 if (policy_handle_is_valid(&conn->pol)) {
947 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
948 des_access, &conn->pol);
950 if (!NT_STATUS_IS_OK(result)) {
951 /* Hit the cache code again. This cleans out the old connection and gets a new one */
952 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
953 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
956 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
957 des_access, &conn->pol);
960 if (!NT_STATUS_IS_OK(result)) {
961 cli_shutdown(conn->cli);
962 DLIST_REMOVE(cm_conns, conn);
976 /* Return a SAM policy handle on a domain */
978 NTSTATUS cm_get_sam_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
980 struct winbindd_cm_conn *conn;
981 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
983 static CLI_POLICY_HND hnd;
985 /* Look for existing connections */
987 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
990 /* This *shitty* code needs scrapping ! JRA */
992 if (policy_handle_is_valid(&conn->pol)) {
1001 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
1002 des_access, &conn->pol);
1004 if (!NT_STATUS_IS_OK(result)) {
1005 /* Hit the cache code again. This cleans out the old connection and gets a new one */
1006 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
1008 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
1011 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
1012 des_access, &conn->pol);
1015 if (!NT_STATUS_IS_OK(result)) {
1017 cli_shutdown(conn->cli);
1018 DLIST_REMOVE(cm_conns, conn);
1025 hnd.pol = conn->pol;
1026 hnd.cli = conn->cli;
1030 return NT_STATUS_OK;
1033 /* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
1034 netlogon pipe as no handle is returned. */
1036 NTSTATUS cm_get_netlogon_cli(struct winbindd_domain *domain,
1037 const unsigned char *trust_passwd,
1038 uint32 sec_channel_type,
1040 struct cli_state **cli)
1042 NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1043 struct winbindd_cm_conn *conn;
1048 return NT_STATUS_INVALID_PARAMETER;
1050 /* Open an initial conection - keep the mutex. */
1052 find_cm_connection(domain, PIPE_NETLOGON, &conn);
1054 if ( fresh && (conn != NULL) ) {
1055 cli_shutdown(conn->cli);
1060 /* purge connection from cache */
1061 find_cm_connection(domain, PIPE_NETLOGON, &conn);
1063 DEBUG(0,("Could not purge connection\n"));
1064 return NT_STATUS_UNSUCCESSFUL;
1070 return NT_STATUS_OK;
1073 result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
1075 if (!NT_STATUS_IS_OK(result))
1078 fstr_sprintf(lock_name, "NETLOGON\\%s", conn->controller);
1080 if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
1081 DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
1084 if ( sec_channel_type == SEC_CHAN_DOMAIN )
1085 fstr_sprintf(conn->cli->mach_acct, "%s$", lp_workgroup());
1087 /* This must be the remote domain (not ours) for schannel */
1089 fstrcpy( conn->cli->domain, domain->name);
1091 result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd);
1094 secrets_named_mutex_release(lock_name);
1096 if (!NT_STATUS_IS_OK(result)) {
1097 cli_shutdown(conn->cli);
1098 DLIST_REMOVE(cm_conns, conn);
1108 /* Dump the current connection status */
1110 static void dump_conn_list(void)
1112 struct winbindd_cm_conn *con;
1114 DEBUG(0, ("\tDomain Controller Pipe\n"));
1116 for(con = cm_conns; con; con = con->next) {
1119 /* Display pipe info */
1121 if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
1122 DEBUG(0, ("Error: not enough memory!\n"));
1124 DEBUG(0, ("%s\n", msg));
1130 void winbindd_cm_status(void)
1132 /* List open connections */
1134 DEBUG(0, ("winbindd connection manager status:\n"));
1139 DEBUG(0, ("\tNo active connections\n"));
1142 /* Close all cached connections */
1144 void winbindd_cm_flush(void)
1146 struct winbindd_cm_conn *conn, tmp;
1148 /* Flush connection cache */
1150 for (conn = cm_conns; conn; conn = conn->next) {
1152 if (!connection_ok(conn))
1155 DEBUG(10, ("Closing connection to %s on %s\n",
1156 conn->pipe_name, conn->controller));
1159 cli_shutdown(conn->cli);
1161 tmp.next = conn->next;
1163 DLIST_REMOVE(cm_conns, conn);
1168 /* Flush failed connection cache */
1170 flush_negative_conn_cache();