r6299: last commits for 3.0.14
[Samba.git] / source / nsswitch / winbindd_cm.c
blobc5cf1d5f4646554caec3bbb643ad49531e7033c2
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, ("cm_get_ipc_userpass: Retrieved auth-user from secrets.tdb [%s\\%s]\n",
106 *domain, *username));
108 } else {
109 DEBUG(3, ("cm_get_ipc_userpass: No auth-user defined\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 /* Windows 2003 SP1 does not lie LsaOpenPolicy() over schannel.
380 Returns RPC_NT_CANNOT_SUPPPORT (0xc0020041) for that call.
381 So just drop it on the lsarpc pipe */
383 if ( (domain->primary || IS_DC) && (pipe_index!=PI_LSARPC) ) {
384 NTSTATUS status = setup_schannel( *cli, domain->name );
385 if (!NT_STATUS_IS_OK(status)) {
386 DEBUG(3,("schannel refused - continuing without "
387 "schannel (%s)\n", nt_errstr(status)));
391 /* set the domain if empty; needed for schannel connections */
392 if ( !*(*cli)->domain )
393 fstrcpy( (*cli)->domain, domain->name );
395 if ( !cli_nt_session_open (*cli, pipe_index) ) {
397 result = NT_STATUS_PIPE_NOT_AVAILABLE;
399 /* This might be a NT4 DC */
400 if ( is_win2k_pipe(pipe_index) )
401 add_failed_connection = False;
403 cli_shutdown(*cli);
404 goto done;
407 result = NT_STATUS_OK;
408 add_failed_connection = False;
410 done:
411 if (got_mutex)
412 secrets_named_mutex_release(controller);
414 SAFE_FREE(machine_password);
415 SAFE_FREE(machine_krb5_principal);
416 SAFE_FREE(ipc_username);
417 SAFE_FREE(ipc_domain);
418 SAFE_FREE(ipc_password);
420 if (add_failed_connection)
421 add_failed_connection_entry(domain->name, controller, result);
423 return result;
426 struct dc_name_ip {
427 fstring name;
428 struct in_addr ip;
431 static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
432 const char *dcname, struct in_addr ip,
433 struct dc_name_ip **dcs, int *num)
435 if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname)))
436 return False;
438 *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
440 if (*dcs == NULL)
441 return False;
443 fstrcpy((*dcs)[*num].name, dcname);
444 (*dcs)[*num].ip = ip;
445 *num += 1;
446 return True;
449 static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
450 struct in_addr ip, uint16 port,
451 struct sockaddr_in **addrs, int *num)
453 *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
455 if (*addrs == NULL)
456 return False;
458 (*addrs)[*num].sin_family = PF_INET;
459 putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
460 (*addrs)[*num].sin_port = htons(port);
462 *num += 1;
463 return True;
466 /*******************************************************************
467 convert an ip to a name
468 *******************************************************************/
470 static void dcip_to_name( const char *domainname, const char *realm, struct in_addr ip, fstring name )
472 /* try node status request first */
474 if ( name_status_find(domainname, 0x1c, 0x20, ip, name) )
475 return;
477 /* backup in case the ads stuff fails */
479 fstrcpy( name, inet_ntoa(ip) );
481 #ifdef WITH_ADS
482 /* for active directory servers, try to get the ldap server name.
483 None of these failure should be considered critical for now */
485 if ( lp_security() == SEC_ADS )
487 ADS_STRUCT *ads;
488 ADS_STATUS status;
490 ads = ads_init( realm, domainname, NULL );
491 ads->auth.flags |= ADS_AUTH_NO_BIND;
493 if ( !ads_try_connect( ads, inet_ntoa(ip), LDAP_PORT ) ) {
494 ads_destroy( &ads );
495 return;
498 status = ads_server_info(ads);
499 if ( !ADS_ERR_OK(status) ) {
500 ads_destroy( &ads );
501 return;
504 fstrcpy(name, ads->config.ldap_server_name);
506 ads_destroy( &ads );
508 #endif
510 return;
514 /*******************************************************************
515 Retreive a list of IP address for domain controllers. Fill in
516 the dcs[] with results.
517 *******************************************************************/
519 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
520 struct dc_name_ip **dcs, int *num_dcs)
522 fstring dcname;
523 struct in_addr ip;
524 struct ip_service *ip_list = NULL;
525 int iplist_size = 0;
526 int i;
527 BOOL is_our_domain;
530 is_our_domain = strequal(domain->name, lp_workgroup());
532 if ( !is_our_domain
533 && get_dc_name_via_netlogon(domain, dcname, &ip)
534 && add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs) )
536 return True;
539 if ( is_our_domain
540 && must_use_pdc(domain->name)
541 && get_pdc_ip(domain->name, &ip))
543 if (add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip), ip, dcs, num_dcs))
544 return True;
547 /* try standard netbios queries first */
549 get_sorted_dc_list(domain->name, &ip_list, &iplist_size, False);
551 /* check for security = ads and use DNS if we can */
553 if ( iplist_size==0 && lp_security() == SEC_ADS )
554 get_sorted_dc_list(domain->alt_name, &ip_list, &iplist_size, True);
556 /* now add to the dc array. We'll wait until the last minute
557 to look up the name of the DC. But we fill in the char* for
558 the ip now in to make the failed connection cache work */
560 for ( i=0; i<iplist_size; i++ ) {
561 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip),
562 ip_list[i].ip, dcs, num_dcs);
565 SAFE_FREE( ip_list );
567 return True;
570 static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
571 const struct winbindd_domain *domain,
572 fstring dcname, struct sockaddr_in *addr, int *fd)
574 struct dc_name_ip *dcs = NULL;
575 int num_dcs = 0;
577 const char **dcnames = NULL;
578 int num_dcnames = 0;
580 struct sockaddr_in *addrs = NULL;
581 int num_addrs = 0;
583 int i, fd_index;
585 if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
586 return False;
588 for (i=0; i<num_dcs; i++) {
590 add_string_to_array(mem_ctx, dcs[i].name,
591 &dcnames, &num_dcnames);
592 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
593 &addrs, &num_addrs);
595 add_string_to_array(mem_ctx, dcs[i].name,
596 &dcnames, &num_dcnames);
597 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
598 &addrs, &num_addrs);
601 if ((num_dcnames == 0) || (num_dcnames != num_addrs))
602 return False;
604 if ( !open_any_socket_out(addrs, num_addrs, 10000, &fd_index, fd) )
606 for (i=0; i<num_dcs; i++) {
607 add_failed_connection_entry(domain->name,
608 dcs[i].name, NT_STATUS_UNSUCCESSFUL);
610 return False;
613 *addr = addrs[fd_index];
615 /* if we have no name on the server or just an IP address for
616 the name, now try to get the name */
618 if ( is_ipaddress(dcnames[fd_index]) || *dcnames[fd_index] == '\0' )
619 dcip_to_name( domain->name, domain->alt_name, addr->sin_addr, dcname );
620 else
621 fstrcpy(dcname, dcnames[fd_index]);
623 return True;
626 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
627 const int pipe_index,
628 struct winbindd_cm_conn *new_conn)
630 TALLOC_CTX *mem_ctx;
631 NTSTATUS result;
633 int retries;
635 if ((mem_ctx = talloc_init("cm_open_connection")) == NULL)
636 return NT_STATUS_NO_MEMORY;
638 for (retries = 0; retries < 3; retries++) {
640 int fd = -1;
641 BOOL retry;
643 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
645 if ((strlen(domain->dcname) > 0) &&
646 NT_STATUS_IS_OK(check_negative_conn_cache(domain->name,
647 domain->dcname))) {
648 int dummy;
649 if (!open_any_socket_out(&domain->dcaddr, 1, 10000,
650 &dummy, &fd)) {
651 fd = -1;
655 if ((fd == -1) &&
656 !find_new_dc(mem_ctx, domain, domain->dcname,
657 &domain->dcaddr, &fd))
658 break;
660 new_conn->cli = NULL;
662 result = cm_prepare_connection(domain, fd, pipe_index,
663 domain->dcname,
664 &new_conn->cli, &retry);
666 if (NT_STATUS_IS_OK(result)) {
667 fstrcpy(new_conn->domain, domain->name);
668 /* Initialise SMB connection */
669 fstrcpy(new_conn->pipe_name,
670 get_pipe_name_from_index(pipe_index));
671 break;
674 if (!retry)
675 break;
678 talloc_destroy(mem_ctx);
679 return result;
682 /************************************************************************
683 Wrapper around statuc cm_open_connection to retreive a freshly
684 setup cli_state struct
685 ************************************************************************/
687 NTSTATUS cm_fresh_connection(struct winbindd_domain *domain, const int pipe_index,
688 struct cli_state **cli)
690 NTSTATUS result;
691 struct winbindd_cm_conn conn;
693 result = cm_open_connection( domain, pipe_index, &conn );
695 if ( NT_STATUS_IS_OK(result) )
696 *cli = conn.cli;
698 return result;
701 /* Return true if a connection is still alive */
703 static BOOL connection_ok(struct winbindd_cm_conn *conn)
705 if (!conn) {
706 smb_panic("Invalid parameter passed to connection_ok(): conn was NULL!\n");
707 return False;
710 if (!conn->cli) {
711 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
712 conn->controller, conn->domain, conn->pipe_name));
713 return False;
716 if (!conn->cli->initialised) {
717 DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
718 conn->controller, conn->domain, conn->pipe_name));
719 return False;
722 if (conn->cli->fd == -1) {
723 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
724 conn->controller, conn->domain, conn->pipe_name));
725 return False;
728 return True;
731 /* Search the cache for a connection. If there is a broken one,
732 shut it down properly and return NULL. */
734 static void find_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
735 struct winbindd_cm_conn **conn_out)
737 struct winbindd_cm_conn *conn;
739 for (conn = cm_conns; conn; ) {
740 if (strequal(conn->domain, domain->name) &&
741 strequal(conn->pipe_name, pipe_name)) {
742 if (!connection_ok(conn)) {
743 /* Dead connection - remove it. */
744 struct winbindd_cm_conn *conn_temp = conn->next;
745 if (conn->cli)
746 cli_shutdown(conn->cli);
747 DLIST_REMOVE(cm_conns, conn);
748 SAFE_FREE(conn);
749 conn = conn_temp; /* Keep the loop moving */
750 continue;
751 } else {
752 break;
755 conn = conn->next;
758 *conn_out = conn;
761 /* Initialize a new connection up to the RPC BIND. */
763 static NTSTATUS new_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
764 struct winbindd_cm_conn **conn_out)
766 struct winbindd_cm_conn *conn;
767 NTSTATUS result;
769 if (!(conn = SMB_MALLOC_P(struct winbindd_cm_conn)))
770 return NT_STATUS_NO_MEMORY;
772 ZERO_STRUCTP(conn);
774 if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
775 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
776 domain->name, pipe_name, nt_errstr(result)));
777 SAFE_FREE(conn);
778 return result;
780 DLIST_ADD(cm_conns, conn);
782 *conn_out = conn;
783 return NT_STATUS_OK;
786 /* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
788 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const char *pipe_name,
789 struct winbindd_cm_conn **conn_out)
791 find_cm_connection(domain, pipe_name, conn_out);
793 if (*conn_out != NULL)
794 return NT_STATUS_OK;
796 return new_cm_connection(domain, pipe_name, conn_out);
799 /**********************************************************************************
800 We can 'sense' certain things about the DC by it's replies to certain questions.
802 This tells us if this particular remote server is Active Directory, and if it is
803 native mode.
804 **********************************************************************************/
806 void set_dc_type_and_flags( struct winbindd_domain *domain )
808 NTSTATUS result;
809 struct winbindd_cm_conn conn;
810 DS_DOMINFO_CTR ctr;
811 TALLOC_CTX *mem_ctx = NULL;
813 ZERO_STRUCT( conn );
814 ZERO_STRUCT( ctr );
816 domain->native_mode = False;
817 domain->active_directory = False;
819 if (domain->internal) {
820 domain->initialized = True;
821 return;
824 if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
825 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n",
826 domain->name, nt_errstr(result)));
827 domain->initialized = True;
828 return;
831 if ( conn.cli ) {
832 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli,
833 conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
834 goto done;
838 if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING)
839 && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
840 domain->native_mode = True;
842 /* Cheat - shut down the DS pipe, and open LSA */
844 cli_nt_session_close(conn.cli);
846 if ( cli_nt_session_open (conn.cli, PI_LSARPC) ) {
847 char *domain_name = NULL;
848 char *dns_name = NULL;
849 DOM_SID *dom_sid = NULL;
851 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n", domain->name);
852 if (!mem_ctx) {
853 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
854 return;
857 result = cli_lsa_open_policy2(conn.cli, mem_ctx, True,
858 SEC_RIGHTS_MAXIMUM_ALLOWED,
859 &conn.pol);
861 if (NT_STATUS_IS_OK(result)) {
862 /* This particular query is exactly what Win2k clients use
863 to determine that the DC is active directory */
864 result = cli_lsa_query_info_policy2(conn.cli, mem_ctx,
865 &conn.pol,
866 12, &domain_name,
867 &dns_name, NULL,
868 NULL, &dom_sid);
871 if (NT_STATUS_IS_OK(result)) {
872 if (domain_name)
873 fstrcpy(domain->name, domain_name);
875 if (dns_name)
876 fstrcpy(domain->alt_name, dns_name);
878 if (dom_sid)
879 sid_copy(&domain->sid, dom_sid);
881 domain->active_directory = True;
882 } else {
884 result = cli_lsa_open_policy(conn.cli, mem_ctx, True,
885 SEC_RIGHTS_MAXIMUM_ALLOWED,
886 &conn.pol);
888 if (!NT_STATUS_IS_OK(result))
889 goto done;
891 result = cli_lsa_query_info_policy(conn.cli, mem_ctx,
892 &conn.pol, 5, &domain_name,
893 &dom_sid);
895 if (NT_STATUS_IS_OK(result)) {
896 if (domain_name)
897 fstrcpy(domain->name, domain_name);
899 if (dom_sid)
900 sid_copy(&domain->sid, dom_sid);
905 done:
907 DEBUG(3,("add_trusted_domain: %s is an %s %s domain\n", domain->name,
908 domain->active_directory ? "ADS" : "NT4",
909 domain->native_mode ? "native mode" :
910 ((domain->active_directory && !domain->native_mode) ? "mixed mode" : "")));
912 /* close the connection; no other calls use this pipe and it is called only
913 on reestablishing the domain list --jerry */
915 if ( conn.cli )
916 cli_shutdown( conn.cli );
918 talloc_destroy(mem_ctx);
920 domain->initialized = True;
922 return;
927 /* Return a LSA policy handle on a domain */
929 NTSTATUS cm_get_lsa_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
931 struct winbindd_cm_conn *conn;
932 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
933 NTSTATUS result;
934 static CLI_POLICY_HND hnd;
936 /* Look for existing connections */
938 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
939 return result;
941 /* This *shitty* code needs scrapping ! JRA */
943 if (policy_handle_is_valid(&conn->pol)) {
944 hnd.pol = conn->pol;
945 hnd.cli = conn->cli;
946 *return_hnd = &hnd;
948 return NT_STATUS_OK;
951 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
952 des_access, &conn->pol);
954 if (!NT_STATUS_IS_OK(result)) {
955 /* Hit the cache code again. This cleans out the old connection and gets a new one */
956 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
957 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
958 return result;
960 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
961 des_access, &conn->pol);
964 if (!NT_STATUS_IS_OK(result)) {
965 cli_shutdown(conn->cli);
966 DLIST_REMOVE(cm_conns, conn);
967 SAFE_FREE(conn);
968 return result;
972 hnd.pol = conn->pol;
973 hnd.cli = conn->cli;
975 *return_hnd = &hnd;
977 return NT_STATUS_OK;
980 /* Return a SAM policy handle on a domain */
982 NTSTATUS cm_get_sam_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
984 struct winbindd_cm_conn *conn;
985 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
986 NTSTATUS result;
987 static CLI_POLICY_HND hnd;
989 /* Look for existing connections */
991 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
992 return result;
994 /* This *shitty* code needs scrapping ! JRA */
996 if (policy_handle_is_valid(&conn->pol)) {
997 hnd.pol = conn->pol;
998 hnd.cli = conn->cli;
1000 *return_hnd = &hnd;
1002 return NT_STATUS_OK;
1005 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
1006 des_access, &conn->pol);
1008 if (!NT_STATUS_IS_OK(result)) {
1009 /* Hit the cache code again. This cleans out the old connection and gets a new one */
1010 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
1012 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
1013 return result;
1015 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
1016 des_access, &conn->pol);
1019 if (!NT_STATUS_IS_OK(result)) {
1021 cli_shutdown(conn->cli);
1022 DLIST_REMOVE(cm_conns, conn);
1023 SAFE_FREE(conn);
1025 /* log a message for possible Windows 2003 SP1 DC's */
1026 if ( NT_STATUS_EQUAL(result,NT_STATUS_ACCESS_DENIED) && (lp_security() == SEC_DOMAIN) ) {
1027 DEBUG(0,("samr_connect() received NT_STATUS_ACCESS_DENIED. If you are connecting \n"));
1028 DEBUGADD(0,("to a Windows 2003 SP1 DC, this is a known issue. There are two current \n"));
1029 DEBUGADD(0,("workarounds:\n"));
1030 DEBUGADD(0,("(a) Move your configuration to security = ads, or\n"));
1031 DEBUGADD(0,("(b) set 'client schannel = no' in smb.conf and use 'wbinfo --set-auth-user'\n"));
1032 DEBUGADD(0,(" to define the credentials when connecting to the DC\n"));
1035 return result;
1039 hnd.pol = conn->pol;
1040 hnd.cli = conn->cli;
1042 *return_hnd = &hnd;
1044 return NT_STATUS_OK;
1047 /* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
1048 netlogon pipe as no handle is returned. */
1050 NTSTATUS cm_get_netlogon_cli(struct winbindd_domain *domain,
1051 const unsigned char *trust_passwd,
1052 uint32 sec_channel_type,
1053 BOOL fresh,
1054 struct cli_state **cli)
1056 NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1057 struct winbindd_cm_conn *conn;
1058 fstring lock_name;
1059 BOOL got_mutex;
1061 if (!cli)
1062 return NT_STATUS_INVALID_PARAMETER;
1064 /* Open an initial conection - keep the mutex. */
1066 find_cm_connection(domain, PIPE_NETLOGON, &conn);
1068 if ( fresh && (conn != NULL) ) {
1069 cli_shutdown(conn->cli);
1070 conn->cli = NULL;
1072 conn = NULL;
1074 /* purge connection from cache */
1075 find_cm_connection(domain, PIPE_NETLOGON, &conn);
1076 if (conn != NULL) {
1077 DEBUG(0,("Could not purge connection\n"));
1078 return NT_STATUS_UNSUCCESSFUL;
1082 if (conn != NULL) {
1083 *cli = conn->cli;
1084 return NT_STATUS_OK;
1087 result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
1089 if (!NT_STATUS_IS_OK(result))
1090 return result;
1092 fstr_sprintf(lock_name, "NETLOGON\\%s", conn->controller);
1094 if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
1095 DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
1098 if ( sec_channel_type == SEC_CHAN_DOMAIN )
1099 fstr_sprintf(conn->cli->mach_acct, "%s$", lp_workgroup());
1101 /* This must be the remote domain (not ours) for schannel */
1103 fstrcpy( conn->cli->domain, domain->name);
1105 result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd);
1107 if (got_mutex)
1108 secrets_named_mutex_release(lock_name);
1110 if (!NT_STATUS_IS_OK(result)) {
1111 cli_shutdown(conn->cli);
1112 DLIST_REMOVE(cm_conns, conn);
1113 SAFE_FREE(conn);
1114 return result;
1117 *cli = conn->cli;
1119 return result;
1122 /* Dump the current connection status */
1124 static void dump_conn_list(void)
1126 struct winbindd_cm_conn *con;
1128 DEBUG(0, ("\tDomain Controller Pipe\n"));
1130 for(con = cm_conns; con; con = con->next) {
1131 char *msg;
1133 /* Display pipe info */
1135 if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
1136 DEBUG(0, ("Error: not enough memory!\n"));
1137 } else {
1138 DEBUG(0, ("%s\n", msg));
1139 SAFE_FREE(msg);
1144 void winbindd_cm_status(void)
1146 /* List open connections */
1148 DEBUG(0, ("winbindd connection manager status:\n"));
1150 if (cm_conns)
1151 dump_conn_list();
1152 else
1153 DEBUG(0, ("\tNo active connections\n"));
1156 /* Close all cached connections */
1158 void winbindd_cm_flush(void)
1160 struct winbindd_cm_conn *conn, tmp;
1162 /* Flush connection cache */
1164 for (conn = cm_conns; conn; conn = conn->next) {
1166 if (!connection_ok(conn))
1167 continue;
1169 DEBUG(10, ("Closing connection to %s on %s\n",
1170 conn->pipe_name, conn->controller));
1172 if (conn->cli)
1173 cli_shutdown(conn->cli);
1175 tmp.next = conn->next;
1177 DLIST_REMOVE(cm_conns, conn);
1178 SAFE_FREE(conn);
1179 conn = &tmp;
1182 /* Flush failed connection cache */
1184 flush_negative_conn_cache();