r7415: * big change -- volker's new async winbindd from trunk
[Samba/gbeck.git] / source / nsswitch / winbindd_cm.c
bloba6f09f4bf291c4aa044b3bb07dbdf0cec533e448
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon connection manager
6 Copyright (C) Tim Potter 2001
7 Copyright (C) Andrew Bartlett 2002
8 Copyright (C) Gerald (Jerry) Carter 2003-2005.
9 Copyright (C) Volker Lendecke 2004-2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 We need to manage connections to domain controllers without having to
28 mess up the main winbindd code with other issues. The aim of the
29 connection manager is to:
31 - make connections to domain controllers and cache them
32 - re-establish connections when networks or servers go down
33 - centralise the policy on connection timeouts, domain controller
34 selection etc
35 - manage re-entrancy for when winbindd becomes able to handle
36 multiple outstanding rpc requests
38 Why not have connection management as part of the rpc layer like tng?
39 Good question. This code may morph into libsmb/rpc_cache.c or something
40 like that but at the moment it's simply staying as part of winbind. I
41 think the TNG architecture of forcing every user of the rpc layer to use
42 the connection caching system is a bad idea. It should be an optional
43 method of using the routines.
45 The TNG design is quite good but I disagree with some aspects of the
46 implementation. -tpot
51 TODO:
53 - I'm pretty annoyed by all the make_nmb_name() stuff. It should be
54 moved down into another function.
56 - Take care when destroying cli_structs as they can be shared between
57 various sam handles.
61 #include "includes.h"
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 /* Choose between anonymous or authenticated connections. We need to use
71 an authenticated connection if DCs have the RestrictAnonymous registry
72 entry set > 0, or the "Additional restrictions for anonymous
73 connections" set in the win2k Local Security Policy.
75 Caller to free() result in domain, username, password
78 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
80 *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
81 *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
82 *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
84 if (*username && **username) {
86 if (!*domain || !**domain)
87 *domain = smb_xstrdup(lp_workgroup());
89 if (!*password || !**password)
90 *password = smb_xstrdup("");
92 DEBUG(3, ("cm_get_ipc_userpass: Retrieved auth-user from secrets.tdb [%s\\%s]\n",
93 *domain, *username));
95 } else {
96 DEBUG(3, ("cm_get_ipc_userpass: No auth-user defined\n"));
97 *username = smb_xstrdup("");
98 *domain = smb_xstrdup("");
99 *password = smb_xstrdup("");
103 static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
104 fstring dcname, struct in_addr *dc_ip)
106 struct winbindd_domain *our_domain;
107 NTSTATUS result;
108 struct rpc_pipe_client *cli;
109 TALLOC_CTX *mem_ctx;
111 fstring tmp;
112 char *p;
114 /* Hmmmm. We can only open one connection to the NETLOGON pipe at the
115 * moment.... */
117 if (IS_DC)
118 return False;
120 if (domain->primary)
121 return False;
123 our_domain = find_our_domain();
125 if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL)
126 return False;
129 /* These var's can be ignored -- we're not requesting
130 anything in the credential chain here */
131 unsigned char *session_key;
132 DOM_CRED *creds;
133 result = cm_connect_netlogon(our_domain, mem_ctx, &cli,
134 &session_key, &creds);
137 if (!NT_STATUS_IS_OK(result))
138 return False;
140 result = rpccli_netlogon_getdcname(cli, mem_ctx, domain->dcname,
141 domain->name, tmp);
143 talloc_destroy(mem_ctx);
145 if (!NT_STATUS_IS_OK(result))
146 return False;
148 /* cli_netlogon_getdcname gives us a name with \\ */
149 p = tmp;
150 if (*p == '\\') p+=1;
151 if (*p == '\\') p+=1;
153 fstrcpy(dcname, p);
155 if (!resolve_name(dcname, dc_ip, 0x20))
156 return False;
158 return True;
161 /************************************************************************
162 Given a fd with a just-connected TCP connection to a DC, open a connection
163 to the pipe.
164 ************************************************************************/
166 static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
167 const int sockfd,
168 const char *controller,
169 struct cli_state **cli,
170 BOOL *retry)
172 char *machine_password, *machine_krb5_principal;
173 char *ipc_username, *ipc_domain, *ipc_password;
175 BOOL got_mutex;
176 BOOL add_failed_connection = True;
178 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
180 struct sockaddr peeraddr;
181 socklen_t peeraddr_len;
183 struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
185 machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL,
186 NULL);
188 if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(),
189 lp_realm()) == -1) {
190 SAFE_FREE(machine_password);
191 return NT_STATUS_NO_MEMORY;
194 cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
196 *retry = True;
198 got_mutex = secrets_named_mutex(controller,
199 WINBIND_SERVER_MUTEX_WAIT_TIME);
201 if (!got_mutex) {
202 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n",
203 controller));
204 result = NT_STATUS_POSSIBLE_DEADLOCK;
205 goto done;
208 if ((*cli = cli_initialise(NULL)) == NULL) {
209 DEBUG(1, ("Could not cli_initialize\n"));
210 result = NT_STATUS_NO_MEMORY;
211 goto done;
214 (*cli)->timeout = 10000; /* 10 seconds */
215 (*cli)->fd = sockfd;
216 fstrcpy((*cli)->desthost, controller);
217 (*cli)->use_kerberos = True;
219 peeraddr_len = sizeof(peeraddr);
221 if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
222 (peeraddr_len != sizeof(struct sockaddr_in)) ||
223 (peeraddr_in->sin_family != PF_INET))
225 DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
226 goto done;
229 if (ntohs(peeraddr_in->sin_port) == 139) {
230 struct nmb_name calling;
231 struct nmb_name called;
233 make_nmb_name(&calling, global_myname(), 0x0);
234 make_nmb_name(&called, "*SMBSERVER", 0x20);
236 if (!cli_session_request(*cli, &calling, &called)) {
237 DEBUG(8, ("cli_session_request failed for %s\n",
238 controller));
239 goto done;
243 cli_setup_signing_state(*cli, Undefined);
245 if (!cli_negprot(*cli)) {
246 DEBUG(1, ("cli_negprot failed\n"));
247 cli_shutdown(*cli);
248 goto done;
251 /* Krb5 session */
253 if ((lp_security() == SEC_ADS)
254 && ((*cli)->protocol >= PROTOCOL_NT1 &&
255 (*cli)->capabilities & CAP_EXTENDED_SECURITY)) {
257 ADS_STATUS ads_status;
258 (*cli)->use_kerberos = True;
259 DEBUG(5, ("connecting to %s from %s with kerberos principal "
260 "[%s]\n", controller, global_myname(),
261 machine_krb5_principal));
263 ads_status = cli_session_setup_spnego(*cli,
264 machine_krb5_principal,
265 machine_password,
266 lp_workgroup());
268 if (!ADS_ERR_OK(ads_status))
269 DEBUG(4,("failed kerberos session setup with %s\n",
270 ads_errstr(ads_status)));
272 result = ads_ntstatus(ads_status);
275 if (NT_STATUS_IS_OK(result))
276 goto session_setup_done;
278 /* Fall back to non-kerberos session setup */
280 (*cli)->use_kerberos = False;
282 if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
283 (strlen(ipc_username) > 0)) {
285 /* Only try authenticated if we have a username */
287 DEBUG(5, ("connecting to %s from %s with username "
288 "[%s]\\[%s]\n", controller, global_myname(),
289 ipc_domain, ipc_username));
291 if (cli_session_setup(*cli, ipc_username,
292 ipc_password, strlen(ipc_password)+1,
293 ipc_password, strlen(ipc_password)+1,
294 ipc_domain)) {
295 DEBUG(5, ("authenticated session setup failed\n"));
296 goto session_setup_done;
300 /* Fall back to anonymous connection, this might fail later */
302 if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) {
303 DEBUG(5, ("Connected anonymously\n"));
304 goto session_setup_done;
307 result = cli_nt_error(*cli);
309 if (NT_STATUS_IS_OK(result))
310 result = NT_STATUS_UNSUCCESSFUL;
312 /* We can't session setup */
314 goto done;
316 session_setup_done:
318 if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
320 result = cli_nt_error(*cli);
322 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
324 if (NT_STATUS_IS_OK(result))
325 result = NT_STATUS_UNSUCCESSFUL;
327 cli_shutdown(*cli);
328 goto done;
331 secrets_named_mutex_release(controller);
332 got_mutex = False;
333 *retry = False;
335 /* set the domain if empty; needed for schannel connections */
336 if ( !*(*cli)->domain )
337 fstrcpy( (*cli)->domain, domain->name );
339 (*cli)->pipe_auth_flags = 0;
341 result = NT_STATUS_OK;
342 add_failed_connection = False;
344 done:
345 if (got_mutex)
346 secrets_named_mutex_release(controller);
348 SAFE_FREE(machine_password);
349 SAFE_FREE(machine_krb5_principal);
350 SAFE_FREE(ipc_username);
351 SAFE_FREE(ipc_domain);
352 SAFE_FREE(ipc_password);
354 if (add_failed_connection)
355 add_failed_connection_entry(domain->name, controller, result);
357 return result;
360 struct dc_name_ip {
361 fstring name;
362 struct in_addr ip;
365 static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
366 const char *dcname, struct in_addr ip,
367 struct dc_name_ip **dcs, int *num)
369 if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname)))
370 return False;
372 *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
374 if (*dcs == NULL)
375 return False;
377 fstrcpy((*dcs)[*num].name, dcname);
378 (*dcs)[*num].ip = ip;
379 *num += 1;
380 return True;
383 static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
384 struct in_addr ip, uint16 port,
385 struct sockaddr_in **addrs, int *num)
387 *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
389 if (*addrs == NULL)
390 return False;
392 (*addrs)[*num].sin_family = PF_INET;
393 putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
394 (*addrs)[*num].sin_port = htons(port);
396 *num += 1;
397 return True;
400 static void mailslot_name(struct in_addr dc_ip, fstring name)
402 fstr_sprintf(name, "\\MAILSLOT\\NET\\GETDC%X", dc_ip.s_addr);
405 static BOOL send_getdc_request(struct in_addr dc_ip,
406 const char *domain_name,
407 const DOM_SID *sid)
409 pstring outbuf;
410 char *p;
411 fstring my_acct_name;
412 fstring my_mailslot;
414 mailslot_name(dc_ip, my_mailslot);
416 memset(outbuf, '\0', sizeof(outbuf));
418 p = outbuf;
420 SCVAL(p, 0, SAMLOGON);
421 p++;
423 SCVAL(p, 0, 0); /* Count pointer ... */
424 p++;
426 SIVAL(p, 0, 0); /* The sender's token ... */
427 p += 2;
429 p += dos_PutUniCode(p, global_myname(), sizeof(pstring), True);
430 fstr_sprintf(my_acct_name, "%s$", global_myname());
431 p += dos_PutUniCode(p, my_acct_name, sizeof(pstring), True);
433 memcpy(p, my_mailslot, strlen(my_mailslot)+1);
434 p += strlen(my_mailslot)+1;
436 SIVAL(p, 0, 0x80);
437 p+=4;
439 SIVAL(p, 0, sid_size(sid));
440 p+=4;
442 p = ALIGN4(p, outbuf);
444 sid_linearize(p, sid_size(sid), sid);
445 p += sid_size(sid);
447 SIVAL(p, 0, 1);
448 SSVAL(p, 4, 0xffff);
449 SSVAL(p, 6, 0xffff);
450 p+=8;
452 return cli_send_mailslot(False, "\\MAILSLOT\\NET\\NTLOGON", 0,
453 outbuf, PTR_DIFF(p, outbuf),
454 global_myname(), 0, domain_name, 0x1c,
455 dc_ip);
458 static BOOL receive_getdc_response(struct in_addr dc_ip,
459 const char *domain_name,
460 fstring dc_name)
462 struct packet_struct *packet;
463 fstring my_mailslot;
464 char *buf, *p;
465 fstring dcname, user, domain;
466 int len;
468 mailslot_name(dc_ip, my_mailslot);
470 packet = receive_unexpected(DGRAM_PACKET, 0, my_mailslot);
472 if (packet == NULL) {
473 DEBUG(5, ("Did not receive packet for %s\n", my_mailslot));
474 return False;
477 DEBUG(5, ("Received packet for %s\n", my_mailslot));
479 buf = packet->packet.dgram.data;
480 len = packet->packet.dgram.datasize;
482 if (len < 70) {
483 /* 70 is a completely arbitrary value to make sure
484 the SVAL below does not read uninitialized memory */
485 DEBUG(3, ("GetDC got short response\n"));
486 return False;
489 /* This should be (buf-4)+SVAL(buf-4, smb_vwv12)... */
490 p = buf+SVAL(buf, smb_vwv10);
492 if (CVAL(p,0) != SAMLOGON_R) {
493 DEBUG(8, ("GetDC got invalid response type %d\n", CVAL(p, 0)));
494 return False;
497 p+=2;
498 pull_ucs2(buf, dcname, p, sizeof(dcname), PTR_DIFF(buf+len, p),
499 STR_TERMINATE|STR_NOALIGN);
500 p = skip_unibuf(p, PTR_DIFF(buf+len, p));
501 pull_ucs2(buf, user, p, sizeof(dcname), PTR_DIFF(buf+len, p),
502 STR_TERMINATE|STR_NOALIGN);
503 p = skip_unibuf(p, PTR_DIFF(buf+len, p));
504 pull_ucs2(buf, domain, p, sizeof(dcname), PTR_DIFF(buf+len, p),
505 STR_TERMINATE|STR_NOALIGN);
506 p = skip_unibuf(p, PTR_DIFF(buf+len, p));
508 if (!strequal(domain, domain_name)) {
509 DEBUG(3, ("GetDC: Expected domain %s, got %s\n",
510 domain_name, domain));
511 return False;
514 p = dcname;
515 if (*p == '\\') p += 1;
516 if (*p == '\\') p += 1;
518 fstrcpy(dc_name, p);
520 DEBUG(10, ("GetDC gave name %s for domain %s\n",
521 dc_name, domain));
523 return True;
526 /*******************************************************************
527 convert an ip to a name
528 *******************************************************************/
530 static void dcip_to_name( const char *domainname, const char *realm,
531 const DOM_SID *sid, struct in_addr ip, fstring name )
533 int i;
535 /* try GETDC requests first */
537 send_getdc_request(ip, domainname, sid);
538 smb_msleep(100);
540 for (i=0; i<5; i++) {
541 if (receive_getdc_response(ip, domainname, name))
542 return;
543 smb_msleep(500);
546 /* try node status request */
548 if ( name_status_find(domainname, 0x1c, 0x20, ip, name) )
549 return;
551 /* backup in case the netbios stuff fails */
553 fstrcpy( name, inet_ntoa(ip) );
555 #ifdef WITH_ADS
556 /* for active directory servers, try to get the ldap server name.
557 None of these failure should be considered critical for now */
559 if ( lp_security() == SEC_ADS )
561 ADS_STRUCT *ads;
562 ADS_STATUS status;
564 ads = ads_init( realm, domainname, NULL );
565 ads->auth.flags |= ADS_AUTH_NO_BIND;
567 if ( !ads_try_connect( ads, inet_ntoa(ip), LDAP_PORT ) ) {
568 ads_destroy( &ads );
569 return;
572 status = ads_server_info(ads);
573 if ( !ADS_ERR_OK(status) ) {
574 ads_destroy( &ads );
575 return;
578 fstrcpy(name, ads->config.ldap_server_name);
580 ads_destroy( &ads );
582 #endif
584 return;
587 /*******************************************************************
588 Retreive a list of IP address for domain controllers. Fill in
589 the dcs[] with results.
590 *******************************************************************/
592 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
593 struct dc_name_ip **dcs, int *num_dcs)
595 fstring dcname;
596 struct in_addr ip;
597 struct ip_service *ip_list = NULL;
598 int iplist_size = 0;
599 int i;
600 BOOL is_our_domain;
603 is_our_domain = strequal(domain->name, lp_workgroup());
605 if ( !is_our_domain
606 && get_dc_name_via_netlogon(domain, dcname, &ip)
607 && add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs) )
609 return True;
612 if ( is_our_domain
613 && must_use_pdc(domain->name)
614 && get_pdc_ip(domain->name, &ip))
616 if (add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip), ip, dcs, num_dcs))
617 return True;
620 /* try standard netbios queries first */
622 get_sorted_dc_list(domain->name, &ip_list, &iplist_size, False);
624 /* check for security = ads and use DNS if we can */
626 if ( iplist_size==0 && lp_security() == SEC_ADS )
627 get_sorted_dc_list(domain->alt_name, &ip_list, &iplist_size, True);
629 /* FIXME!! this is where we should re-insert the GETDC requests --jerry */
631 /* now add to the dc array. We'll wait until the last minute
632 to look up the name of the DC. But we fill in the char* for
633 the ip now in to make the failed connection cache work */
635 for ( i=0; i<iplist_size; i++ ) {
636 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip),
637 ip_list[i].ip, dcs, num_dcs);
640 SAFE_FREE( ip_list );
642 return True;
645 static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
646 const struct winbindd_domain *domain,
647 fstring dcname, struct sockaddr_in *addr, int *fd)
649 struct dc_name_ip *dcs = NULL;
650 int num_dcs = 0;
652 const char **dcnames = NULL;
653 int num_dcnames = 0;
655 struct sockaddr_in *addrs = NULL;
656 int num_addrs = 0;
658 int i, fd_index;
660 if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
661 return False;
663 for (i=0; i<num_dcs; i++) {
665 add_string_to_array(mem_ctx, dcs[i].name,
666 &dcnames, &num_dcnames);
667 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
668 &addrs, &num_addrs);
670 add_string_to_array(mem_ctx, dcs[i].name,
671 &dcnames, &num_dcnames);
672 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
673 &addrs, &num_addrs);
676 if ((num_dcnames == 0) || (num_dcnames != num_addrs))
677 return False;
679 if ( !open_any_socket_out(addrs, num_addrs, 10000, &fd_index, fd) )
681 for (i=0; i<num_dcs; i++) {
682 add_failed_connection_entry(domain->name,
683 dcs[i].name, NT_STATUS_UNSUCCESSFUL);
685 return False;
688 *addr = addrs[fd_index];
690 /* if we have no name on the server or just an IP address for
691 the name, now try to get the name */
693 if ( is_ipaddress(dcnames[fd_index]) || *dcnames[fd_index] == '\0' )
694 dcip_to_name( domain->name, domain->alt_name, &domain->sid, addr->sin_addr, dcname );
695 else
696 fstrcpy(dcname, dcnames[fd_index]);
698 return True;
701 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
702 struct winbindd_cm_conn *new_conn)
704 TALLOC_CTX *mem_ctx;
705 NTSTATUS result;
707 int retries;
709 if ((mem_ctx = talloc_init("cm_open_connection")) == NULL)
710 return NT_STATUS_NO_MEMORY;
712 for (retries = 0; retries < 3; retries++) {
714 int fd = -1;
715 BOOL retry;
717 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
719 if ((strlen(domain->dcname) > 0) &&
720 NT_STATUS_IS_OK(check_negative_conn_cache(domain->name,
721 domain->dcname))) {
722 int dummy;
723 if (!open_any_socket_out(&domain->dcaddr, 1, 10000,
724 &dummy, &fd)) {
725 fd = -1;
729 if ((fd == -1) &&
730 !find_new_dc(mem_ctx, domain, domain->dcname,
731 &domain->dcaddr, &fd))
732 break;
734 new_conn->cli = NULL;
736 result = cm_prepare_connection(domain, fd, domain->dcname,
737 &new_conn->cli, &retry);
739 if (!retry)
740 break;
743 talloc_destroy(mem_ctx);
744 return result;
747 /* Return true if a connection is still alive */
749 void invalidate_cm_connection(struct winbindd_cm_conn *conn)
751 if (conn->samr_pipe != NULL) {
752 cli_rpc_close(conn->samr_pipe);
753 conn->samr_pipe = NULL;
756 if (conn->lsa_pipe != NULL) {
757 cli_rpc_close(conn->lsa_pipe);
758 conn->lsa_pipe = NULL;
761 if (conn->netlogon_auth2_pipe != NULL) {
762 cli_rpc_close(conn->netlogon_auth2_pipe);
763 conn->netlogon_auth2_pipe = NULL;
766 if (conn->netlogon_pipe != NULL) {
767 cli_rpc_close(conn->netlogon_pipe);
768 conn->netlogon_pipe = NULL;
771 if (conn->cli)
772 cli_shutdown(conn->cli);
774 conn->cli = NULL;
777 void close_conns_after_fork(void)
779 struct winbindd_domain *domain;
781 for (domain = domain_list(); domain; domain = domain->next) {
782 if (domain->conn.cli == NULL)
783 continue;
785 if (domain->conn.cli->fd == -1)
786 continue;
788 close(domain->conn.cli->fd);
789 domain->conn.cli->fd = -1;
793 static BOOL connection_ok(struct winbindd_domain *domain)
795 if (domain->conn.cli == NULL) {
796 DEBUG(8, ("Connection to %s for domain %s has NULL "
797 "cli!\n", domain->dcname, domain->name));
798 return False;
801 if (!domain->conn.cli->initialised) {
802 DEBUG(3, ("Connection to %s for domain %s was never "
803 "initialised!\n", domain->dcname, domain->name));
804 return False;
807 if (domain->conn.cli->fd == -1) {
808 DEBUG(3, ("Connection to %s for domain %s has died or was "
809 "never started (fd == -1)\n",
810 domain->dcname, domain->name));
811 return False;
814 return True;
817 /* Initialize a new connection up to the RPC BIND. */
819 static NTSTATUS init_dc_connection(struct winbindd_domain *domain)
821 if (connection_ok(domain))
822 return NT_STATUS_OK;
824 invalidate_cm_connection(&domain->conn);
826 return cm_open_connection(domain, &domain->conn);
829 /**********************************************************************************
830 We can 'sense' certain things about the DC by it's replies to certain questions.
832 This tells us if this particular remote server is Active Directory, and if it is
833 native mode.
834 **********************************************************************************/
836 void set_dc_type_and_flags( struct winbindd_domain *domain )
838 NTSTATUS result;
839 DS_DOMINFO_CTR ctr;
840 TALLOC_CTX *mem_ctx = NULL;
841 struct rpc_pipe_client *cli;
842 POLICY_HND pol;
844 char *domain_name = NULL;
845 char *dns_name = NULL;
846 DOM_SID *dom_sid = NULL;
848 ZERO_STRUCT( ctr );
850 domain->native_mode = False;
851 domain->active_directory = False;
853 if (domain->internal) {
854 domain->initialized = True;
855 return;
858 result = init_dc_connection(domain);
859 if (!NT_STATUS_IS_OK(result)) {
860 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection "
861 "to %s: (%s)\n", domain->name, nt_errstr(result)));
862 domain->initialized = True;
863 return;
866 cli = cli_rpc_open_noauth(domain->conn.cli, PI_LSARPC_DS);
868 if (cli == NULL) {
869 DEBUG(5, ("set_dc_type_and_flags: Could not bind to "
870 "PI_LSARPC_DS on domain %s: (%s)\n",
871 domain->name, nt_errstr(result)));
872 domain->initialized = True;
873 return;
876 result = rpccli_ds_getprimarydominfo(cli, cli->cli->mem_ctx,
877 DsRolePrimaryDomainInfoBasic,
878 &ctr);
879 cli_rpc_close(cli);
881 if (!NT_STATUS_IS_OK(result)) {
882 domain->initialized = True;
883 return;
886 if ((ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) &&
887 !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
888 domain->native_mode = True;
890 cli = cli_rpc_open_noauth(domain->conn.cli, PI_LSARPC);
892 if (cli == NULL) {
893 domain->initialized = True;
894 return;
897 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
898 domain->name);
899 if (!mem_ctx) {
900 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
901 return;
904 result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
905 SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
907 if (NT_STATUS_IS_OK(result)) {
908 /* This particular query is exactly what Win2k clients use
909 to determine that the DC is active directory */
910 result = rpccli_lsa_query_info_policy2(cli, mem_ctx, &pol,
911 12, &domain_name,
912 &dns_name, NULL,
913 NULL, &dom_sid);
916 if (NT_STATUS_IS_OK(result)) {
917 if (domain_name)
918 fstrcpy(domain->name, domain_name);
920 if (dns_name)
921 fstrcpy(domain->alt_name, dns_name);
923 if (dom_sid)
924 sid_copy(&domain->sid, dom_sid);
926 domain->active_directory = True;
927 } else {
929 result = rpccli_lsa_open_policy(cli, mem_ctx, True,
930 SEC_RIGHTS_MAXIMUM_ALLOWED,
931 &pol);
933 if (!NT_STATUS_IS_OK(result))
934 goto done;
936 result = rpccli_lsa_query_info_policy(cli, mem_ctx,
937 &pol, 5, &domain_name,
938 &dom_sid);
940 if (NT_STATUS_IS_OK(result)) {
941 if (domain_name)
942 fstrcpy(domain->name, domain_name);
944 if (dom_sid)
945 sid_copy(&domain->sid, dom_sid);
948 done:
950 cli_rpc_close(cli);
952 talloc_destroy(mem_ctx);
954 domain->initialized = True;
956 return;
959 static BOOL cm_get_schannel_key(struct winbindd_domain *domain,
960 TALLOC_CTX *mem_ctx,
961 unsigned char **session_key)
963 struct rpc_pipe_client *cli;
964 DOM_CRED *credentials;
966 if (lp_client_schannel() == False)
967 return False;
969 return NT_STATUS_IS_OK(cm_connect_netlogon(domain, mem_ctx,
970 &cli, session_key,
971 &credentials));
974 NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
975 struct rpc_pipe_client **cli, POLICY_HND *sam_handle)
977 struct winbindd_cm_conn *conn;
978 NTSTATUS result;
980 result = init_dc_connection(domain);
981 if (!NT_STATUS_IS_OK(result))
982 return result;
984 conn = &domain->conn;
986 if (conn->samr_pipe == NULL) {
987 unsigned char *session_key;
989 if (cm_get_schannel_key(domain, mem_ctx, &session_key))
990 conn->samr_pipe = cli_rpc_open_schannel(conn->cli,
991 PI_SAMR,
992 session_key,
993 domain->name);
994 else
995 conn->samr_pipe = cli_rpc_open_noauth(conn->cli,
996 PI_SAMR);
998 if (conn->samr_pipe == NULL) {
999 result = NT_STATUS_PIPE_NOT_AVAILABLE;
1000 goto done;
1003 result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1004 SEC_RIGHTS_MAXIMUM_ALLOWED,
1005 &conn->sam_connect_handle);
1006 if (!NT_STATUS_IS_OK(result))
1007 goto done;
1009 result = rpccli_samr_open_domain(conn->samr_pipe,
1010 mem_ctx,
1011 &conn->sam_connect_handle,
1012 SEC_RIGHTS_MAXIMUM_ALLOWED,
1013 &domain->sid,
1014 &conn->sam_domain_handle);
1017 done:
1018 if (!NT_STATUS_IS_OK(result)) {
1019 invalidate_cm_connection(conn);
1020 return NT_STATUS_UNSUCCESSFUL;
1023 *cli = conn->samr_pipe;
1024 *sam_handle = conn->sam_domain_handle;
1025 return result;
1028 NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
1029 struct rpc_pipe_client **cli, POLICY_HND *lsa_policy)
1031 struct winbindd_cm_conn *conn;
1032 NTSTATUS result;
1034 result = init_dc_connection(domain);
1035 if (!NT_STATUS_IS_OK(result))
1036 return result;
1038 conn = &domain->conn;
1040 if (conn->lsa_pipe == NULL) {
1041 unsigned char *session_key;
1043 if (cm_get_schannel_key(domain, mem_ctx, &session_key))
1044 conn->lsa_pipe = cli_rpc_open_schannel(conn->cli,
1045 PI_LSARPC,
1046 session_key,
1047 domain->name);
1048 else
1049 conn->lsa_pipe = cli_rpc_open_noauth(conn->cli,
1050 PI_LSARPC);
1052 if (conn->lsa_pipe == NULL) {
1053 result = NT_STATUS_PIPE_NOT_AVAILABLE;
1054 goto done;
1057 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
1058 SEC_RIGHTS_MAXIMUM_ALLOWED,
1059 &conn->lsa_policy);
1062 done:
1063 if (!NT_STATUS_IS_OK(result)) {
1064 invalidate_cm_connection(conn);
1065 return NT_STATUS_UNSUCCESSFUL;
1068 *cli = conn->lsa_pipe;
1069 *lsa_policy = conn->lsa_policy;
1070 return result;
1073 /*******************************************************************
1074 wrapper around retrieving the trust account password
1075 *******************************************************************/
1077 static BOOL get_trust_pw(const char *domain, uint8 ret_pwd[16],
1078 uint32 *channel)
1080 DOM_SID sid;
1081 char *pwd;
1082 time_t last_set_time;
1084 /* if we are a DC and this is not our domain, then lookup an account
1085 for the domain trust */
1087 if ( IS_DC && !strequal(domain, lp_workgroup()) &&
1088 lp_allow_trusted_domains() ) {
1090 if (!secrets_fetch_trusted_domain_password(domain, &pwd, &sid,
1091 &last_set_time)) {
1092 DEBUG(0, ("get_trust_pw: could not fetch trust "
1093 "account password for trusted domain %s\n",
1094 domain));
1095 return False;
1098 *channel = SEC_CHAN_DOMAIN;
1099 E_md4hash(pwd, ret_pwd);
1100 SAFE_FREE(pwd);
1102 return True;
1105 /* Just get the account for the requested domain. In the future this
1106 * might also cover to be member of more than one domain. */
1108 if (secrets_fetch_trust_account_password(domain, ret_pwd,
1109 &last_set_time, channel))
1110 return True;
1112 DEBUG(5, ("get_trust_pw: could not fetch trust account "
1113 "password for domain %s\n", domain));
1114 return False;
1117 NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
1118 TALLOC_CTX *mem_ctx,
1119 struct rpc_pipe_client **cli,
1120 unsigned char **session_key,
1121 DOM_CRED **credentials)
1123 struct winbindd_cm_conn *conn;
1124 NTSTATUS result;
1126 uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS;
1127 uint8 mach_pwd[16];
1128 uint32 sec_chan_type;
1129 DOM_CHAL clnt_chal, srv_chal, rcv_chal;
1130 const char *server_name;
1131 const char *account_name;
1132 UTIME zerotime;
1134 result = init_dc_connection(domain);
1135 if (!NT_STATUS_IS_OK(result))
1136 return result;
1138 conn = &domain->conn;
1140 if (conn->netlogon_pipe != NULL) {
1141 *cli = conn->netlogon_pipe;
1142 *session_key = (unsigned char *)&conn->sess_key;
1143 *credentials = &conn->clnt_cred;
1144 return NT_STATUS_OK;
1147 if (!get_trust_pw(domain->name, mach_pwd, &sec_chan_type))
1148 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1150 conn->netlogon_auth2_pipe = cli_rpc_open_noauth(conn->cli,
1151 PI_NETLOGON);
1152 if (conn->netlogon_auth2_pipe == NULL)
1153 return NT_STATUS_UNSUCCESSFUL;
1155 if (lp_client_schannel() != False)
1156 neg_flags |= NETLOGON_NEG_SCHANNEL;
1158 generate_random_buffer(clnt_chal.data, 8);
1160 server_name = talloc_asprintf(mem_ctx, "\\\\%s", domain->dcname);
1161 account_name = talloc_asprintf(mem_ctx, "%s$",
1162 domain->primary ?
1163 global_myname() : domain->name);
1165 if ((server_name == NULL) || (account_name == NULL))
1166 return NT_STATUS_NO_MEMORY;
1168 result = rpccli_net_req_chal(conn->netlogon_auth2_pipe, server_name,
1169 global_myname(), &clnt_chal, &srv_chal);
1170 if (!NT_STATUS_IS_OK(result))
1171 return result;
1173 /**************** Long-term Session key **************/
1175 /* calculate the session key */
1176 cred_session_key(&clnt_chal, &srv_chal, mach_pwd, conn->sess_key);
1177 memset((char *)conn->sess_key+8, '\0', 8);
1179 /* calculate auth2 credentials */
1180 zerotime.time = 0;
1181 cred_create(conn->sess_key, &clnt_chal, zerotime,
1182 &conn->clnt_cred.challenge);
1184 result = rpccli_net_auth2(conn->netlogon_auth2_pipe, server_name,
1185 account_name, sec_chan_type, global_myname(),
1186 &conn->clnt_cred.challenge, &neg_flags,
1187 &rcv_chal);
1189 if (!NT_STATUS_IS_OK(result))
1190 return result;
1192 zerotime.time = 0;
1193 if (!cred_assert(&rcv_chal, conn->sess_key, &srv_chal, zerotime)) {
1194 DEBUG(0, ("Server replied with bad credential\n"));
1195 return NT_STATUS_ACCESS_DENIED;
1198 if ((lp_client_schannel() == True) &&
1199 ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
1200 DEBUG(3, ("Server did not offer schannel\n"));
1201 cli_rpc_close(conn->netlogon_auth2_pipe);
1202 conn->netlogon_auth2_pipe = NULL;
1203 return NT_STATUS_ACCESS_DENIED;
1206 if ((lp_client_schannel() == False) ||
1207 ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
1208 /* keep the existing connection to NETLOGON open */
1209 conn->netlogon_pipe = conn->netlogon_auth2_pipe;
1210 conn->netlogon_auth2_pipe = NULL;
1211 *cli = conn->netlogon_pipe;
1212 *session_key = (unsigned char *)&conn->sess_key;
1213 *credentials = &conn->clnt_cred;
1214 return NT_STATUS_OK;
1217 conn->netlogon_pipe = cli_rpc_open_schannel(conn->cli, PI_NETLOGON,
1218 conn->sess_key,
1219 domain->name);
1221 if (conn->netlogon_pipe == NULL) {
1222 DEBUG(3, ("Could not open schannel'ed NETLOGON pipe\n"));
1223 cli_rpc_close(conn->netlogon_auth2_pipe);
1224 conn->netlogon_auth2_pipe = NULL;
1225 return NT_STATUS_ACCESS_DENIED;
1228 *cli = conn->netlogon_pipe;
1229 *session_key = (unsigned char *)&conn->sess_key;
1230 *credentials = &conn->clnt_cred;
1232 return NT_STATUS_OK;