This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
Child failed to find DC's. Reschedule check.
****************************************************************/
-static void msg_failed_to_go_online(int msg_type, struct process_id src, void *buf, size_t len)
+static void msg_failed_to_go_online(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
{
struct winbindd_domain *domain;
- const char *domainname = (const char *)buf;
+ const char *domainname = (const char *)data->data;
- if (buf == NULL || len == 0) {
+ if (data->data == NULL || data->length == 0) {
return;
}
Actually cause a reconnect from a message.
****************************************************************/
-static void msg_try_to_go_online(int msg_type, struct process_id src, void *buf, size_t len)
+static void msg_try_to_go_online(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
{
struct winbindd_domain *domain;
- const char *domainname = (const char *)buf;
+ const char *domainname = (const char *)data->data;
- if (buf == NULL || len == 0) {
+ if (data->data == NULL || data->length == 0) {
return;
}
/* Stop zombies */
CatchChild();
- message_block();
-
child_pid = sys_fork();
if (child_pid == -1) {
DEBUG(0, ("fork_child_dc_connect: Could not fork: %s\n", strerror(errno)));
- message_unblock();
return False;
}
if (child_pid != 0) {
/* Parent */
- message_register(MSG_WINBIND_TRY_TO_GO_ONLINE,msg_try_to_go_online);
- message_register(MSG_WINBIND_FAILED_TO_GO_ONLINE,msg_failed_to_go_online);
- message_unblock();
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_WINBIND_TRY_TO_GO_ONLINE,
+ msg_try_to_go_online);
+ messaging_register(winbind_messaging_context(), NULL,
+ MSG_WINBIND_FAILED_TO_GO_ONLINE,
+ msg_failed_to_go_online);
return True;
}
close_conns_after_fork();
if (!override_logfile) {
+ pstring logfile;
+ pstr_sprintf(logfile, "%s/log.winbindd-dc-connect", dyn_LOGFILEBASE);
+ lp_set_logfile(logfile);
reopen_logs();
}
if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs)) || (num_dcs == 0)) {
/* Still offline ? Can't find DC's. */
- message_send_pid(pid_to_procid(parent_pid), MSG_WINBIND_FAILED_TO_GO_ONLINE,
- domain->name,
- strlen(domain->name)+1, False);
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(parent_pid),
+ MSG_WINBIND_FAILED_TO_GO_ONLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name)+1);
_exit(0);
}
/* We got a DC. Send a message to our parent to get it to
try and do the same. */
- message_send_pid(pid_to_procid(parent_pid), MSG_WINBIND_TRY_TO_GO_ONLINE,
- domain->name,
- strlen(domain->name)+1, False);
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(parent_pid),
+ MSG_WINBIND_TRY_TO_GO_ONLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name)+1);
_exit(0);
}
Handler triggered if we're offline to try and detect a DC.
****************************************************************/
-static void check_domain_online_handler(struct timed_event *te,
+static void check_domain_online_handler(struct event_context *ctx,
+ struct timed_event *te,
const struct timeval *now,
void *private_data)
{
struct winbindd_domain *domain =
(struct winbindd_domain *)private_data;
- DEBUG(10,("check_domain_online_handler: called for domain %s\n",
- domain->name ));
+ DEBUG(10,("check_domain_online_handler: called for domain "
+ "%s (online = %s)\n", domain->name,
+ domain->online ? "True" : "False" ));
- if (domain->check_online_event) {
- TALLOC_FREE(domain->check_online_event);
- }
+ TALLOC_FREE(domain->check_online_event);
/* Are we still in "startup" mode ? */
DEBUG(10,("set_domain_offline: called for domain %s\n",
domain->name ));
- if (domain->check_online_event) {
- TALLOC_FREE(domain->check_online_event);
- }
+ TALLOC_FREE(domain->check_online_event);
if (domain->internal) {
DEBUG(3,("set_domain_offline: domain %s is internal - logic error.\n",
calc_new_online_timeout_check(domain);
- domain->check_online_event = add_timed_event( NULL,
+ domain->check_online_event = event_add_timed(winbind_event_context(),
+ NULL,
timeval_current_ofs(domain->check_online_timeout,0),
"check_domain_online_handler",
check_domain_online_handler,
/* The above *has* to succeed for winbindd to work. */
if (!domain->check_online_event) {
- smb_panic("set_domain_offline: failed to add online handler.\n");
+ smb_panic("set_domain_offline: failed to add online handler");
}
DEBUG(10,("set_domain_offline: added event handler for domain %s\n",
domain->name ));
+
+ /* Send an offline message to the idmap child when our
+ primary domain goes offline */
+
+ if ( domain->primary ) {
+ struct winbindd_child *idmap = idmap_child();
+
+ if ( idmap->pid != 0 ) {
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(idmap->pid),
+ MSG_WINBIND_OFFLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name)+1);
+ }
+ }
+
+ return;
}
/****************************************************************
domain->name ));
if (domain->internal) {
- DEBUG(3,("set_domain_offline: domain %s is internal - logic error.\n",
+ DEBUG(3,("set_domain_online: domain %s is internal - logic error.\n",
domain->name ));
return;
}
return;
}
+ winbindd_set_locator_kdc_envs(domain);
+
/* If we are waiting to get a krb5 ticket, trigger immediately. */
GetTimeOfDay(&now);
- set_event_dispatch_time("krb5_ticket_gain_handler", now);
+ set_event_dispatch_time(winbind_event_context(),
+ "krb5_ticket_gain_handler", now);
/* Ok, we're out of any startup mode now... */
domain->startup = False;
/* Ensure we have no online timeout checks. */
domain->check_online_timeout = 0;
- if (domain->check_online_event) {
- TALLOC_FREE(domain->check_online_event);
- }
+ TALLOC_FREE(domain->check_online_event);
/* Ensure we ignore any pending child messages. */
- message_deregister(MSG_WINBIND_TRY_TO_GO_ONLINE);
- message_deregister(MSG_WINBIND_FAILED_TO_GO_ONLINE);
+ messaging_deregister(winbind_messaging_context(),
+ MSG_WINBIND_TRY_TO_GO_ONLINE, NULL);
+ messaging_deregister(winbind_messaging_context(),
+ MSG_WINBIND_FAILED_TO_GO_ONLINE, NULL);
domain->online = True;
+
+ /* Send an online message to the idmap child when our
+ primary domain comes online */
+
+ if ( domain->primary ) {
+ struct winbindd_child *idmap = idmap_child();
+
+ if ( idmap->pid != 0 ) {
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(idmap->pid),
+ MSG_WINBIND_ONLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name)+1);
+ }
+ }
+
+ return;
}
/****************************************************************
DEBUG(10,("set_domain_online_request: domain %s was globally offline.\n",
domain->name ));
- domain->check_online_event = add_timed_event( NULL,
- timeval_current_ofs(5, 0),
- "check_domain_online_handler",
- check_domain_online_handler,
- domain);
+ domain->check_online_event = event_add_timed(winbind_event_context(),
+ NULL,
+ timeval_current_ofs(5, 0),
+ "check_domain_online_handler",
+ check_domain_online_handler,
+ domain);
/* The above *has* to succeed for winbindd to work. */
if (!domain->check_online_event) {
- smb_panic("set_domain_online_request: failed to add online handler.\n");
+ smb_panic("set_domain_online_request: failed to add online handler");
}
}
domain->startup = True;
tev.tv_sec += 5;
- set_event_dispatch_time("check_domain_online_handler", tev);
+
+ set_event_dispatch_time(winbind_event_context(), "check_domain_online_handler", tev);
}
/****************************************************************
add_failed_connection_entry(domain->alt_name, server, result);
saf_delete(domain->alt_name);
}
+ winbindd_unset_locator_kdc_env(domain);
}
/* Choose between anonymous or authenticated connections. We need to use
orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
- werr = rpccli_netlogon_getdcname(netlogon_pipe, mem_ctx, our_domain->dcname,
- domain->name, tmp);
+ werr = rpccli_netlogon_getanydcname(netlogon_pipe, mem_ctx, our_domain->dcname,
+ domain->name, tmp);
/* And restore our original timeout. */
cli_set_timeout(netlogon_pipe->cli, orig_timeout);
talloc_destroy(mem_ctx);
if (!W_ERROR_IS_OK(werr)) {
- DEBUG(10, ("rpccli_netlogon_getdcname failed: %s\n",
+ DEBUG(10, ("rpccli_netlogon_getanydcname failed: %s\n",
dos_errstr(werr)));
return False;
}
- /* cli_netlogon_getdcname gives us a name with \\ */
+ /* cli_netlogon_getanydcname gives us a name with \\ */
p = tmp;
if (*p == '\\') {
p+=1;
fstrcpy(dcname, p);
- DEBUG(10, ("rpccli_netlogon_getdcname returned %s\n", dcname));
+ DEBUG(10, ("rpccli_netlogon_getanydcname returned %s\n", dcname));
if (!resolve_name(dcname, dc_ip, 0x20)) {
return False;
"[%s]\n", controller, global_myname(),
machine_krb5_principal));
+ winbindd_set_locator_kdc_envs(domain);
+
ads_status = cli_session_setup_spnego(*cli,
machine_krb5_principal,
machine_password,
saf_store( domain->alt_name, (*cli)->desthost );
}
+ winbindd_set_locator_kdc_envs(domain);
+
if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
result = cli_nt_error(*cli);
SSVAL(p, 6, 0xffff);
p+=8;
- return cli_send_mailslot(False, "\\MAILSLOT\\NET\\NTLOGON", 0,
+ return cli_send_mailslot(winbind_messaging_context(),
+ False, "\\MAILSLOT\\NET\\NTLOGON", 0,
outbuf, PTR_DIFF(p, outbuf),
global_myname(), 0, domain_name, 0x1c,
dc_ip);
DEBUG(10,("dcip_to_name: flags = 0x%x\n", (unsigned int)ads->config.flags));
- if (domain->primary && (ads->config.flags & ADS_KDC) && ads_closest_dc(ads)) {
- /* We're going to use this KDC for this realm/domain.
- If we are using sites, then force the krb5 libs
- to use this KDC. */
-
- create_local_private_krb5_conf_for_domain(domain->alt_name,
- domain->name,
- ip);
+ if (domain->primary && (ads->config.flags & ADS_KDC)) {
+ if (ads_closest_dc(ads)) {
+ char *sitename = sitename_fetch(ads->config.realm);
+
+ /* We're going to use this KDC for this realm/domain.
+ If we are using sites, then force the krb5 libs
+ to use this KDC. */
+
+ create_local_private_krb5_conf_for_domain(domain->alt_name,
+ domain->name,
+ sitename,
+ ip);
+
+ SAFE_FREE(sitename);
+ } else {
+ /* use an off site KDC */
+ create_local_private_krb5_conf_for_domain(domain->alt_name,
+ domain->name,
+ NULL,
+ ip);
+ }
+ winbindd_set_locator_kdc_envs(domain);
/* Ensure we contact this DC also. */
saf_store( domain->name, name);
}
if (sec == SEC_ADS) {
+ char *sitename = NULL;
+
/* We need to make sure we know the local site before
doing any DNS queries, as this will restrict the
get_sorted_dc_list() call below to only fetching
/* Find any DC to get the site record.
We deliberately don't care about the
return here. */
- get_dc_name(domain->name, lp_realm(), dcname, &ip);
- /* Now do the site-specific AD dns lookup. */
- get_sorted_dc_list(domain->alt_name, &ip_list, &iplist_size, True);
+ get_dc_name(domain->name, domain->alt_name, dcname, &ip);
+
+ sitename = sitename_fetch(domain->alt_name);
+ if (sitename) {
+
+ /* Do the site-specific AD dns lookup first. */
+ get_sorted_dc_list(domain->alt_name, sitename, &ip_list, &iplist_size, True);
+
+ for ( i=0; i<iplist_size; i++ ) {
+ add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip),
+ ip_list[i].ip, dcs, num_dcs);
+ }
+
+ SAFE_FREE(ip_list);
+ SAFE_FREE(sitename);
+ iplist_size = 0;
+ }
+
+ /* Now we add DCs from the main AD dns lookup. */
+ get_sorted_dc_list(domain->alt_name, NULL, &ip_list, &iplist_size, True);
+
+ for ( i=0; i<iplist_size; i++ ) {
+ add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip),
+ ip_list[i].ip, dcs, num_dcs);
+ }
}
/* try standard netbios queries if no ADS */
- if (iplist_size==0)
- get_sorted_dc_list(domain->name, &ip_list, &iplist_size, False);
+ if (iplist_size==0) {
+ get_sorted_dc_list(domain->name, NULL, &ip_list, &iplist_size, False);
+ }
/* FIXME!! this is where we should re-insert the GETDC requests --jerry */
}
if (NT_STATUS_IS_OK(result)) {
+
+ winbindd_set_locator_kdc_envs(domain);
+
if (domain->online == False) {
/* We're changing state from offline to online. */
set_global_winbindd_state_online();
return init_dc_connection_network(domain);
}
+/******************************************************************************
+ Set the trust flags (direction and forest location) for a domain
+******************************************************************************/
+
+static BOOL set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
+{
+ struct winbindd_domain *our_domain;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ struct ds_domain_trust *domains = NULL;
+ int count = 0;
+ int i;
+ uint32 flags = (DS_DOMAIN_IN_FOREST |
+ DS_DOMAIN_DIRECT_OUTBOUND |
+ DS_DOMAIN_DIRECT_INBOUND);
+ struct rpc_pipe_client *cli;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s\n", domain->name ));
+
+ /* Our primary domain doesn't need to worry about trust flags.
+ Force it to go through the network setup */
+ if ( domain->primary ) {
+ return False;
+ }
+
+ our_domain = find_our_domain();
+
+ if ( !connection_ok(our_domain) ) {
+ DEBUG(3,("set_dc_type_and_flags_trustinfo: No connection to our domain!\n"));
+ return False;
+ }
+
+ /* This won't work unless our domain is AD */
+
+ if ( !our_domain->active_directory ) {
+ return False;
+ }
+
+ /* Use DsEnumerateDomainTrusts to get us the trust direction
+ and type */
+
+ result = cm_connect_netlogon(our_domain, &cli);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(5, ("set_dc_type_and_flags_trustinfo: Could not open "
+ "a connection to %s for PIPE_NETLOGON (%s)\n",
+ domain->name, nt_errstr(result)));
+ return False;
+ }
+
+ if ( (mem_ctx = talloc_init("set_dc_type_and_flags_trustinfo")) == NULL ) {
+ DEBUG(0,("set_dc_type_and_flags_trustinfo: talloc_init() failed!\n"));
+ return False;
+ }
+
+ result = rpccli_ds_enum_domain_trusts(cli, mem_ctx,
+ cli->cli->desthost,
+ flags, &domains,
+ (unsigned int *)&count);
+
+ /* Now find the domain name and get the flags */
+
+ for ( i=0; i<count; i++ ) {
+ if ( strequal( domain->name, domains[i].netbios_domain ) ) {
+ domain->domain_flags = domains[i].flags;
+ domain->domain_type = domains[i].trust_type;
+ domain->domain_trust_attribs = domains[i].trust_attributes;
+
+ if ( domain->domain_type == DS_DOMAIN_TRUST_TYPE_UPLEVEL )
+ domain->active_directory = True;
+
+ /* This flag is only set if the domain is *our*
+ primary domain and the primary domain is in
+ native mode */
+
+ domain->native_mode = (domain->domain_flags & DS_DOMAIN_NATIVE_MODE);
+
+ DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s is %sin "
+ "native mode.\n", domain->name,
+ domain->native_mode ? "" : "NOT "));
+
+ DEBUG(5,("set_dc_type_and_flags_trustinfo: domain %s is %s"
+ "running active directory.\n", domain->name,
+ domain->active_directory ? "" : "NOT "));
+
+
+ domain->initialized = True;
+
+ if ( !winbindd_can_contact_domain( domain) )
+ domain->internal = True;
+
+ break;
+ }
+ }
+
+ talloc_destroy( mem_ctx );
+
+ return domain->initialized;
+}
+
/******************************************************************************
We can 'sense' certain things about the DC by it's replies to certain
questions.
is native mode.
******************************************************************************/
-static void set_dc_type_and_flags( struct winbindd_domain *domain )
+static void set_dc_type_and_flags_connect( struct winbindd_domain *domain )
{
NTSTATUS result;
DS_DOMINFO_CTR ctr;
return;
}
- DEBUG(5, ("set_dc_type_and_flags: domain %s\n", domain->name ));
+ DEBUG(5, ("set_dc_type_and_flags_connect: domain %s\n", domain->name ));
cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC_DS,
&result);
if (cli == NULL) {
- DEBUG(5, ("set_dc_type_and_flags: Could not bind to "
+ DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
"PI_LSARPC_DS on domain %s: (%s)\n",
domain->name, nt_errstr(result)));
- return;
+
+ /* if this is just a non-AD domain we need to continue
+ * identifying so that we can in the end return with
+ * domain->initialized = True - gd */
+
+ goto no_lsarpc_ds;
}
result = rpccli_ds_getprimarydominfo(cli, cli->cli->mem_ctx,
cli_rpc_pipe_close(cli);
if (!NT_STATUS_IS_OK(result)) {
- DEBUG(5, ("set_dc_type_and_flags: rpccli_ds_getprimarydominfo "
+ DEBUG(5, ("set_dc_type_and_flags_connect: rpccli_ds_getprimarydominfo "
"on domain %s failed: (%s)\n",
domain->name, nt_errstr(result)));
return;
domain->native_mode = False;
}
+no_lsarpc_ds:
cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC, &result);
if (cli == NULL) {
- DEBUG(5, ("set_dc_type_and_flags: Could not bind to "
+ DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
"PI_LSARPC on domain %s: (%s)\n",
domain->name, nt_errstr(result)));
cli_rpc_pipe_close(cli);
mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
domain->name);
if (!mem_ctx) {
- DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
+ DEBUG(1, ("set_dc_type_and_flags_connect: talloc_init() failed\n"));
cli_rpc_pipe_close(cli);
return;
}
}
done:
- DEBUG(5, ("set_dc_type_and_flags: domain %s is %sin native mode.\n",
+ DEBUG(5, ("set_dc_type_and_flags_connect: domain %s is %sin native mode.\n",
domain->name, domain->native_mode ? "" : "NOT "));
- DEBUG(5,("set_dc_type_and_flags: domain %s is %srunning active directory.\n",
+ DEBUG(5,("set_dc_type_and_flags_connect: domain %s is %srunning active directory.\n",
domain->name, domain->active_directory ? "" : "NOT "));
cli_rpc_pipe_close(cli);
domain->initialized = True;
}
+/**********************************************************************
+ Set the domain_flags (trust attributes, domain operating modes, etc...
+***********************************************************************/
+
+static void set_dc_type_and_flags( struct winbindd_domain *domain )
+{
+ /* we always have to contact our primary domain */
+
+ if ( domain->primary ) {
+ DEBUG(10,("set_dc_type_and_flags: setting up flags for "
+ "primary domain\n"));
+ set_dc_type_and_flags_connect( domain );
+ return;
+ }
+
+ /* Use our DC to get the information if possible */
+
+ if ( !set_dc_type_and_flags_trustinfo( domain ) ) {
+ /* Otherwise, fallback to contacting the
+ domain directly */
+ set_dc_type_and_flags_connect( domain );
+ }
+
+ return;
+}
+
+
+
+/**********************************************************************
+***********************************************************************/
+
static BOOL cm_get_schannel_dcinfo(struct winbindd_domain *domain,
struct dcinfo **ppdc)
{
return NT_STATUS_OK;
}
- if (!get_trust_pw(domain->name, mach_pwd, &sec_chan_type)) {
+ if (domain->primary && !get_trust_pw(domain->name, mach_pwd, &sec_chan_type)) {
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
return result;
}
+ if ( !domain->primary ) {
+ /* Clear the schannel request bit and drop down */
+ neg_flags &= ~NETLOGON_NEG_SCHANNEL;
+ goto no_schannel;
+ }
+
if (lp_client_schannel() != False) {
neg_flags |= NETLOGON_NEG_SCHANNEL;
}
return NT_STATUS_ACCESS_DENIED;
}
+ no_schannel:
if ((lp_client_schannel() == False) ||
((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
+
+ /*
+ * NetSamLogonEx only works for schannel
+ */
+ domain->can_do_samlogon_ex = False;
+
/* We're done - just keep the existing connection to NETLOGON
* open */
conn->netlogon_pipe = netlogon_pipe;
return !NT_STATUS_IS_OK(result) ? result : NT_STATUS_PIPE_NOT_AVAILABLE;
}
+ /*
+ * Try NetSamLogonEx for AD domains
+ */
+ domain->can_do_samlogon_ex = domain->active_directory;
+
*cli = conn->netlogon_pipe;
return NT_STATUS_OK;
}