r5555: current with 3.0 tree as of r5548; getting ready for 3.0.12pre1
[Samba.git] / source / nsswitch / winbindd_cm.c
blobdc2d6cfc6f63638d1da84c3a5d916b771e7c167a
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 - Take care when destroying cli_structs as they can be shared between
55 various sam handles.
59 #include "includes.h"
60 #include "winbindd.h"
62 #undef DBGC_CLASS
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;
70 fstring domain;
71 fstring controller;
72 fstring pipe_name;
73 struct cli_state *cli;
74 POLICY_HND pol;
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));
108 } else {
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 )
121 NTSTATUS ret;
122 uchar trust_password[16];
123 uint32 sec_channel_type;
124 DOM_SID sid;
125 time_t lct;
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()) ) {
131 char *pass = NULL;
133 if ( !secrets_fetch_trusted_domain_password( domain,
134 &pass, &sid, &lct) )
136 return NT_STATUS_UNSUCCESSFUL;
139 sec_channel_type = SEC_CHAN_DOMAIN;
140 E_md4hash(pass, trust_password);
141 SAFE_FREE( pass );
143 } else {
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);
154 return ret;
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;
161 NTSTATUS result;
162 struct winbindd_cm_conn *conn;
163 TALLOC_CTX *mem_ctx;
165 fstring tmp;
166 char *p;
168 if (IS_DC)
169 return False;
171 if (domain->primary)
172 return False;
174 if ((our_domain = find_our_domain()) == NULL)
175 return False;
177 result = get_connection_from_cache(our_domain, PIPE_NETLOGON, &conn);
178 if (!NT_STATUS_IS_OK(result))
179 return False;
181 if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL)
182 return False;
184 result = cli_netlogon_getdcname(conn->cli, mem_ctx, domain->name, tmp);
186 talloc_destroy(mem_ctx);
188 if (!NT_STATUS_IS_OK(result))
189 return False;
191 /* cli_netlogon_getdcname gives us a name with \\ */
192 p = tmp;
193 if (*p == '\\') p+=1;
194 if (*p == '\\') p+=1;
196 fstrcpy(dcname, p);
198 if (!resolve_name(dcname, dc_ip, 0x20))
199 return False;
201 return True;
204 /************************************************************************
205 Given a fd with a just-connected TCP connection to a DC, open a connection
206 to the pipe.
207 ************************************************************************/
209 static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
210 const int sockfd,
211 const int pipe_index,
212 const char *controller,
213 struct cli_state **cli,
214 BOOL *retry)
216 char *machine_password, *machine_krb5_principal;
217 char *ipc_username, *ipc_domain, *ipc_password;
219 BOOL got_mutex;
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,
230 NULL);
232 if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(),
233 lp_realm()) == -1) {
234 SAFE_FREE(machine_password);
235 return NT_STATUS_NO_MEMORY;
238 cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
240 *retry = True;
242 got_mutex = secrets_named_mutex(controller,
243 WINBIND_SERVER_MUTEX_WAIT_TIME);
245 if (!got_mutex) {
246 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n",
247 controller));
248 result = NT_STATUS_POSSIBLE_DEADLOCK;
249 goto done;
252 if ((*cli = cli_initialise(NULL)) == NULL) {
253 DEBUG(1, ("Could not cli_initialize\n"));
254 result = NT_STATUS_NO_MEMORY;
255 goto done;
258 (*cli)->timeout = 10000; /* 10 seconds */
259 (*cli)->fd = sockfd;
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)));
270 goto done;
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",
282 controller));
283 goto done;
287 cli_setup_signing_state(*cli, Undefined);
289 if (!cli_negprot(*cli)) {
290 DEBUG(1, ("cli_negprot failed\n"));
291 cli_shutdown(*cli);
292 goto done;
295 /* Krb5 session */
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,
309 machine_password,
310 lp_workgroup());
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,
338 ipc_domain)) {
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 */
358 goto done;
360 session_setup_done:
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;
371 cli_shutdown(*cli);
372 goto done;
375 secrets_named_mutex_release(controller);
376 got_mutex = False;
377 *retry = False;
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;
399 cli_shutdown(*cli);
400 goto done;
403 result = NT_STATUS_OK;
404 add_failed_connection = False;
406 done:
407 if (got_mutex)
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);
419 return result;
422 struct dc_name_ip {
423 fstring name;
424 struct in_addr ip;
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)))
432 return False;
434 *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
436 if (*dcs == NULL)
437 return False;
439 fstrcpy((*dcs)[*num].name, dcname);
440 (*dcs)[*num].ip = ip;
441 *num += 1;
442 return True;
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);
451 if (*addrs == NULL)
452 return False;
454 (*addrs)[*num].sin_family = PF_INET;
455 putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
456 (*addrs)[*num].sin_port = htons(port);
458 *num += 1;
459 return True;
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) )
471 return;
473 /* backup in case the ads stuff fails */
475 fstrcpy( name, inet_ntoa(ip) );
477 #ifdef WITH_ADS
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 )
483 ADS_STRUCT *ads;
484 ADS_STATUS status;
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 ) ) {
490 ads_destroy( &ads );
491 return;
494 status = ads_server_info(ads);
495 if ( !ADS_ERR_OK(status) ) {
496 ads_destroy( &ads );
497 return;
500 fstrcpy(name, ads->config.ldap_server_name);
502 ads_destroy( &ads );
504 #endif
506 return;
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)
518 fstring dcname;
519 struct in_addr ip;
520 struct ip_service *ip_list = NULL;
521 int iplist_size = 0;
522 int i;
523 BOOL is_our_domain;
526 is_our_domain = strequal(domain->name, lp_workgroup());
528 if ( !is_our_domain
529 && get_dc_name_via_netlogon(domain, dcname, &ip)
530 && add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs) )
532 return True;
535 if ( is_our_domain
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))
540 return True;
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 );
563 return True;
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;
571 int num_dcs = 0;
573 const char **dcnames = NULL;
574 int num_dcnames = 0;
576 struct sockaddr_in *addrs = NULL;
577 int num_addrs = 0;
579 int i, fd_index;
581 if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
582 return False;
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,
589 &addrs, &num_addrs);
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,
594 &addrs, &num_addrs);
597 if ((num_dcnames == 0) || (num_dcnames != num_addrs))
598 return False;
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);
606 return False;
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 );
616 else
617 fstrcpy(dcname, dcnames[fd_index]);
619 return True;
622 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
623 const int pipe_index,
624 struct winbindd_cm_conn *new_conn)
626 TALLOC_CTX *mem_ctx;
627 NTSTATUS result;
629 int retries;
631 if ((mem_ctx = talloc_init("cm_open_connection")) == NULL)
632 return NT_STATUS_NO_MEMORY;
634 for (retries = 0; retries < 3; retries++) {
636 int fd = -1;
637 BOOL retry;
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,
643 domain->dcname))) {
644 int dummy;
645 if (!open_any_socket_out(&domain->dcaddr, 1, 10000,
646 &dummy, &fd)) {
647 fd = -1;
651 if ((fd == -1) &&
652 !find_new_dc(mem_ctx, domain, domain->dcname,
653 &domain->dcaddr, &fd))
654 break;
656 new_conn->cli = NULL;
658 result = cm_prepare_connection(domain, fd, pipe_index,
659 domain->dcname,
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));
667 break;
670 if (!retry)
671 break;
674 talloc_destroy(mem_ctx);
675 return result;
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)
686 NTSTATUS result;
687 struct winbindd_cm_conn conn;
689 result = cm_open_connection( domain, pipe_index, &conn );
691 if ( NT_STATUS_IS_OK(result) )
692 *cli = conn.cli;
694 return result;
697 /* Return true if a connection is still alive */
699 static BOOL connection_ok(struct winbindd_cm_conn *conn)
701 if (!conn) {
702 smb_panic("Invalid parameter passed to connection_ok(): conn was NULL!\n");
703 return False;
706 if (!conn->cli) {
707 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
708 conn->controller, conn->domain, conn->pipe_name));
709 return False;
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));
715 return False;
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));
721 return False;
724 return True;
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;
741 if (conn->cli)
742 cli_shutdown(conn->cli);
743 DLIST_REMOVE(cm_conns, conn);
744 SAFE_FREE(conn);
745 conn = conn_temp; /* Keep the loop moving */
746 continue;
747 } else {
748 break;
751 conn = conn->next;
754 *conn_out = conn;
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;
763 NTSTATUS result;
765 if (!(conn = SMB_MALLOC_P(struct winbindd_cm_conn)))
766 return NT_STATUS_NO_MEMORY;
768 ZERO_STRUCTP(conn);
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)));
773 SAFE_FREE(conn);
774 return result;
776 DLIST_ADD(cm_conns, conn);
778 *conn_out = conn;
779 return NT_STATUS_OK;
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)
790 return NT_STATUS_OK;
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
799 native mode.
800 **********************************************************************************/
802 void set_dc_type_and_flags( struct winbindd_domain *domain )
804 NTSTATUS result;
805 struct winbindd_cm_conn conn;
806 DS_DOMINFO_CTR ctr;
807 TALLOC_CTX *mem_ctx = NULL;
809 ZERO_STRUCT( conn );
810 ZERO_STRUCT( ctr );
812 domain->native_mode = False;
813 domain->active_directory = False;
815 if (domain->internal) {
816 domain->initialized = True;
817 return;
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;
824 return;
827 if ( conn.cli ) {
828 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli,
829 conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
830 goto done;
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);
848 if (!mem_ctx) {
849 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
850 return;
853 result = cli_lsa_open_policy2(conn.cli, mem_ctx, True,
854 SEC_RIGHTS_MAXIMUM_ALLOWED,
855 &conn.pol);
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,
861 &conn.pol,
862 12, &domain_name,
863 &dns_name, NULL,
864 NULL, &dom_sid);
867 if (NT_STATUS_IS_OK(result)) {
868 if (domain_name)
869 fstrcpy(domain->name, domain_name);
871 if (dns_name)
872 fstrcpy(domain->alt_name, dns_name);
874 if (dom_sid)
875 sid_copy(&domain->sid, dom_sid);
877 domain->active_directory = True;
878 } else {
880 result = cli_lsa_open_policy(conn.cli, mem_ctx, True,
881 SEC_RIGHTS_MAXIMUM_ALLOWED,
882 &conn.pol);
884 if (!NT_STATUS_IS_OK(result))
885 goto done;
887 result = cli_lsa_query_info_policy(conn.cli, mem_ctx,
888 &conn.pol, 5, &domain_name,
889 &dom_sid);
891 if (NT_STATUS_IS_OK(result)) {
892 if (domain_name)
893 fstrcpy(domain->name, domain_name);
895 if (dom_sid)
896 sid_copy(&domain->sid, dom_sid);
901 done:
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 */
911 if ( conn.cli )
912 cli_shutdown( conn.cli );
914 talloc_destroy(mem_ctx);
916 domain->initialized = True;
918 return;
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;
929 NTSTATUS result;
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)))
935 return result;
937 /* This *shitty* code needs scrapping ! JRA */
939 if (policy_handle_is_valid(&conn->pol)) {
940 hnd.pol = conn->pol;
941 hnd.cli = conn->cli;
942 *return_hnd = &hnd;
944 return NT_STATUS_OK;
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)))
954 return result;
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);
963 SAFE_FREE(conn);
964 return result;
968 hnd.pol = conn->pol;
969 hnd.cli = conn->cli;
971 *return_hnd = &hnd;
973 return NT_STATUS_OK;
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;
982 NTSTATUS result;
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)))
988 return result;
990 /* This *shitty* code needs scrapping ! JRA */
992 if (policy_handle_is_valid(&conn->pol)) {
993 hnd.pol = conn->pol;
994 hnd.cli = conn->cli;
996 *return_hnd = &hnd;
998 return NT_STATUS_OK;
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)))
1009 return result;
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);
1019 SAFE_FREE(conn);
1021 return result;
1025 hnd.pol = conn->pol;
1026 hnd.cli = conn->cli;
1028 *return_hnd = &hnd;
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,
1039 BOOL fresh,
1040 struct cli_state **cli)
1042 NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1043 struct winbindd_cm_conn *conn;
1044 fstring lock_name;
1045 BOOL got_mutex;
1047 if (!cli)
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);
1056 conn->cli = NULL;
1058 conn = NULL;
1060 /* purge connection from cache */
1061 find_cm_connection(domain, PIPE_NETLOGON, &conn);
1062 if (conn != NULL) {
1063 DEBUG(0,("Could not purge connection\n"));
1064 return NT_STATUS_UNSUCCESSFUL;
1068 if (conn != NULL) {
1069 *cli = conn->cli;
1070 return NT_STATUS_OK;
1073 result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
1075 if (!NT_STATUS_IS_OK(result))
1076 return 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);
1093 if (got_mutex)
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);
1099 SAFE_FREE(conn);
1100 return result;
1103 *cli = conn->cli;
1105 return result;
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) {
1117 char *msg;
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"));
1123 } else {
1124 DEBUG(0, ("%s\n", msg));
1125 SAFE_FREE(msg);
1130 void winbindd_cm_status(void)
1132 /* List open connections */
1134 DEBUG(0, ("winbindd connection manager status:\n"));
1136 if (cm_conns)
1137 dump_conn_list();
1138 else
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))
1153 continue;
1155 DEBUG(10, ("Closing connection to %s on %s\n",
1156 conn->pipe_name, conn->controller));
1158 if (conn->cli)
1159 cli_shutdown(conn->cli);
1161 tmp.next = conn->next;
1163 DLIST_REMOVE(cm_conns, conn);
1164 SAFE_FREE(conn);
1165 conn = &tmp;
1168 /* Flush failed connection cache */
1170 flush_negative_conn_cache();