r4348: syncing up for 3.0.11pre1
[Samba.git] / source / nsswitch / winbindd_cm.c
blob1843ec188b03479bfa058f37e091b751f359e699
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;
218 struct ntuser_creds creds;
220 BOOL got_mutex;
221 BOOL add_failed_connection = True;
223 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
225 struct sockaddr peeraddr;
226 socklen_t peeraddr_len;
228 struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
230 machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL,
231 NULL);
233 if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(),
234 lp_realm()) == -1) {
235 SAFE_FREE(machine_password);
236 return NT_STATUS_NO_MEMORY;
239 cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
241 *retry = True;
243 got_mutex = secrets_named_mutex(controller,
244 WINBIND_SERVER_MUTEX_WAIT_TIME);
246 if (!got_mutex) {
247 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n",
248 controller));
249 result = NT_STATUS_POSSIBLE_DEADLOCK;
250 goto done;
253 if ((*cli = cli_initialise(NULL)) == NULL) {
254 DEBUG(1, ("Could not cli_initialize\n"));
255 result = NT_STATUS_NO_MEMORY;
256 goto done;
259 (*cli)->timeout = 10000; /* 10 seconds */
260 (*cli)->fd = sockfd;
261 fstrcpy((*cli)->desthost, controller);
262 (*cli)->use_kerberos = True;
264 peeraddr_len = sizeof(peeraddr);
266 if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
267 (peeraddr_len != sizeof(struct sockaddr_in)) ||
268 (peeraddr_in->sin_family != PF_INET))
269 goto done;
271 if (ntohs(peeraddr_in->sin_port) == 139) {
272 struct nmb_name calling;
273 struct nmb_name called;
275 make_nmb_name(&calling, global_myname(), 0x0);
276 make_nmb_name(&called, "*SMBSERVER", 0x20);
278 if (!cli_session_request(*cli, &calling, &called)) {
279 DEBUG(8, ("cli_session_request failed for %s\n",
280 controller));
281 goto done;
285 cli_setup_signing_state(*cli, Undefined);
287 if (!cli_negprot(*cli)) {
288 DEBUG(1, ("cli_negprot failed\n"));
289 cli_shutdown(*cli);
290 goto done;
293 /* Krb5 session */
295 if ((lp_security() == SEC_ADS)
296 && ((*cli)->protocol >= PROTOCOL_NT1 &&
297 (*cli)->capabilities & CAP_EXTENDED_SECURITY)) {
299 ADS_STATUS ads_status;
300 (*cli)->use_kerberos = True;
301 DEBUG(5, ("connecting to %s from %s with kerberos principal "
302 "[%s]\n", controller, global_myname(),
303 machine_krb5_principal));
305 ads_status = cli_session_setup_spnego(*cli,
306 machine_krb5_principal,
307 machine_password,
308 lp_workgroup());
310 if (!ADS_ERR_OK(ads_status))
311 DEBUG(4,("failed kerberos session setup with %s\n",
312 ads_errstr(ads_status)));
314 result = ads_ntstatus(ads_status);
317 if (NT_STATUS_IS_OK(result))
318 goto session_setup_done;
320 /* Fall back to non-kerberos session setup */
322 (*cli)->use_kerberos = False;
324 if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
325 (strlen(ipc_username) > 0)) {
327 /* Only try authenticated if we have a username */
329 DEBUG(5, ("connecting to %s from %s with username "
330 "[%s]\\[%s]\n", controller, global_myname(),
331 ipc_domain, ipc_username));
333 if (cli_session_setup(*cli, ipc_username,
334 ipc_password, strlen(ipc_password)+1,
335 ipc_password, strlen(ipc_password)+1,
336 ipc_domain)) {
337 DEBUG(5, ("authenticated session setup failed\n"));
338 goto session_setup_done;
342 /* Fall back to anonymous connection, this might fail later */
344 if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) {
345 DEBUG(5, ("Connected anonymously\n"));
346 goto session_setup_done;
349 result = cli_nt_error(*cli);
351 if (NT_STATUS_IS_OK(result))
352 result = NT_STATUS_UNSUCCESSFUL;
354 /* We can't session setup */
356 goto done;
358 session_setup_done:
360 if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
362 result = cli_nt_error(*cli);
364 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
366 if (NT_STATUS_IS_OK(result))
367 result = NT_STATUS_UNSUCCESSFUL;
369 cli_shutdown(*cli);
370 goto done;
373 init_creds(&creds, ipc_username, ipc_domain, ipc_password);
374 cli_init_creds(*cli, &creds);
376 secrets_named_mutex_release(controller);
377 got_mutex = False;
378 *retry = False;
380 if (domain->primary || IS_DC) {
381 NTSTATUS status = setup_schannel( *cli, domain->name );
382 if (!NT_STATUS_IS_OK(status)) {
383 DEBUG(3,("schannel refused - continuing without "
384 "schannel (%s)\n", nt_errstr(status)));
388 /* set the domain if empty; needed for schannel connections */
389 if ( !*(*cli)->domain )
390 fstrcpy( (*cli)->domain, domain->name );
392 if ( !cli_nt_session_open (*cli, pipe_index) ) {
394 result = NT_STATUS_PIPE_NOT_AVAILABLE;
396 /* This might be a NT4 DC */
397 if ( is_win2k_pipe(pipe_index) )
398 add_failed_connection = False;
400 cli_shutdown(*cli);
401 goto done;
404 result = NT_STATUS_OK;
405 add_failed_connection = False;
407 done:
408 if (got_mutex)
409 secrets_named_mutex_release(controller);
411 SAFE_FREE(machine_password);
412 SAFE_FREE(machine_krb5_principal);
413 SAFE_FREE(ipc_username);
414 SAFE_FREE(ipc_domain);
415 SAFE_FREE(ipc_password);
417 if (add_failed_connection)
418 add_failed_connection_entry(domain->name, controller, result);
420 return result;
423 struct dc_name_ip {
424 fstring name;
425 struct in_addr ip;
428 static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
429 const char *dcname, struct in_addr ip,
430 struct dc_name_ip **dcs, int *num)
432 if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname)))
433 return False;
435 *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
437 if (*dcs == NULL)
438 return False;
440 fstrcpy((*dcs)[*num].name, dcname);
441 (*dcs)[*num].ip = ip;
442 *num += 1;
443 return True;
446 static BOOL add_string_to_array(TALLOC_CTX *mem_ctx,
447 const char *str, char ***array, int *num)
449 char *dup_str = talloc_strdup(mem_ctx, str);
451 *array = TALLOC_REALLOC_ARRAY(mem_ctx, *array, char *, (*num)+1);
453 if ((*array == NULL) || (dup_str == NULL))
454 return False;
456 (*array)[*num] = dup_str;
457 *num += 1;
458 return True;
461 static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
462 struct in_addr ip, uint16 port,
463 struct sockaddr_in **addrs, int *num)
465 *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
467 if (*addrs == NULL)
468 return False;
470 (*addrs)[*num].sin_family = PF_INET;
471 putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
472 (*addrs)[*num].sin_port = htons(port);
474 *num += 1;
475 return True;
478 static BOOL get_dcs_1c(TALLOC_CTX *mem_ctx,
479 const struct winbindd_domain *domain,
480 struct dc_name_ip **dcs, int *num_dcs)
482 struct ip_service *iplist = NULL;
483 int i, num = 0;
485 if (!internal_resolve_name(domain->name, 0x1c, &iplist, &num,
486 lp_name_resolve_order()))
487 return False;
489 /* Now try to find the server names of at least one IP address, hosts
490 * not replying are cached as such */
492 for (i=0; i<num; i++) {
494 fstring dcname;
496 if (!name_status_find(domain->name, 0x1c, 0x20, iplist[i].ip,
497 dcname))
498 continue;
500 if (add_one_dc_unique(mem_ctx, domain->name, dcname,
501 iplist[i].ip, dcs, num_dcs)) {
502 /* One DC responded, so we assume that he will also
503 work on 139/445 */
504 break;
508 return True;
511 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
512 struct dc_name_ip **dcs, int *num_dcs)
514 fstring dcname;
515 struct in_addr ip;
516 BOOL is_our_domain;
518 const char *p;
520 is_our_domain = strequal(domain->name, lp_workgroup());
522 if (!is_our_domain && get_dc_name_via_netlogon(domain, dcname, &ip) &&
523 add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs))
524 return True;
526 if (!is_our_domain) {
527 /* NETLOGON to our own domain could not give us a DC name
528 * (which is an error), fall back to looking up domain#1c */
529 return get_dcs_1c(mem_ctx, domain, dcs, num_dcs);
532 if (must_use_pdc(domain->name) && get_pdc_ip(domain->name, &ip)) {
534 if (!name_status_find(domain->name, 0x1b, 0x20, ip, dcname))
535 return False;
537 if (add_one_dc_unique(mem_ctx, domain->name,
538 dcname, ip, dcs, num_dcs))
539 return True;
542 p = lp_passwordserver();
544 if (*p == 0)
545 return get_dcs_1c(mem_ctx, domain, dcs, num_dcs);
547 while (next_token(&p, dcname, LIST_SEP, sizeof(dcname))) {
549 if (strequal(dcname, "*")) {
550 get_dcs_1c(mem_ctx, domain, dcs, num_dcs);
551 continue;
554 if (!resolve_name(dcname, &ip, 0x20))
555 continue;
557 add_one_dc_unique(mem_ctx, domain->name, dcname, ip,
558 dcs, num_dcs);
561 return True;
564 static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
565 const struct winbindd_domain *domain,
566 fstring dcname, struct sockaddr_in *addr, int *fd)
568 struct dc_name_ip *dcs = NULL;
569 int num_dcs = 0;
571 char **dcnames = NULL;
572 int num_dcnames = 0;
574 struct sockaddr_in *addrs = NULL;
575 int num_addrs = 0;
577 int i, fd_index;
579 if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
580 return False;
582 for (i=0; i<num_dcs; i++) {
584 add_string_to_array(mem_ctx, dcs[i].name,
585 &dcnames, &num_dcnames);
586 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
587 &addrs, &num_addrs);
589 add_string_to_array(mem_ctx, dcs[i].name,
590 &dcnames, &num_dcnames);
591 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
592 &addrs, &num_addrs);
595 if ((num_dcnames == 0) || (num_dcnames != num_addrs))
596 return False;
598 if (!open_any_socket_out(addrs, num_addrs, 10000, &fd_index, fd)) {
599 for (i=0; i<num_dcs; i++) {
600 add_failed_connection_entry(domain->name,
601 dcs[i].name,
602 NT_STATUS_UNSUCCESSFUL);
604 return False;
607 fstrcpy(dcname, dcnames[fd_index]);
608 *addr = addrs[fd_index];
610 return True;
613 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
614 const int pipe_index,
615 struct winbindd_cm_conn *new_conn)
617 TALLOC_CTX *mem_ctx;
618 NTSTATUS result;
620 int retries;
622 if ((mem_ctx = talloc_init("cm_open_connection")) == NULL)
623 return NT_STATUS_NO_MEMORY;
625 for (retries = 0; retries < 3; retries++) {
627 int fd = -1;
628 BOOL retry;
630 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
632 if ((strlen(domain->dcname) > 0) &&
633 NT_STATUS_IS_OK(check_negative_conn_cache(domain->name,
634 domain->dcname))) {
635 int dummy;
636 if (!open_any_socket_out(&domain->dcaddr, 1, 10000,
637 &dummy, &fd)) {
638 fd = -1;
642 if ((fd == -1) &&
643 !find_new_dc(mem_ctx, domain, domain->dcname,
644 &domain->dcaddr, &fd))
645 break;
647 new_conn->cli = NULL;
649 result = cm_prepare_connection(domain, fd, pipe_index,
650 domain->dcname,
651 &new_conn->cli, &retry);
653 if (NT_STATUS_IS_OK(result)) {
654 fstrcpy(new_conn->domain, domain->name);
655 /* Initialise SMB connection */
656 fstrcpy(new_conn->pipe_name,
657 get_pipe_name_from_index(pipe_index));
658 break;
661 if (!retry)
662 break;
665 talloc_destroy(mem_ctx);
666 return result;
669 /************************************************************************
670 Wrapper around statuc cm_open_connection to retreive a freshly
671 setup cli_state struct
672 ************************************************************************/
674 NTSTATUS cm_fresh_connection(struct winbindd_domain *domain, const int pipe_index,
675 struct cli_state **cli)
677 NTSTATUS result;
678 struct winbindd_cm_conn conn;
680 result = cm_open_connection( domain, pipe_index, &conn );
682 if ( NT_STATUS_IS_OK(result) )
683 *cli = conn.cli;
685 return result;
688 /* Return true if a connection is still alive */
690 static BOOL connection_ok(struct winbindd_cm_conn *conn)
692 if (!conn) {
693 smb_panic("Invalid parameter passed to connection_ok(): conn was NULL!\n");
694 return False;
697 if (!conn->cli) {
698 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
699 conn->controller, conn->domain, conn->pipe_name));
700 return False;
703 if (!conn->cli->initialised) {
704 DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
705 conn->controller, conn->domain, conn->pipe_name));
706 return False;
709 if (conn->cli->fd == -1) {
710 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
711 conn->controller, conn->domain, conn->pipe_name));
712 return False;
715 return True;
718 /* Search the cache for a connection. If there is a broken one,
719 shut it down properly and return NULL. */
721 static void find_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
722 struct winbindd_cm_conn **conn_out)
724 struct winbindd_cm_conn *conn;
726 for (conn = cm_conns; conn; ) {
727 if (strequal(conn->domain, domain->name) &&
728 strequal(conn->pipe_name, pipe_name)) {
729 if (!connection_ok(conn)) {
730 /* Dead connection - remove it. */
731 struct winbindd_cm_conn *conn_temp = conn->next;
732 if (conn->cli)
733 cli_shutdown(conn->cli);
734 DLIST_REMOVE(cm_conns, conn);
735 SAFE_FREE(conn);
736 conn = conn_temp; /* Keep the loop moving */
737 continue;
738 } else {
739 break;
742 conn = conn->next;
745 *conn_out = conn;
748 /* Initialize a new connection up to the RPC BIND. */
750 static NTSTATUS new_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
751 struct winbindd_cm_conn **conn_out)
753 struct winbindd_cm_conn *conn;
754 NTSTATUS result;
756 if (!(conn = SMB_MALLOC_P(struct winbindd_cm_conn)))
757 return NT_STATUS_NO_MEMORY;
759 ZERO_STRUCTP(conn);
761 if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
762 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
763 domain->name, pipe_name, nt_errstr(result)));
764 SAFE_FREE(conn);
765 return result;
767 DLIST_ADD(cm_conns, conn);
769 *conn_out = conn;
770 return NT_STATUS_OK;
773 /* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
775 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const char *pipe_name,
776 struct winbindd_cm_conn **conn_out)
778 find_cm_connection(domain, pipe_name, conn_out);
780 if (*conn_out != NULL)
781 return NT_STATUS_OK;
783 return new_cm_connection(domain, pipe_name, conn_out);
786 /**********************************************************************************
787 We can 'sense' certain things about the DC by it's replies to certain questions.
789 This tells us if this particular remote server is Active Directory, and if it is
790 native mode.
791 **********************************************************************************/
793 void set_dc_type_and_flags( struct winbindd_domain *domain )
795 NTSTATUS result;
796 struct winbindd_cm_conn conn;
797 DS_DOMINFO_CTR ctr;
798 TALLOC_CTX *mem_ctx = NULL;
800 ZERO_STRUCT( conn );
801 ZERO_STRUCT( ctr );
803 domain->native_mode = False;
804 domain->active_directory = False;
806 if (domain->internal) {
807 domain->initialized = True;
808 return;
811 if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
812 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n",
813 domain->name, nt_errstr(result)));
814 domain->initialized = True;
815 return;
818 if ( conn.cli ) {
819 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli,
820 conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
821 goto done;
825 if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING)
826 && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
827 domain->native_mode = True;
829 /* Cheat - shut down the DS pipe, and open LSA */
831 cli_nt_session_close(conn.cli);
833 if ( cli_nt_session_open (conn.cli, PI_LSARPC) ) {
834 char *domain_name = NULL;
835 char *dns_name = NULL;
836 DOM_SID *dom_sid = NULL;
838 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n", domain->name);
839 if (!mem_ctx) {
840 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
841 return;
844 result = cli_lsa_open_policy2(conn.cli, mem_ctx, True,
845 SEC_RIGHTS_MAXIMUM_ALLOWED,
846 &conn.pol);
848 if (NT_STATUS_IS_OK(result)) {
849 /* This particular query is exactly what Win2k clients use
850 to determine that the DC is active directory */
851 result = cli_lsa_query_info_policy2(conn.cli, mem_ctx,
852 &conn.pol,
853 12, &domain_name,
854 &dns_name, NULL,
855 NULL, &dom_sid);
858 if (NT_STATUS_IS_OK(result)) {
859 if (domain_name)
860 fstrcpy(domain->name, domain_name);
862 if (dns_name)
863 fstrcpy(domain->alt_name, dns_name);
865 if (dom_sid)
866 sid_copy(&domain->sid, dom_sid);
868 domain->active_directory = True;
869 } else {
871 result = cli_lsa_open_policy(conn.cli, mem_ctx, True,
872 SEC_RIGHTS_MAXIMUM_ALLOWED,
873 &conn.pol);
875 if (!NT_STATUS_IS_OK(result))
876 goto done;
878 result = cli_lsa_query_info_policy(conn.cli, mem_ctx,
879 &conn.pol, 5, &domain_name,
880 &dom_sid);
882 if (NT_STATUS_IS_OK(result)) {
883 if (domain_name)
884 fstrcpy(domain->name, domain_name);
886 if (dom_sid)
887 sid_copy(&domain->sid, dom_sid);
892 done:
894 /* close the connection; no other calls use this pipe and it is called only
895 on reestablishing the domain list --jerry */
897 if ( conn.cli )
898 cli_shutdown( conn.cli );
900 talloc_destroy(mem_ctx);
902 domain->initialized = True;
904 return;
909 /* Return a LSA policy handle on a domain */
911 NTSTATUS cm_get_lsa_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
913 struct winbindd_cm_conn *conn;
914 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
915 NTSTATUS result;
916 static CLI_POLICY_HND hnd;
918 /* Look for existing connections */
920 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
921 return result;
923 /* This *shitty* code needs scrapping ! JRA */
925 if (policy_handle_is_valid(&conn->pol)) {
926 hnd.pol = conn->pol;
927 hnd.cli = conn->cli;
928 *return_hnd = &hnd;
930 return NT_STATUS_OK;
933 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
934 des_access, &conn->pol);
936 if (!NT_STATUS_IS_OK(result)) {
937 /* Hit the cache code again. This cleans out the old connection and gets a new one */
938 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
939 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
940 return result;
942 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
943 des_access, &conn->pol);
946 if (!NT_STATUS_IS_OK(result)) {
947 cli_shutdown(conn->cli);
948 DLIST_REMOVE(cm_conns, conn);
949 SAFE_FREE(conn);
950 return result;
954 hnd.pol = conn->pol;
955 hnd.cli = conn->cli;
957 *return_hnd = &hnd;
959 return NT_STATUS_OK;
962 /* Return a SAM policy handle on a domain */
964 NTSTATUS cm_get_sam_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
966 struct winbindd_cm_conn *conn;
967 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
968 NTSTATUS result;
969 static CLI_POLICY_HND hnd;
971 /* Look for existing connections */
973 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
974 return result;
976 /* This *shitty* code needs scrapping ! JRA */
978 if (policy_handle_is_valid(&conn->pol)) {
979 hnd.pol = conn->pol;
980 hnd.cli = conn->cli;
982 *return_hnd = &hnd;
984 return NT_STATUS_OK;
987 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
988 des_access, &conn->pol);
990 if (!NT_STATUS_IS_OK(result)) {
991 /* Hit the cache code again. This cleans out the old connection and gets a new one */
992 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
994 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
995 return result;
997 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
998 des_access, &conn->pol);
1001 if (!NT_STATUS_IS_OK(result)) {
1003 cli_shutdown(conn->cli);
1004 DLIST_REMOVE(cm_conns, conn);
1005 SAFE_FREE(conn);
1007 return result;
1011 hnd.pol = conn->pol;
1012 hnd.cli = conn->cli;
1014 *return_hnd = &hnd;
1016 return NT_STATUS_OK;
1019 /* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
1020 netlogon pipe as no handle is returned. */
1022 NTSTATUS cm_get_netlogon_cli(struct winbindd_domain *domain,
1023 const unsigned char *trust_passwd,
1024 uint32 sec_channel_type,
1025 BOOL fresh,
1026 struct cli_state **cli)
1028 NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1029 struct winbindd_cm_conn *conn;
1030 fstring lock_name;
1031 BOOL got_mutex;
1033 if (!cli)
1034 return NT_STATUS_INVALID_PARAMETER;
1036 /* Open an initial conection - keep the mutex. */
1038 find_cm_connection(domain, PIPE_NETLOGON, &conn);
1040 if ( fresh && (conn != NULL) ) {
1041 cli_shutdown(conn->cli);
1042 conn->cli = NULL;
1044 conn = NULL;
1046 /* purge connection from cache */
1047 find_cm_connection(domain, PIPE_NETLOGON, &conn);
1048 if (conn != NULL) {
1049 DEBUG(0,("Could not purge connection\n"));
1050 return NT_STATUS_UNSUCCESSFUL;
1054 if (conn != NULL) {
1055 *cli = conn->cli;
1056 return NT_STATUS_OK;
1059 result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
1061 if (!NT_STATUS_IS_OK(result))
1062 return result;
1064 fstr_sprintf(lock_name, "NETLOGON\\%s", conn->controller);
1066 if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
1067 DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
1070 if ( sec_channel_type == SEC_CHAN_DOMAIN )
1071 fstr_sprintf(conn->cli->mach_acct, "%s$", lp_workgroup());
1073 /* This must be the remote domain (not ours) for schannel */
1075 fstrcpy( conn->cli->domain, domain->name);
1077 result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd);
1079 if (got_mutex)
1080 secrets_named_mutex_release(lock_name);
1082 if (!NT_STATUS_IS_OK(result)) {
1083 cli_shutdown(conn->cli);
1084 DLIST_REMOVE(cm_conns, conn);
1085 SAFE_FREE(conn);
1086 return result;
1089 *cli = conn->cli;
1091 return result;
1094 /* Dump the current connection status */
1096 static void dump_conn_list(void)
1098 struct winbindd_cm_conn *con;
1100 DEBUG(0, ("\tDomain Controller Pipe\n"));
1102 for(con = cm_conns; con; con = con->next) {
1103 char *msg;
1105 /* Display pipe info */
1107 if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
1108 DEBUG(0, ("Error: not enough memory!\n"));
1109 } else {
1110 DEBUG(0, ("%s\n", msg));
1111 SAFE_FREE(msg);
1116 void winbindd_cm_status(void)
1118 /* List open connections */
1120 DEBUG(0, ("winbindd connection manager status:\n"));
1122 if (cm_conns)
1123 dump_conn_list();
1124 else
1125 DEBUG(0, ("\tNo active connections\n"));
1128 /* Close all cached connections */
1130 void winbindd_cm_flush(void)
1132 struct winbindd_cm_conn *conn, tmp;
1134 /* Flush connection cache */
1136 for (conn = cm_conns; conn; conn = conn->next) {
1138 if (!connection_ok(conn))
1139 continue;
1141 DEBUG(10, ("Closing connection to %s on %s\n",
1142 conn->pipe_name, conn->controller));
1144 if (conn->cli)
1145 cli_shutdown(conn->cli);
1147 tmp.next = conn->next;
1149 DLIST_REMOVE(cm_conns, conn);
1150 SAFE_FREE(conn);
1151 conn = &tmp;
1154 /* Flush failed connection cache */
1156 flush_negative_conn_cache();