2 Unix SMB/CIFS implementation.
4 Winbind daemon connection manager
6 Copyright (C) Tim Potter 2001
7 Copyright (C) Andrew Bartlett 2002
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 We need to manage connections to domain controllers without having to
26 mess up the main winbindd code with other issues. The aim of the
27 connection manager is to:
29 - make connections to domain controllers and cache them
30 - re-establish connections when networks or servers go down
31 - centralise the policy on connection timeouts, domain controller
33 - manage re-entrancy for when winbindd becomes able to handle
34 multiple outstanding rpc requests
36 Why not have connection management as part of the rpc layer like tng?
37 Good question. This code may morph into libsmb/rpc_cache.c or something
38 like that but at the moment it's simply staying as part of winbind. I
39 think the TNG architecture of forcing every user of the rpc layer to use
40 the connection caching system is a bad idea. It should be an optional
41 method of using the routines.
43 The TNG design is quite good but I disagree with some aspects of the
51 - I'm pretty annoyed by all the make_nmb_name() stuff. It should be
52 moved down into another function.
54 - Take care when destroying cli_structs as they can be shared between
63 #define DBGC_CLASS DBGC_WINBIND
65 /* Global list of connections. Initially a DLIST but can become a hash
66 table or whatever later. */
68 struct winbindd_cm_conn
{
69 struct winbindd_cm_conn
*prev
, *next
;
73 struct cli_state
*cli
;
77 static struct winbindd_cm_conn
*cm_conns
= NULL
;
79 static NTSTATUS
get_connection_from_cache(struct winbindd_domain
*domain
,
80 const char *pipe_name
,
81 struct winbindd_cm_conn
**conn_out
);
83 /* Choose between anonymous or authenticated connections. We need to use
84 an authenticated connection if DCs have the RestrictAnonymous registry
85 entry set > 0, or the "Additional restrictions for anonymous
86 connections" set in the win2k Local Security Policy.
88 Caller to free() result in domain, username, password
91 static void cm_get_ipc_userpass(char **username
, char **domain
, char **password
)
93 *username
= secrets_fetch(SECRETS_AUTH_USER
, NULL
);
94 *domain
= secrets_fetch(SECRETS_AUTH_DOMAIN
, NULL
);
95 *password
= secrets_fetch(SECRETS_AUTH_PASSWORD
, NULL
);
97 if (*username
&& **username
) {
99 if (!*domain
|| !**domain
)
100 *domain
= smb_xstrdup(lp_workgroup());
102 if (!*password
|| !**password
)
103 *password
= smb_xstrdup("");
105 DEBUG(3, ("cm_get_ipc_userpass: Retrieved auth-user from secrets.tdb [%s\\%s]\n",
106 *domain
, *username
));
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
)
122 uchar trust_password
[16];
123 uint32 sec_channel_type
;
127 /* use the domain trust password if we're on a DC
128 and this is not our domain */
130 if ( IS_DC
&& !strequal(domain
, lp_workgroup()) ) {
133 if ( !secrets_fetch_trusted_domain_password( domain
,
136 return NT_STATUS_UNSUCCESSFUL
;
139 sec_channel_type
= SEC_CHAN_DOMAIN
;
140 E_md4hash(pass
, trust_password
);
144 if (!secrets_fetch_trust_account_password(lp_workgroup(),
145 trust_password
, NULL
, &sec_channel_type
))
147 return NT_STATUS_UNSUCCESSFUL
;
151 ret
= cli_nt_setup_netsec(cli
, sec_channel_type
,
152 AUTH_PIPE_NETSEC
| AUTH_PIPE_SIGN
, trust_password
);
157 static BOOL
get_dc_name_via_netlogon(const struct winbindd_domain
*domain
,
158 fstring dcname
, struct in_addr
*dc_ip
)
160 struct winbindd_domain
*our_domain
;
162 struct winbindd_cm_conn
*conn
;
174 if ((our_domain
= find_our_domain()) == NULL
)
177 result
= get_connection_from_cache(our_domain
, PIPE_NETLOGON
, &conn
);
178 if (!NT_STATUS_IS_OK(result
))
181 if ((mem_ctx
= talloc_init("get_dc_name_via_netlogon")) == NULL
)
184 result
= cli_netlogon_getdcname(conn
->cli
, mem_ctx
, domain
->name
, tmp
);
186 talloc_destroy(mem_ctx
);
188 if (!NT_STATUS_IS_OK(result
))
191 /* cli_netlogon_getdcname gives us a name with \\ */
193 if (*p
== '\\') p
+=1;
194 if (*p
== '\\') p
+=1;
198 if (!resolve_name(dcname
, dc_ip
, 0x20))
204 /************************************************************************
205 Given a fd with a just-connected TCP connection to a DC, open a connection
207 ************************************************************************/
209 static NTSTATUS
cm_prepare_connection(const struct winbindd_domain
*domain
,
211 const int pipe_index
,
212 const char *controller
,
213 struct cli_state
**cli
,
216 char *machine_password
, *machine_krb5_principal
;
217 char *ipc_username
, *ipc_domain
, *ipc_password
;
220 BOOL add_failed_connection
= True
;
222 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
224 struct sockaddr peeraddr
;
225 socklen_t peeraddr_len
;
227 struct sockaddr_in
*peeraddr_in
= (struct sockaddr_in
*)&peeraddr
;
229 machine_password
= secrets_fetch_machine_password(lp_workgroup(), NULL
,
232 if (asprintf(&machine_krb5_principal
, "%s$@%s", global_myname(),
234 SAFE_FREE(machine_password
);
235 return NT_STATUS_NO_MEMORY
;
238 cm_get_ipc_userpass(&ipc_username
, &ipc_domain
, &ipc_password
);
242 got_mutex
= secrets_named_mutex(controller
,
243 WINBIND_SERVER_MUTEX_WAIT_TIME
);
246 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n",
248 result
= NT_STATUS_POSSIBLE_DEADLOCK
;
252 if ((*cli
= cli_initialise(NULL
)) == NULL
) {
253 DEBUG(1, ("Could not cli_initialize\n"));
254 result
= NT_STATUS_NO_MEMORY
;
258 (*cli
)->timeout
= 10000; /* 10 seconds */
260 fstrcpy((*cli
)->desthost
, controller
);
261 (*cli
)->use_kerberos
= True
;
263 peeraddr_len
= sizeof(peeraddr
);
265 if ((getpeername((*cli
)->fd
, &peeraddr
, &peeraddr_len
) != 0) ||
266 (peeraddr_len
!= sizeof(struct sockaddr_in
)) ||
267 (peeraddr_in
->sin_family
!= PF_INET
))
269 DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno
)));
273 if (ntohs(peeraddr_in
->sin_port
) == 139) {
274 struct nmb_name calling
;
275 struct nmb_name called
;
277 make_nmb_name(&calling
, global_myname(), 0x0);
278 make_nmb_name(&called
, "*SMBSERVER", 0x20);
280 if (!cli_session_request(*cli
, &calling
, &called
)) {
281 DEBUG(8, ("cli_session_request failed for %s\n",
287 cli_setup_signing_state(*cli
, Undefined
);
289 if (!cli_negprot(*cli
)) {
290 DEBUG(1, ("cli_negprot failed\n"));
297 if ((lp_security() == SEC_ADS
)
298 && ((*cli
)->protocol
>= PROTOCOL_NT1
&&
299 (*cli
)->capabilities
& CAP_EXTENDED_SECURITY
)) {
301 ADS_STATUS ads_status
;
302 (*cli
)->use_kerberos
= True
;
303 DEBUG(5, ("connecting to %s from %s with kerberos principal "
304 "[%s]\n", controller
, global_myname(),
305 machine_krb5_principal
));
307 ads_status
= cli_session_setup_spnego(*cli
,
308 machine_krb5_principal
,
312 if (!ADS_ERR_OK(ads_status
))
313 DEBUG(4,("failed kerberos session setup with %s\n",
314 ads_errstr(ads_status
)));
316 result
= ads_ntstatus(ads_status
);
319 if (NT_STATUS_IS_OK(result
))
320 goto session_setup_done
;
322 /* Fall back to non-kerberos session setup */
324 (*cli
)->use_kerberos
= False
;
326 if ((((*cli
)->sec_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
) != 0) &&
327 (strlen(ipc_username
) > 0)) {
329 /* Only try authenticated if we have a username */
331 DEBUG(5, ("connecting to %s from %s with username "
332 "[%s]\\[%s]\n", controller
, global_myname(),
333 ipc_domain
, ipc_username
));
335 if (cli_session_setup(*cli
, ipc_username
,
336 ipc_password
, strlen(ipc_password
)+1,
337 ipc_password
, strlen(ipc_password
)+1,
339 DEBUG(5, ("authenticated session setup failed\n"));
340 goto session_setup_done
;
344 /* Fall back to anonymous connection, this might fail later */
346 if (cli_session_setup(*cli
, "", NULL
, 0, NULL
, 0, "")) {
347 DEBUG(5, ("Connected anonymously\n"));
348 goto session_setup_done
;
351 result
= cli_nt_error(*cli
);
353 if (NT_STATUS_IS_OK(result
))
354 result
= NT_STATUS_UNSUCCESSFUL
;
356 /* We can't session setup */
362 if (!cli_send_tconX(*cli
, "IPC$", "IPC", "", 0)) {
364 result
= cli_nt_error(*cli
);
366 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result
)));
368 if (NT_STATUS_IS_OK(result
))
369 result
= NT_STATUS_UNSUCCESSFUL
;
375 secrets_named_mutex_release(controller
);
379 /* 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
;
407 result
= NT_STATUS_OK
;
408 add_failed_connection
= False
;
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
);
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
)))
438 *dcs
= TALLOC_REALLOC_ARRAY(mem_ctx
, *dcs
, struct dc_name_ip
, (*num
)+1);
443 fstrcpy((*dcs
)[*num
].name
, dcname
);
444 (*dcs
)[*num
].ip
= ip
;
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);
458 (*addrs
)[*num
].sin_family
= PF_INET
;
459 putip((char *)&((*addrs
)[*num
].sin_addr
), (char *)&ip
);
460 (*addrs
)[*num
].sin_port
= htons(port
);
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
) )
477 /* backup in case the ads stuff fails */
479 fstrcpy( name
, inet_ntoa(ip
) );
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
)
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
) ) {
498 status
= ads_server_info(ads
);
499 if ( !ADS_ERR_OK(status
) ) {
504 fstrcpy(name
, ads
->config
.ldap_server_name
);
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
)
524 struct ip_service
*ip_list
= NULL
;
530 is_our_domain
= strequal(domain
->name
, lp_workgroup());
533 && get_dc_name_via_netlogon(domain
, dcname
, &ip
)
534 && add_one_dc_unique(mem_ctx
, domain
->name
, dcname
, ip
, dcs
, num_dcs
) )
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
))
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
);
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
;
577 const char **dcnames
= NULL
;
580 struct sockaddr_in
*addrs
= NULL
;
585 if (!get_dcs(mem_ctx
, domain
, &dcs
, &num_dcs
) || (num_dcs
== 0))
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,
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,
601 if ((num_dcnames
== 0) || (num_dcnames
!= num_addrs
))
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
);
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
);
621 fstrcpy(dcname
, dcnames
[fd_index
]);
626 static NTSTATUS
cm_open_connection(struct winbindd_domain
*domain
,
627 const int pipe_index
,
628 struct winbindd_cm_conn
*new_conn
)
635 if ((mem_ctx
= talloc_init("cm_open_connection")) == NULL
)
636 return NT_STATUS_NO_MEMORY
;
638 for (retries
= 0; retries
< 3; retries
++) {
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
,
649 if (!open_any_socket_out(&domain
->dcaddr
, 1, 10000,
656 !find_new_dc(mem_ctx
, domain
, domain
->dcname
,
657 &domain
->dcaddr
, &fd
))
660 new_conn
->cli
= NULL
;
662 result
= cm_prepare_connection(domain
, fd
, pipe_index
,
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
));
678 talloc_destroy(mem_ctx
);
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
)
691 struct winbindd_cm_conn conn
;
693 result
= cm_open_connection( domain
, pipe_index
, &conn
);
695 if ( NT_STATUS_IS_OK(result
) )
701 /* Return true if a connection is still alive */
703 static BOOL
connection_ok(struct winbindd_cm_conn
*conn
)
706 smb_panic("Invalid parameter passed to connection_ok(): conn was NULL!\n");
711 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
712 conn
->controller
, conn
->domain
, conn
->pipe_name
));
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
));
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
));
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
;
746 cli_shutdown(conn
->cli
);
747 DLIST_REMOVE(cm_conns
, conn
);
749 conn
= conn_temp
; /* Keep the loop moving */
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
;
769 if (!(conn
= SMB_MALLOC_P(struct winbindd_cm_conn
)))
770 return NT_STATUS_NO_MEMORY
;
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
)));
780 DLIST_ADD(cm_conns
, conn
);
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
)
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
804 **********************************************************************************/
806 void set_dc_type_and_flags( struct winbindd_domain
*domain
)
809 struct winbindd_cm_conn conn
;
811 TALLOC_CTX
*mem_ctx
= NULL
;
816 domain
->native_mode
= False
;
817 domain
->active_directory
= False
;
819 if (domain
->internal
) {
820 domain
->initialized
= True
;
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
;
832 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn
.cli
,
833 conn
.cli
->mem_ctx
, DsRolePrimaryDomainInfoBasic
, &ctr
)) ) {
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
);
853 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
857 result
= cli_lsa_open_policy2(conn
.cli
, mem_ctx
, True
,
858 SEC_RIGHTS_MAXIMUM_ALLOWED
,
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
,
871 if (NT_STATUS_IS_OK(result
)) {
873 fstrcpy(domain
->name
, domain_name
);
876 fstrcpy(domain
->alt_name
, dns_name
);
879 sid_copy(&domain
->sid
, dom_sid
);
881 domain
->active_directory
= True
;
884 result
= cli_lsa_open_policy(conn
.cli
, mem_ctx
, True
,
885 SEC_RIGHTS_MAXIMUM_ALLOWED
,
888 if (!NT_STATUS_IS_OK(result
))
891 result
= cli_lsa_query_info_policy(conn
.cli
, mem_ctx
,
892 &conn
.pol
, 5, &domain_name
,
895 if (NT_STATUS_IS_OK(result
)) {
897 fstrcpy(domain
->name
, domain_name
);
900 sid_copy(&domain
->sid
, dom_sid
);
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 */
916 cli_shutdown( conn
.cli
);
918 talloc_destroy(mem_ctx
);
920 domain
->initialized
= True
;
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
;
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
)))
941 /* This *shitty* code needs scrapping ! JRA */
943 if (policy_handle_is_valid(&conn
->pol
)) {
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
)))
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
);
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
;
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
)))
994 /* This *shitty* code needs scrapping ! JRA */
996 if (policy_handle_is_valid(&conn
->pol
)) {
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
)))
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
);
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"));
1039 hnd
.pol
= conn
->pol
;
1040 hnd
.cli
= conn
->cli
;
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
,
1054 struct cli_state
**cli
)
1056 NTSTATUS result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
1057 struct winbindd_cm_conn
*conn
;
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
);
1074 /* purge connection from cache */
1075 find_cm_connection(domain
, PIPE_NETLOGON
, &conn
);
1077 DEBUG(0,("Could not purge connection\n"));
1078 return NT_STATUS_UNSUCCESSFUL
;
1084 return NT_STATUS_OK
;
1087 result
= new_cm_connection(domain
, PIPE_NETLOGON
, &conn
);
1089 if (!NT_STATUS_IS_OK(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
);
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
);
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
) {
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"));
1138 DEBUG(0, ("%s\n", msg
));
1144 void winbindd_cm_status(void)
1146 /* List open connections */
1148 DEBUG(0, ("winbindd connection manager status:\n"));
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
))
1169 DEBUG(10, ("Closing connection to %s on %s\n",
1170 conn
->pipe_name
, conn
->controller
));
1173 cli_shutdown(conn
->cli
);
1175 tmp
.next
= conn
->next
;
1177 DLIST_REMOVE(cm_conns
, conn
);
1182 /* Flush failed connection cache */
1184 flush_negative_conn_cache();