Copyright (C) Andrew Bartlett 2002
Copyright (C) Gerald (Jerry) Carter 2003-2005.
Copyright (C) Volker Lendecke 2004-2005
+ Copyright (C) Jeremy Allison 2006
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/>.
*/
/*
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
+struct dc_name_ip {
+ fstring name;
+ struct in_addr ip;
+};
+
+extern struct winbindd_methods reconnect_methods;
+extern BOOL override_logfile;
+
+static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain);
+static void set_dc_type_and_flags( struct winbindd_domain *domain );
+static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
+ struct dc_name_ip **dcs, int *num_dcs);
+
+/****************************************************************
+ Child failed to find DC's. Reschedule check.
+****************************************************************/
+
+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 *)data->data;
+
+ if (data->data == NULL || data->length == 0) {
+ return;
+ }
+
+ DEBUG(5,("msg_fail_to_go_online: received for domain %s.\n", domainname));
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+
+ if (strequal(domain->name, domainname)) {
+ if (domain->online) {
+ /* We're already online, ignore. */
+ DEBUG(5,("msg_fail_to_go_online: domain %s "
+ "already online.\n", domainname));
+ continue;
+ }
+
+ /* Reschedule the online check. */
+ set_domain_offline(domain);
+ break;
+ }
+ }
+}
+
+/****************************************************************
+ Actually cause a reconnect from a message.
+****************************************************************/
+
+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 *)data->data;
+
+ if (data->data == NULL || data->length == 0) {
+ return;
+ }
+
+ DEBUG(5,("msg_try_to_go_online: received for domain %s.\n", domainname));
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+
+ if (strequal(domain->name, domainname)) {
+
+ if (domain->online) {
+ /* We're already online, ignore. */
+ DEBUG(5,("msg_try_to_go_online: domain %s "
+ "already online.\n", domainname));
+ continue;
+ }
+
+ /* This call takes care of setting the online
+ flag to true if we connected, or re-adding
+ the offline handler if false. Bypasses online
+ check so always does network calls. */
+
+ init_dc_connection_network(domain);
+ break;
+ }
+ }
+}
+
+/****************************************************************
+ Fork a child to try and contact a DC. Do this as contacting a
+ DC requires blocking lookups and we don't want to block our
+ parent.
+****************************************************************/
+
+static BOOL fork_child_dc_connect(struct winbindd_domain *domain)
+{
+ struct dc_name_ip *dcs = NULL;
+ int num_dcs = 0;
+ TALLOC_CTX *mem_ctx = NULL;
+ pid_t child_pid;
+ pid_t parent_pid = sys_getpid();
+
+ /* Stop zombies */
+ CatchChild();
+
+ child_pid = sys_fork();
+
+ if (child_pid == -1) {
+ DEBUG(0, ("fork_child_dc_connect: Could not fork: %s\n", strerror(errno)));
+ return False;
+ }
+
+ if (child_pid != 0) {
+ /* Parent */
+ 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;
+ }
+
+ /* Child. */
+
+ /* Leave messages blocked - we will never process one. */
+
+ /* tdb needs special fork handling */
+ if (tdb_reopen_all(1) == -1) {
+ DEBUG(0,("tdb_reopen_all failed.\n"));
+ _exit(0);
+ }
+
+ 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();
+ }
+
+ mem_ctx = talloc_init("fork_child_dc_connect");
+ if (!mem_ctx) {
+ DEBUG(0,("talloc_init failed.\n"));
+ _exit(0);
+ }
+
+ if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs)) || (num_dcs == 0)) {
+ /* Still offline ? Can't find DC's. */
+ 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. */
+
+ 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 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 (online = %s)\n", domain->name,
+ domain->online ? "True" : "False" ));
+
+ TALLOC_FREE(domain->check_online_event);
+
+ /* Are we still in "startup" mode ? */
+
+ if (domain->startup && (now->tv_sec > domain->startup_time + 30)) {
+ /* No longer in "startup" mode. */
+ DEBUG(10,("check_domain_online_handler: domain %s no longer in 'startup' mode.\n",
+ domain->name ));
+ domain->startup = False;
+ }
+
+ /* We've been told to stay offline, so stay
+ that way. */
+
+ if (get_global_winbindd_state_offline()) {
+ DEBUG(10,("check_domain_online_handler: domain %s remaining globally offline\n",
+ domain->name ));
+ return;
+ }
+
+ /* Fork a child to test if it can contact a DC.
+ If it can then send ourselves a message to
+ cause a reconnect. */
+
+ fork_child_dc_connect(domain);
+}
+
+/****************************************************************
+ If we're still offline setup the timeout check.
+****************************************************************/
+
+static void calc_new_online_timeout_check(struct winbindd_domain *domain)
+{
+ int wbc = lp_winbind_cache_time();
+
+ if (domain->startup) {
+ domain->check_online_timeout = 10;
+ } else if (domain->check_online_timeout < wbc) {
+ domain->check_online_timeout = wbc;
+ }
+}
+
+/****************************************************************
+ Set domain offline and also add handler to put us back online
+ if we detect a DC.
+****************************************************************/
+
+void set_domain_offline(struct winbindd_domain *domain)
+{
+ DEBUG(10,("set_domain_offline: called for domain %s\n",
+ domain->name ));
+
+ TALLOC_FREE(domain->check_online_event);
+
+ if (domain->internal) {
+ DEBUG(3,("set_domain_offline: domain %s is internal - logic error.\n",
+ domain->name ));
+ return;
+ }
+
+ domain->online = False;
+
+ /* Offline domains are always initialized. They're
+ re-initialized when they go back online. */
+
+ domain->initialized = True;
+
+ /* We only add the timeout handler that checks and
+ allows us to go back online when we've not
+ been told to remain offline. */
+
+ if (get_global_winbindd_state_offline()) {
+ DEBUG(10,("set_domain_offline: domain %s remaining globally offline\n",
+ domain->name ));
+ return;
+ }
+
+ /* If we're in statup mode, check again in 10 seconds, not in
+ lp_winbind_cache_time() seconds (which is 5 mins by default). */
+
+ calc_new_online_timeout_check(domain);
+
+ 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,
+ domain);
+
+ /* The above *has* to succeed for winbindd to work. */
+ if (!domain->check_online_event) {
+ 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;
+}
+
+/****************************************************************
+ Set domain online - if allowed.
+****************************************************************/
+
+static void set_domain_online(struct winbindd_domain *domain)
+{
+ struct timeval now;
+
+ DEBUG(10,("set_domain_online: called for domain %s\n",
+ domain->name ));
+
+ if (domain->internal) {
+ DEBUG(3,("set_domain_online: domain %s is internal - logic error.\n",
+ domain->name ));
+ return;
+ }
+
+ if (get_global_winbindd_state_offline()) {
+ DEBUG(10,("set_domain_online: domain %s remaining globally offline\n",
+ domain->name ));
+ return;
+ }
+
+ winbindd_set_locator_kdc_envs(domain);
+
+ /* If we are waiting to get a krb5 ticket, trigger immediately. */
+ GetTimeOfDay(&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;
+
+ if (domain->online == False) {
+ /* We were offline - now we're online. We default to
+ using the MS-RPC backend if we started offline,
+ and if we're going online for the first time we
+ should really re-initialize the backends and the
+ checks to see if we're talking to an AD or NT domain.
+ */
+
+ domain->initialized = False;
+
+ /* 'reconnect_methods' is the MS-RPC backend. */
+ if (domain->backend == &reconnect_methods) {
+ domain->backend = NULL;
+ }
+ }
+
+ /* Ensure we have no online timeout checks. */
+ domain->check_online_timeout = 0;
+ TALLOC_FREE(domain->check_online_event);
+
+ /* Ensure we ignore any pending child messages. */
+ 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;
+}
+
+/****************************************************************
+ Requested to set a domain online.
+****************************************************************/
+
+void set_domain_online_request(struct winbindd_domain *domain)
+{
+ struct timeval tev;
+
+ DEBUG(10,("set_domain_online_request: called for domain %s\n",
+ domain->name ));
+
+ if (get_global_winbindd_state_offline()) {
+ DEBUG(10,("set_domain_online_request: domain %s remaining globally offline\n",
+ domain->name ));
+ return;
+ }
+
+ /* We've been told it's safe to go online and
+ try and connect to a DC. But I don't believe it
+ because network manager seems to lie.
+ Wait at least 5 seconds. Heuristics suck... */
+
+ if (!domain->check_online_event) {
+ /* If we've come from being globally offline we
+ don't have a check online event handler set.
+ We need to add one now we're trying to go
+ back online. */
+
+ DEBUG(10,("set_domain_online_request: domain %s was globally offline.\n",
+ domain->name ));
+
+ 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");
+ }
+ }
+
+ GetTimeOfDay(&tev);
+
+ /* Go into "startup" mode again. */
+ domain->startup_time = tev.tv_sec;
+ domain->startup = True;
+
+ tev.tv_sec += 5;
+
+ set_event_dispatch_time(winbind_event_context(), "check_domain_online_handler", tev);
+}
+
+/****************************************************************
+ Add -ve connection cache entries for domain and realm.
+****************************************************************/
+
+void winbind_add_failed_connection_entry(const struct winbindd_domain *domain,
+ const char *server,
+ NTSTATUS result)
+{
+ add_failed_connection_entry(domain->name, server, result);
+ /* If this was the saf name for the last thing we talked to,
+ remove it. */
+ saf_delete(domain->name);
+ if (*domain->alt_name) {
+ 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
an authenticated connection if DCs have the RestrictAnonymous registry
static void cm_get_ipc_userpass(char **username, char **domain, char **password)
{
- *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
- *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
- *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
+ *username = (char *)secrets_fetch(SECRETS_AUTH_USER, NULL);
+ *domain = (char *)secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
+ *password = (char *)secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
if (*username && **username) {
struct winbindd_domain *our_domain = NULL;
struct rpc_pipe_client *netlogon_pipe = NULL;
NTSTATUS result;
+ WERROR werr;
TALLOC_CTX *mem_ctx;
-
+ unsigned int orig_timeout;
fstring tmp;
char *p;
result = cm_connect_netlogon(our_domain, &netlogon_pipe);
if (!NT_STATUS_IS_OK(result)) {
+ talloc_destroy(mem_ctx);
return False;
}
- result = rpccli_netlogon_getdcname(netlogon_pipe, mem_ctx, our_domain->dcname,
- domain->name, tmp);
+ /* This call can take a long time - allow the server to time out.
+ 35 seconds should do it. */
+
+ orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
+
+ 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 (!NT_STATUS_IS_OK(result)) {
- DEBUG(10, ("rpccli_netlogon_getdcname failed: %s\n",
- nt_errstr(result)));
+ if (!W_ERROR_IS_OK(werr)) {
+ 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;
char *ipc_username, *ipc_domain, *ipc_password;
BOOL got_mutex;
- BOOL add_failed_connection = True;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
+ DEBUG(10,("cm_prepare_connection: connecting to DC %s for domain %s\n",
+ controller, domain->name ));
+
machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL,
NULL);
goto done;
}
- if ((*cli = cli_initialise(NULL)) == NULL) {
+ if ((*cli = cli_initialise()) == NULL) {
DEBUG(1, ("Could not cli_initialize\n"));
result = NT_STATUS_NO_MEMORY;
goto done;
(peeraddr_in->sin_family != PF_INET))
{
DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
+ result = NT_STATUS_UNSUCCESSFUL;
goto done;
}
if (!cli_session_request(*cli, &calling, &called)) {
DEBUG(8, ("cli_session_request failed for %s\n",
controller));
+ result = NT_STATUS_UNSUCCESSFUL;
goto done;
}
}
if (!cli_negprot(*cli)) {
DEBUG(1, ("cli_negprot failed\n"));
- cli_shutdown(*cli);
+ result = NT_STATUS_UNSUCCESSFUL;
goto done;
}
-
if ((*cli)->protocol >= PROTOCOL_NT1 && (*cli)->capabilities & CAP_EXTENDED_SECURITY) {
ADS_STATUS ads_status;
"[%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,
DEBUG(5, ("connecting to %s from %s with username "
"[%s]\\[%s]\n", controller, global_myname(),
- machine_account, machine_password));
+ lp_workgroup(), machine_account));
ads_status = cli_session_setup_spnego(*cli,
machine_account,
"[%s]\\[%s]\n", controller, global_myname(),
ipc_domain, ipc_username));
- if (cli_session_setup(*cli, ipc_username,
- ipc_password, strlen(ipc_password)+1,
- ipc_password, strlen(ipc_password)+1,
- ipc_domain)) {
+ if (NT_STATUS_IS_OK(cli_session_setup(
+ *cli, ipc_username,
+ ipc_password, strlen(ipc_password)+1,
+ ipc_password, strlen(ipc_password)+1,
+ ipc_domain))) {
/* Successful logon with given username. */
cli_init_creds(*cli, ipc_username, ipc_domain, ipc_password);
goto session_setup_done;
/* Fall back to anonymous connection, this might fail later */
- if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) {
+ if (NT_STATUS_IS_OK(cli_session_setup(*cli, "", NULL, 0,
+ NULL, 0, ""))) {
DEBUG(5, ("Connected anonymously\n"));
cli_init_creds(*cli, "", "", "");
goto session_setup_done;
session_setup_done:
+ /* cache the server name for later connections */
+
+ saf_store( domain->name, (*cli)->desthost );
+ if (domain->alt_name && (*cli)->use_kerberos) {
+ 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);
if (NT_STATUS_IS_OK(result))
result = NT_STATUS_UNSUCCESSFUL;
- cli_shutdown(*cli);
goto done;
}
}
result = NT_STATUS_OK;
- add_failed_connection = False;
done:
if (got_mutex) {
SAFE_FREE(ipc_domain);
SAFE_FREE(ipc_password);
- if (add_failed_connection) {
- add_failed_connection_entry(domain->name, controller, result);
+ if (!NT_STATUS_IS_OK(result)) {
+ winbind_add_failed_connection_entry(domain, controller, result);
+ if ((*cli) != NULL) {
+ cli_shutdown(*cli);
+ *cli = NULL;
+ }
}
return result;
}
-struct dc_name_ip {
- fstring name;
- struct in_addr ip;
-};
-
static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
const char *dcname, struct in_addr ip,
struct dc_name_ip **dcs, int *num)
{
*addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
- if (*addrs == NULL)
+ if (*addrs == NULL) {
+ *num = 0;
return False;
+ }
(*addrs)[*num].sin_family = PF_INET;
putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
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);
convert an ip to a name
*******************************************************************/
-static void dcip_to_name( const char *domainname, const char *realm,
- const DOM_SID *sid, struct in_addr ip, fstring name )
+static BOOL dcip_to_name(const struct winbindd_domain *domain, struct in_addr ip, fstring name )
{
+ struct ip_service ip_list;
- /* try GETDC requests first */
-
- if (send_getdc_request(ip, domainname, sid)) {
- int i;
- smb_msleep(100);
- for (i=0; i<5; i++) {
- if (receive_getdc_response(ip, domainname, name))
- return;
- smb_msleep(500);
- }
- }
-
- /* try node status request */
-
- if ( name_status_find(domainname, 0x1c, 0x20, ip, name) )
- return;
-
- /* backup in case the netbios stuff fails */
-
- fstrcpy( name, inet_ntoa(ip) );
+ ip_list.ip = ip;
+ ip_list.port = 0;
#ifdef WITH_ADS
- /* for active directory servers, try to get the ldap server name.
- None of these failure should be considered critical for now */
+ /* For active directory servers, try to get the ldap server name.
+ None of these failures should be considered critical for now */
- if ( lp_security() == SEC_ADS )
- {
+ if (lp_security() == SEC_ADS) {
ADS_STRUCT *ads;
- ADS_STATUS status;
- ads = ads_init( realm, domainname, NULL );
+ ads = ads_init(domain->alt_name, domain->name, NULL);
ads->auth.flags |= ADS_AUTH_NO_BIND;
- if ( !ads_try_connect( ads, inet_ntoa(ip), LDAP_PORT ) ) {
- ads_destroy( &ads );
- return;
- }
+ if (ads_try_connect( ads, inet_ntoa(ip) ) ) {
+ /* We got a cldap packet. */
+ fstrcpy(name, ads->config.ldap_server_name);
+ namecache_store(name, 0x20, 1, &ip_list);
+
+ DEBUG(10,("dcip_to_name: flags = 0x%x\n", (unsigned int)ads->config.flags));
+
+ 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);
+ saf_store( domain->alt_name, name);
+ }
- status = ads_server_info(ads);
- if ( !ADS_ERR_OK(status) ) {
ads_destroy( &ads );
- return;
+ return True;
}
- fstrcpy(name, ads->config.ldap_server_name);
-
ads_destroy( &ads );
}
#endif
- return;
+ /* try GETDC requests next */
+
+ if (send_getdc_request(ip, domain->name, &domain->sid)) {
+ int i;
+ smb_msleep(100);
+ for (i=0; i<5; i++) {
+ if (receive_getdc_response(ip, domain->name, name)) {
+ namecache_store(name, 0x20, 1, &ip_list);
+ return True;
+ }
+ smb_msleep(500);
+ }
+ }
+
+ /* try node status request */
+
+ if ( name_status_find(domain->name, 0x1c, 0x20, ip, name) ) {
+ namecache_store(name, 0x20, 1, &ip_list);
+ return True;
+ }
+ return False;
}
/*******************************************************************
int iplist_size = 0;
int i;
BOOL is_our_domain;
-
+ enum security_types sec = (enum security_types)lp_security();
is_our_domain = strequal(domain->name, lp_workgroup());
return True;
}
- if ( is_our_domain
- && must_use_pdc(domain->name)
- && get_pdc_ip(domain->name, &ip))
- {
- if (add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip), ip, dcs, num_dcs))
- return True;
- }
+ 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
+ DNS records for the correct site. */
- /* try standard netbios queries first */
+ /* Find any DC to get the site record.
+ We deliberately don't care about the
+ return here. */
- get_sorted_dc_list(domain->name, &ip_list, &iplist_size, False);
+ get_dc_name(domain->name, domain->alt_name, dcname, &ip);
- /* check for security = ads and use DNS if we can */
+ sitename = sitename_fetch(domain->alt_name);
+ if (sitename) {
- if ( iplist_size==0 && lp_security() == SEC_ADS )
- get_sorted_dc_list(domain->alt_name, &ip_list, &iplist_size, True);
+ /* 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, NULL, &ip_list, &iplist_size, False);
+ }
/* FIXME!! this is where we should re-insert the GETDC requests --jerry */
int i, fd_index;
+ again:
if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
return False;
for (i=0; i<num_dcs; i++) {
- add_string_to_array(mem_ctx, dcs[i].name,
- &dcnames, &num_dcnames);
- add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
- &addrs, &num_addrs);
+ if (!add_string_to_array(mem_ctx, dcs[i].name,
+ &dcnames, &num_dcnames)) {
+ return False;
+ }
+ if (!add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
+ &addrs, &num_addrs)) {
+ return False;
+ }
- add_string_to_array(mem_ctx, dcs[i].name,
- &dcnames, &num_dcnames);
- add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
- &addrs, &num_addrs);
+ if (!add_string_to_array(mem_ctx, dcs[i].name,
+ &dcnames, &num_dcnames)) {
+ return False;
+ }
+ if (!add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
+ &addrs, &num_addrs)) {
+ return False;
+ }
}
if ((num_dcnames == 0) || (num_dcnames != num_addrs))
return False;
- if ( !open_any_socket_out(addrs, num_addrs, 10000, &fd_index, fd) )
+ if ((addrs == NULL) || (dcnames == NULL))
+ return False;
+
+ /* 5 second timeout. */
+ if ( !open_any_socket_out(addrs, num_addrs, 5000, &fd_index, fd) )
{
for (i=0; i<num_dcs; i++) {
- add_failed_connection_entry(domain->name,
+ DEBUG(10, ("find_new_dc: open_any_socket_out failed for "
+ "domain %s address %s. Error was %s\n",
+ domain->name, inet_ntoa(dcs[i].ip), strerror(errno) ));
+ winbind_add_failed_connection_entry(domain,
dcs[i].name, NT_STATUS_UNSUCCESSFUL);
}
return False;
*addr = addrs[fd_index];
- /* if we have no name on the server or just an IP address for
- the name, now try to get the name */
-
- if ( is_ipaddress(dcnames[fd_index]) || *dcnames[fd_index] == '\0' )
- dcip_to_name( domain->name, domain->alt_name, &domain->sid, addr->sin_addr, dcname );
- else
+ if (*dcnames[fd_index] != '\0' && !is_ipaddress(dcnames[fd_index])) {
+ /* Ok, we've got a name for the DC */
fstrcpy(dcname, dcnames[fd_index]);
+ return True;
+ }
- return True;
+ /* Try to figure out the name */
+ if (dcip_to_name( domain, addr->sin_addr, dcname )) {
+ return True;
+ }
+
+ /* We can not continue without the DC's name */
+ winbind_add_failed_connection_entry(domain, dcs[fd_index].name,
+ NT_STATUS_UNSUCCESSFUL);
+ goto again;
}
static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
{
TALLOC_CTX *mem_ctx;
NTSTATUS result;
-
+ char *saf_servername = saf_fetch( domain->name );
int retries;
- if ((mem_ctx = talloc_init("cm_open_connection")) == NULL)
+ if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
+ SAFE_FREE(saf_servername);
+ set_domain_offline(domain);
return NT_STATUS_NO_MEMORY;
+ }
+
+ /* we have to check the server affinity cache here since
+ later we selecte a DC based on response time and not preference */
+
+ /* Check the negative connection cache
+ before talking to it. It going down may have
+ triggered the reconnection. */
+
+ if ( saf_servername && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, saf_servername))) {
+
+ DEBUG(10,("cm_open_connection: saf_servername is '%s' for domain %s\n",
+ saf_servername, domain->name ));
+
+ /* convert an ip address to a name */
+ if ( is_ipaddress( saf_servername ) ) {
+ fstring saf_name;
+ struct in_addr ip;
+
+ ip = *interpret_addr2( saf_servername );
+ if (dcip_to_name( domain, ip, saf_name )) {
+ fstrcpy( domain->dcname, saf_name );
+ } else {
+ winbind_add_failed_connection_entry(
+ domain, saf_servername,
+ NT_STATUS_UNSUCCESSFUL);
+ }
+ } else {
+ fstrcpy( domain->dcname, saf_servername );
+ }
+
+ SAFE_FREE( saf_servername );
+ }
for (retries = 0; retries < 3; retries++) {
result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
- if ((strlen(domain->dcname) > 0) &&
- NT_STATUS_IS_OK(check_negative_conn_cache(
- domain->name, domain->dcname)) &&
- (resolve_name(domain->dcname, &domain->dcaddr.sin_addr,
- 0x20))) {
- int dummy;
- struct sockaddr_in addrs[2];
- addrs[0] = domain->dcaddr;
- addrs[0].sin_port = htons(445);
- addrs[1] = domain->dcaddr;
- addrs[1].sin_port = htons(139);
- if (!open_any_socket_out(addrs, 2, 10000,
- &dummy, &fd)) {
+ DEBUG(10,("cm_open_connection: dcname is '%s' for domain %s\n",
+ domain->dcname, domain->name ));
+
+ if (*domain->dcname
+ && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
+ && (resolve_name(domain->dcname, &domain->dcaddr.sin_addr, 0x20)))
+ {
+ struct sockaddr_in *addrs = NULL;
+ int num_addrs = 0;
+ int dummy = 0;
+
+ if (!add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 445, &addrs, &num_addrs)) {
+ set_domain_offline(domain);
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (!add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 139, &addrs, &num_addrs)) {
+ set_domain_offline(domain);
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* 5 second timeout. */
+ if (!open_any_socket_out(addrs, num_addrs, 5000, &dummy, &fd)) {
fd = -1;
}
}
- if ((fd == -1) &&
- !find_new_dc(mem_ctx, domain, domain->dcname,
- &domain->dcaddr, &fd))
+ if ((fd == -1)
+ && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd))
+ {
+ /* This is the one place where we will
+ set the global winbindd offline state
+ to true, if a "WINBINDD_OFFLINE" entry
+ is found in the winbindd cache. */
+ set_global_winbindd_state_offline();
break;
+ }
new_conn->cli = NULL;
break;
}
+ 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();
+ }
+ set_domain_online(domain);
+ } else {
+ /* Ensure we setup the retry handler. */
+ set_domain_offline(domain);
+ }
+
talloc_destroy(mem_ctx);
return result;
}
-/* Return true if a connection is still alive */
+/* Close down all open pipes on a connection. */
void invalidate_cm_connection(struct winbindd_cm_conn *conn)
{
+ /* We're closing down a possibly dead
+ connection. Don't have impossibly long (10s) timeouts. */
+
+ if (conn->cli) {
+ cli_set_timeout(conn->cli, 1000); /* 1 second. */
+ }
+
if (conn->samr_pipe != NULL) {
- cli_rpc_pipe_close(conn->samr_pipe);
+ if (!cli_rpc_pipe_close(conn->samr_pipe)) {
+ /* Ok, it must be dead. Drop timeout to 0.5 sec. */
+ if (conn->cli) {
+ cli_set_timeout(conn->cli, 500);
+ }
+ }
conn->samr_pipe = NULL;
}
if (conn->lsa_pipe != NULL) {
- cli_rpc_pipe_close(conn->lsa_pipe);
+ if (!cli_rpc_pipe_close(conn->lsa_pipe)) {
+ /* Ok, it must be dead. Drop timeout to 0.5 sec. */
+ if (conn->cli) {
+ cli_set_timeout(conn->cli, 500);
+ }
+ }
conn->lsa_pipe = NULL;
}
if (conn->netlogon_pipe != NULL) {
- cli_rpc_pipe_close(conn->netlogon_pipe);
+ if (!cli_rpc_pipe_close(conn->netlogon_pipe)) {
+ /* Ok, it must be dead. Drop timeout to 0.5 sec. */
+ if (conn->cli) {
+ cli_set_timeout(conn->cli, 500);
+ }
+ }
conn->netlogon_pipe = NULL;
}
static BOOL connection_ok(struct winbindd_domain *domain)
{
if (domain->conn.cli == NULL) {
- DEBUG(8, ("Connection to %s for domain %s has NULL "
+ DEBUG(8, ("connection_ok: Connection to %s for domain %s has NULL "
"cli!\n", domain->dcname, domain->name));
return False;
}
if (!domain->conn.cli->initialised) {
- DEBUG(3, ("Connection to %s for domain %s was never "
+ DEBUG(3, ("connection_ok: Connection to %s for domain %s was never "
"initialised!\n", domain->dcname, domain->name));
return False;
}
if (domain->conn.cli->fd == -1) {
- DEBUG(3, ("Connection to %s for domain %s has died or was "
+ DEBUG(3, ("connection_ok: Connection to %s for domain %s has died or was "
"never started (fd == -1)\n",
domain->dcname, domain->name));
return False;
}
+ if (domain->online == False) {
+ DEBUG(3, ("connection_ok: Domain %s is offline\n", domain->name));
+ return False;
+ }
+
return True;
}
-
-/* Initialize a new connection up to the RPC BIND. */
-static NTSTATUS init_dc_connection(struct winbindd_domain *domain)
+/* Initialize a new connection up to the RPC BIND.
+ Bypass online status check so always does network calls. */
+
+static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
{
- if (connection_ok(domain))
+ NTSTATUS result;
+
+ /* Internal connections never use the network. */
+ if (domain->internal) {
+ domain->initialized = True;
return NT_STATUS_OK;
+ }
+
+ if (connection_ok(domain)) {
+ if (!domain->initialized) {
+ set_dc_type_and_flags(domain);
+ }
+ return NT_STATUS_OK;
+ }
invalidate_cm_connection(&domain->conn);
- return cm_open_connection(domain, &domain->conn);
+ result = cm_open_connection(domain, &domain->conn);
+
+ if (NT_STATUS_IS_OK(result) && !domain->initialized) {
+ set_dc_type_and_flags(domain);
+ }
+
+ return result;
+}
+
+NTSTATUS init_dc_connection(struct winbindd_domain *domain)
+{
+ if (domain->initialized && !domain->online) {
+ /* We check for online status elsewhere. */
+ return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ }
+
+ 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;
}
/******************************************************************************
is native mode.
******************************************************************************/
-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;
TALLOC_CTX *mem_ctx = NULL;
struct rpc_pipe_client *cli;
POLICY_HND pol;
-
+
char *domain_name = NULL;
char *dns_name = NULL;
- DOM_SID *dom_sid = NULL;
+ char *forest_name = NULL;
+ DOM_SID *dom_sid = NULL;
ZERO_STRUCT( ctr );
- domain->native_mode = False;
- domain->active_directory = False;
-
- if (domain->internal) {
- domain->initialized = True;
+ if (!connection_ok(domain)) {
return;
}
- result = init_dc_connection(domain);
- if (!NT_STATUS_IS_OK(result)) {
- DEBUG(5, ("set_dc_type_and_flags: Could not open a connection "
- "to %s: (%s)\n", domain->name, nt_errstr(result)));
- domain->initialized = True;
- return;
- }
+ 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)));
- domain->initialized = True;
- 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)) {
- domain->initialized = True;
+ DEBUG(5, ("set_dc_type_and_flags_connect: rpccli_ds_getprimarydominfo "
+ "on domain %s failed: (%s)\n",
+ domain->name, nt_errstr(result)));
+
+ /* older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for
+ * every opcode on the LSARPC_DS pipe, continue with
+ * no_lsarpc_ds mode here as well to get domain->initialized
+ * set - gd */
+
+ if (NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR) {
+ goto no_lsarpc_ds;
+ }
+
return;
}
if ((ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) &&
- !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
+ !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE)) {
domain->native_mode = True;
+ } else {
+ domain->native_mode = False;
+ }
+no_lsarpc_ds:
cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC, &result);
if (cli == NULL) {
- domain->initialized = True;
+ 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);
return;
}
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;
}
to determine that the DC is active directory */
result = rpccli_lsa_query_info_policy2(cli, mem_ctx, &pol,
12, &domain_name,
- &dns_name, NULL,
+ &dns_name, &forest_name,
NULL, &dom_sid);
}
if (NT_STATUS_IS_OK(result)) {
+ domain->active_directory = True;
+
if (domain_name)
fstrcpy(domain->name, domain_name);
if (dns_name)
fstrcpy(domain->alt_name, dns_name);
+ if ( forest_name )
+ fstrcpy(domain->forest_name, forest_name);
+
if (dom_sid)
sid_copy(&domain->sid, dom_sid);
-
- domain->active_directory = True;
} else {
-
+ domain->active_directory = False;
+
result = rpccli_lsa_open_policy(cli, mem_ctx, True,
SEC_RIGHTS_MAXIMUM_ALLOWED,
&pol);
}
done:
+ 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_connect: domain %s is %srunning active directory.\n",
+ domain->name, domain->active_directory ? "" : "NOT "));
+
cli_rpc_pipe_close(cli);
talloc_destroy(mem_ctx);
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)
{
struct rpc_pipe_client **cli, POLICY_HND *sam_handle)
{
struct winbindd_cm_conn *conn;
- NTSTATUS result;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
fstring conn_pwd;
struct dcinfo *p_dcinfo;
/* Fall back to schannel if it's a W2K pre-SP1 box. */
if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
+ /* If this call fails - conn->cli can now be NULL ! */
DEBUG(10, ("cm_connect_sam: Could not get schannel auth info "
- "for domain %s, trying anon\n", conn->cli->domain));
+ "for domain %s, trying anon\n", domain->name));
goto anonymous;
}
conn->samr_pipe = cli_rpc_pipe_open_schannel_with_key
struct rpc_pipe_client **cli, POLICY_HND *lsa_policy)
{
struct winbindd_cm_conn *conn;
- NTSTATUS result;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
fstring conn_pwd;
struct dcinfo *p_dcinfo;
/* Fall back to schannel if it's a W2K pre-SP1 box. */
if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
- DEBUG(10, ("cm_connect_sam: Could not get schannel auth info "
- "for domain %s, trying anon\n", conn->cli->domain));
+ /* If this call fails - conn->cli can now be NULL ! */
+ DEBUG(10, ("cm_connect_lsa: Could not get schannel auth info "
+ "for domain %s, trying anon\n", domain->name));
goto anonymous;
}
conn->lsa_pipe = cli_rpc_pipe_open_schannel_with_key
done:
if (!NT_STATUS_IS_OK(result)) {
invalidate_cm_connection(conn);
- return NT_STATUS_UNSUCCESSFUL;
+ return result;
}
*cli = conn->lsa_pipe;
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;
if (conn->netlogon_pipe == NULL) {
DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
"was %s\n", nt_errstr(result)));
- return result;
+
+ /* make sure we return something besides OK */
+ 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;
}