#include "rpc_client/cli_lsarpc.h"
#include "../librpc/gen_ndr/ndr_dssetup_c.h"
#include "libads/sitename_cache.h"
+#include "libsmb/libsmb.h"
#include "libsmb/clidgram.h"
#include "ads.h"
#include "secrets.h"
#include "../libcli/security/security.h"
#include "passdb.h"
#include "messages.h"
-#include "ntdomain.h"
+#include "auth/gensec/gensec.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "lib/param/loadparm.h"
+#include "libcli/auth/netlogon_creds_cli.h"
+#include "auth.h"
+#include "rpc_server/rpc_ncacn_np.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
extern struct winbindd_methods reconnect_methods;
extern bool override_logfile;
-static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain);
+static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain, bool need_rw_dc);
static void set_dc_type_and_flags( struct winbindd_domain *domain );
static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
struct dc_name_ip **dcs, int *num_dcs);
the offline handler if false. Bypasses online
check so always does network calls. */
- init_dc_connection_network(domain);
+ init_dc_connection_network(domain, true);
break;
}
}
struct dc_name_ip *dcs = NULL;
int num_dcs = 0;
TALLOC_CTX *mem_ctx = NULL;
- pid_t parent_pid = sys_getpid();
+ pid_t parent_pid = getpid();
char *lfile = NULL;
+ NTSTATUS status;
if (domain->dc_probe_pid != (pid_t)-1) {
/*
domain->dc_probe_pid = (pid_t)-1;
}
- domain->dc_probe_pid = sys_fork();
+ domain->dc_probe_pid = fork();
if (domain->dc_probe_pid == (pid_t)-1) {
DEBUG(0, ("fork_child_dc_connect: Could not fork: %s\n", strerror(errno)));
}
}
- if (!winbindd_reinit_after_fork(lfile)) {
+ status = winbindd_reinit_after_fork(NULL, lfile);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("winbindd_reinit_after_fork failed: %s\n",
+ nt_errstr(status)));
messaging_send_buf(winbind_messaging_context(),
pid_to_procid(parent_pid),
MSG_WINBIND_FAILED_TO_GO_ONLINE,
- (uint8 *)domain->name,
+ (const uint8_t *)domain->name,
strlen(domain->name)+1);
_exit(1);
}
messaging_send_buf(winbind_messaging_context(),
pid_to_procid(parent_pid),
MSG_WINBIND_FAILED_TO_GO_ONLINE,
- (uint8 *)domain->name,
+ (const uint8_t *)domain->name,
strlen(domain->name)+1);
_exit(1);
}
messaging_send_buf(winbind_messaging_context(),
pid_to_procid(parent_pid),
MSG_WINBIND_FAILED_TO_GO_ONLINE,
- (uint8 *)domain->name,
+ (const uint8_t *)domain->name,
strlen(domain->name)+1);
_exit(0);
}
messaging_send_buf(winbind_messaging_context(),
pid_to_procid(parent_pid),
MSG_WINBIND_TRY_TO_GO_ONLINE,
- (uint8 *)domain->name,
+ (const uint8_t *)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,
+static void check_domain_online_handler(struct tevent_context *ctx,
+ struct tevent_timer *te,
struct timeval now,
void *private_data)
{
}
}
+void winbind_msg_domain_offline(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ const char *domain_name = (const char *)data->data;
+ struct winbindd_domain *domain;
+
+ domain = find_domain_from_name_noinit(domain_name);
+ if (domain == NULL) {
+ return;
+ }
+
+ domain->online = false;
+
+ DEBUG(10, ("Domain %s is marked as offline now.\n",
+ domain_name));
+}
+
+void winbind_msg_domain_online(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ const char *domain_name = (const char *)data->data;
+ struct winbindd_domain *domain;
+
+ domain = find_domain_from_name_noinit(domain_name);
+ if (domain == NULL) {
+ return;
+ }
+
+ domain->online = true;
+
+ DEBUG(10, ("Domain %s is marked as online now.\n",
+ domain_name));
+}
+
/****************************************************************
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)
{
+ pid_t parent_pid = getppid();
+
DEBUG(10,("set_domain_offline: called for domain %s\n",
domain->name ));
calc_new_online_timeout_check(domain);
- domain->check_online_event = event_add_timed(winbind_event_context(),
+ domain->check_online_event = tevent_add_timer(winbind_event_context(),
NULL,
timeval_current_ofs(domain->check_online_timeout,0),
check_domain_online_handler,
DEBUG(10,("set_domain_offline: added event handler for domain %s\n",
domain->name ));
+ /* Send a message to the parent that the domain is offline. */
+ if (parent_pid > 1 && !domain->internal) {
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(parent_pid),
+ MSG_WINBIND_DOMAIN_OFFLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name) + 1);
+ }
+
/* Send an offline message to the idmap child when our
primary domain goes offline */
messaging_send_buf(winbind_messaging_context(),
pid_to_procid(idmap->pid),
MSG_WINBIND_OFFLINE,
- (uint8 *)domain->name,
+ (const uint8_t *)domain->name,
strlen(domain->name)+1);
}
}
static void set_domain_online(struct winbindd_domain *domain)
{
+ pid_t parent_pid = getppid();
+
DEBUG(10,("set_domain_online: called for domain %s\n",
domain->name ));
domain->online = True;
+ /* Send a message to the parent that the domain is online. */
+ if (parent_pid > 1 && !domain->internal) {
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(parent_pid),
+ MSG_WINBIND_DOMAIN_ONLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name) + 1);
+ }
+
/* Send an online message to the idmap child when our
primary domain comes online */
messaging_send_buf(winbind_messaging_context(),
pid_to_procid(idmap->pid),
MSG_WINBIND_ONLINE,
- (uint8 *)domain->name,
+ (const uint8_t *)domain->name,
strlen(domain->name)+1);
}
}
TALLOC_FREE(domain->check_online_event);
- domain->check_online_event = event_add_timed(winbind_event_context(),
+ domain->check_online_event = tevent_add_timer(winbind_event_context(),
NULL,
tev,
check_domain_online_handler,
/* If this was the saf name for the last thing we talked to,
remove it. */
saf_delete(domain->name);
- if (*domain->alt_name) {
+ if (domain->alt_name != NULL) {
add_failed_connection_entry(domain->alt_name, server, result);
saf_delete(domain->alt_name);
}
talloc_destroy(mem_ctx);
return false;
}
- if (strlen(domain->alt_name) == 0) {
- fstrcpy(domain->alt_name,
- domain_info->domain_name);
+ if (domain->alt_name == NULL) {
+ domain->alt_name = talloc_strdup(domain,
+ domain_info->domain_name);
+ if (domain->alt_name == NULL) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ talloc_destroy(mem_ctx);
+ return false;
+ }
}
- if (strlen(domain->forest_name) == 0) {
- fstrcpy(domain->forest_name,
- domain_info->forest_name);
+ if (domain->forest_name == NULL) {
+ domain->forest_name = talloc_strdup(domain,
+ domain_info->forest_name);
+ if (domain->forest_name == NULL) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ talloc_destroy(mem_ctx);
+ return false;
+ }
}
}
} else {
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
+ if (our_domain->alt_name == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
if (asprintf(machine_krb5_principal, "%s$@%s",
account_name, our_domain->alt_name) == -1)
{
return NT_STATUS_NO_MEMORY;
}
- strupper_m(*machine_krb5_principal);
+ if (!strupper_m(*machine_krb5_principal)) {
+ SAFE_FREE(*machine_krb5_principal);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
}
return NT_STATUS_OK;
struct cli_state **cli,
bool *retry)
{
+ bool try_spnego = false;
+ bool try_ipc_auth = false;
char *machine_password = NULL;
char *machine_krb5_principal = NULL;
char *machine_account = NULL;
char *ipc_username = NULL;
char *ipc_domain = NULL;
char *ipc_password = NULL;
+ int flags = 0;
+ uint16_t sec_mode = 0;
struct named_mutex *mutex;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
- struct sockaddr peeraddr;
- socklen_t peeraddr_len;
-
- struct sockaddr_in *peeraddr_in =
- (struct sockaddr_in *)(void *)&peeraddr;
-
DEBUG(10,("cm_prepare_connection: connecting to DC %s for domain %s\n",
controller, domain->name ));
mutex = grab_named_mutex(talloc_tos(), controller,
WINBIND_SERVER_MUTEX_WAIT_TIME);
if (mutex == NULL) {
+ close(sockfd);
DEBUG(0,("cm_prepare_connection: mutex grab failed for %s\n",
controller));
result = NT_STATUS_POSSIBLE_DEADLOCK;
goto done;
}
- if ((*cli = cli_initialise()) == NULL) {
+ flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+
+ *cli = cli_state_create(NULL, sockfd,
+ controller, domain->alt_name,
+ SMB_SIGNING_DEFAULT, flags);
+ if (*cli == NULL) {
+ close(sockfd);
DEBUG(1, ("Could not cli_initialize\n"));
result = NT_STATUS_NO_MEMORY;
goto done;
}
- (*cli)->timeout = 10000; /* 10 seconds */
- (*cli)->fd = sockfd;
- fstrcpy((*cli)->desthost, controller);
- (*cli)->use_kerberos = True;
+ cli_set_timeout(*cli, 10000); /* 10 seconds */
- peeraddr_len = sizeof(peeraddr);
-
- if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0)) {
- DEBUG(0,("cm_prepare_connection: getpeername failed with: %s\n",
- strerror(errno)));
- result = NT_STATUS_UNSUCCESSFUL;
- goto done;
- }
-
- if ((peeraddr_len != sizeof(struct sockaddr_in))
-#ifdef HAVE_IPV6
- && (peeraddr_len != sizeof(struct sockaddr_in6))
-#endif
- ) {
- DEBUG(0,("cm_prepare_connection: got unexpected peeraddr len %d\n",
- peeraddr_len));
- result = NT_STATUS_UNSUCCESSFUL;
- goto done;
- }
-
- if ((peeraddr_in->sin_family != PF_INET)
-#ifdef HAVE_IPV6
- && (peeraddr_in->sin_family != PF_INET6)
-#endif
- ) {
- DEBUG(0,("cm_prepare_connection: got unexpected family %d\n",
- peeraddr_in->sin_family));
- result = NT_STATUS_UNSUCCESSFUL;
- goto done;
- }
-
- result = cli_negprot(*cli);
+ result = smbXcli_negprot((*cli)->conn, (*cli)->timeout,
+ lp_client_min_protocol(),
+ lp_client_max_protocol());
if (!NT_STATUS_IS_OK(result)) {
DEBUG(1, ("cli_negprot failed: %s\n", nt_errstr(result)));
goto done;
}
- if (!is_dc_trusted_domain_situation(domain->name) &&
- (*cli)->protocol >= PROTOCOL_NT1 &&
- (*cli)->capabilities & CAP_EXTENDED_SECURITY)
- {
- ADS_STATUS ads_status;
+ if (smbXcli_conn_protocol((*cli)->conn) >= PROTOCOL_NT1 &&
+ smb1cli_conn_capabilities((*cli)->conn) & CAP_EXTENDED_SECURITY) {
+ try_spnego = true;
+ } else if (smbXcli_conn_protocol((*cli)->conn) >= PROTOCOL_SMB2_02) {
+ try_spnego = true;
+ }
+ if (!is_dc_trusted_domain_situation(domain->name) && try_spnego) {
result = get_trust_creds(domain, &machine_password,
&machine_account,
&machine_krb5_principal);
(*cli)->use_kerberos = True;
DEBUG(5, ("connecting to %s from %s with kerberos principal "
- "[%s] and realm [%s]\n", controller, global_myname(),
+ "[%s] and realm [%s]\n", controller, lp_netbios_name(),
machine_krb5_principal, domain->alt_name));
winbindd_set_locator_kdc_envs(domain);
- ads_status = cli_session_setup_spnego(*cli,
- machine_krb5_principal,
- machine_password,
- lp_workgroup(),
- domain->alt_name);
+ result = cli_session_setup(*cli,
+ machine_krb5_principal,
+ machine_password,
+ strlen(machine_password)+1,
+ machine_password,
+ strlen(machine_password)+1,
+ lp_workgroup());
- if (!ADS_ERR_OK(ads_status)) {
+ if (!NT_STATUS_IS_OK(result)) {
DEBUG(4,("failed kerberos session setup with %s\n",
- ads_errstr(ads_status)));
+ nt_errstr(result)));
}
- result = ads_ntstatus(ads_status);
if (NT_STATUS_IS_OK(result)) {
/* Ensure creds are stored for NTLMSSP authenticated pipe access. */
result = cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
(*cli)->use_kerberos = False;
DEBUG(5, ("connecting to %s from %s with username "
- "[%s]\\[%s]\n", controller, global_myname(),
+ "[%s]\\[%s]\n", controller, lp_netbios_name(),
lp_workgroup(), machine_account));
- ads_status = cli_session_setup_spnego(*cli,
- machine_account,
- machine_password,
- lp_workgroup(),
- NULL);
- if (!ADS_ERR_OK(ads_status)) {
+ result = cli_session_setup(*cli,
+ machine_account,
+ machine_password,
+ strlen(machine_password)+1,
+ machine_password,
+ strlen(machine_password)+1,
+ lp_workgroup());
+ if (!NT_STATUS_IS_OK(result)) {
DEBUG(4, ("authenticated session setup failed with %s\n",
- ads_errstr(ads_status)));
+ nt_errstr(result)));
}
- result = ads_ntstatus(ads_status);
if (NT_STATUS_IS_OK(result)) {
/* Ensure creds are stored for NTLMSSP authenticated pipe access. */
result = cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
- if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
- (strlen(ipc_username) > 0)) {
+ sec_mode = smb1cli_conn_server_security_mode((*cli)->conn);
+
+ try_ipc_auth = false;
+ if (try_spnego) {
+ try_ipc_auth = true;
+ } else if (sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
+ try_ipc_auth = true;
+ }
+
+ if (try_ipc_auth && (strlen(ipc_username) > 0)) {
/* Only try authenticated if we have a username */
DEBUG(5, ("connecting to %s from %s with username "
- "[%s]\\[%s]\n", controller, global_myname(),
+ "[%s]\\[%s]\n", controller, lp_netbios_name(),
ipc_domain, ipc_username));
if (NT_STATUS_IS_OK(cli_session_setup(
"connection for DC %s\n",
controller ));
- if (NT_STATUS_IS_OK(cli_session_setup(*cli, "", NULL, 0,
- NULL, 0, ""))) {
+ result = cli_session_setup(*cli, "", NULL, 0, NULL, 0, "");
+ if (NT_STATUS_IS_OK(result)) {
DEBUG(5, ("Connected anonymously\n"));
result = cli_init_creds(*cli, "", "", "");
if (!NT_STATUS_IS_OK(result)) {
goto session_setup_done;
}
- result = cli_nt_error(*cli);
-
- if (NT_STATUS_IS_OK(result))
- result = NT_STATUS_UNSUCCESSFUL;
-
/* We can't session setup */
-
goto done;
session_setup_done:
+ /*
+ * This should be a short term hack until
+ * dynamic re-authentication is implemented.
+ *
+ * See Bug 9175 - winbindd doesn't recover from
+ * NT_STATUS_NETWORK_SESSION_EXPIRED
+ */
+ if (smbXcli_conn_protocol((*cli)->conn) >= PROTOCOL_SMB2_02) {
+ smbXcli_session_set_disconnect_expired((*cli)->smb2.session);
+ }
+
/* cache the server name for later connections */
- saf_store( domain->name, (*cli)->desthost );
+ saf_store(domain->name, controller);
if (domain->alt_name && (*cli)->use_kerberos) {
- saf_store( domain->alt_name, (*cli)->desthost );
+ saf_store(domain->alt_name, controller);
}
winbindd_set_locator_kdc_envs(domain);
- result = cli_tcon_andx(*cli, "IPC$", "IPC", "", 0);
+ result = cli_tree_connect(*cli, "IPC$", "IPC", "", 0);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
if ( !(*cli)->domain[0] ) {
result = cli_set_domain((*cli), domain->name);
if (!NT_STATUS_IS_OK(result)) {
+ SAFE_FREE(ipc_username);
+ SAFE_FREE(ipc_domain);
+ SAFE_FREE(ipc_password);
return result;
}
}
(struct sockaddr *)(void *)pss))
return False;
- *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
+ *dcs = talloc_realloc(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
if (*dcs == NULL)
return False;
struct sockaddr_storage *pss, uint16 port,
struct sockaddr_storage **addrs, int *num)
{
- *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_storage, (*num)+1);
+ *addrs = talloc_realloc(mem_ctx, *addrs, struct sockaddr_storage, (*num)+1);
if (*addrs == NULL) {
*num = 0;
static bool dcip_to_name(TALLOC_CTX *mem_ctx,
const struct winbindd_domain *domain,
struct sockaddr_storage *pss,
- fstring name )
+ char **name)
{
struct ip_service ip_list;
uint32_t nt_version = NETLOGON_NT_VERSION_1;
NTSTATUS status;
const char *dc_name;
+ fstring nbtname;
ip_list.ss = *pss;
ip_list.port = 0;
/* 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) && (domain->alt_name != NULL)) {
ADS_STRUCT *ads;
ADS_STATUS ads_status;
char addr[INET6_ADDRSTRLEN];
ads_status = ads_connect(ads);
if (ADS_ERR_OK(ads_status)) {
/* We got a cldap packet. */
- fstrcpy(name, ads->config.ldap_server_name);
- namecache_store(name, 0x20, 1, &ip_list);
+ *name = talloc_strdup(mem_ctx,
+ ads->config.ldap_server_name);
+ if (*name == NULL) {
+ return false;
+ }
+ 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 & NBT_SERVER_KDC)) {
if (ads_closest_dc(ads)) {
- char *sitename = sitename_fetch(ads->config.realm);
+ char *sitename = sitename_fetch(mem_ctx, ads->config.realm);
/* We're going to use this KDC for this realm/domain.
If we are using sites, then force the krb5 libs
create_local_private_krb5_conf_for_domain(domain->alt_name,
domain->name,
sitename,
- pss,
- name);
+ pss);
- SAFE_FREE(sitename);
+ TALLOC_FREE(sitename);
} else {
/* use an off site KDC */
create_local_private_krb5_conf_for_domain(domain->alt_name,
domain->name,
NULL,
- pss,
- name);
+ pss);
}
winbindd_set_locator_kdc_envs(domain);
/* Ensure we contact this DC also. */
- saf_store( domain->name, name);
- saf_store( domain->alt_name, name);
+ saf_store(domain->name, *name);
+ saf_store(domain->alt_name, *name);
}
ads_destroy( &ads );
}
ads_destroy( &ads );
+ return false;
}
#endif
- status = nbt_getdc(winbind_messaging_context(), pss, domain->name,
+ status = nbt_getdc(winbind_messaging_context(), 10, pss, domain->name,
&domain->sid, nt_version, mem_ctx, &nt_version,
&dc_name, NULL);
if (NT_STATUS_IS_OK(status)) {
- fstrcpy(name, dc_name);
- namecache_store(name, 0x20, 1, &ip_list);
+ *name = talloc_strdup(mem_ctx, dc_name);
+ if (*name == NULL) {
+ return false;
+ }
+ namecache_store(*name, 0x20, 1, &ip_list);
return True;
}
/* try node status request */
- if ( name_status_find(domain->name, 0x1c, 0x20, pss, name) ) {
- namecache_store(name, 0x20, 1, &ip_list);
- return True;
+ if (name_status_find(domain->name, 0x1c, 0x20, pss, nbtname) ) {
+ namecache_store(nbtname, 0x20, 1, &ip_list);
+
+ if (name != NULL) {
+ *name = talloc_strdup(mem_ctx, nbtname);
+ if (*name == NULL) {
+ return false;
+ }
+ }
+
+ return true;
}
return False;
}
return True;
}
- if (sec == SEC_ADS) {
+ if ((sec == SEC_ADS) && (domain->alt_name != NULL)) {
char *sitename = NULL;
/* We need to make sure we know the local site before
get_dc_name(domain->name, domain->alt_name, dcname, &ss);
- sitename = sitename_fetch(domain->alt_name);
+ sitename = sitename_fetch(mem_ctx, domain->alt_name);
if (sitename) {
/* Do the site-specific AD dns lookup first. */
}
SAFE_FREE(ip_list);
- SAFE_FREE(sitename);
+ TALLOC_FREE(sitename);
iplist_size = 0;
}
iplist_size = 0;
}
- /* Try standard netbios queries if no ADS */
+ /* Try standard netbios queries if no ADS and fall back to DNS queries
+ * if alt_name is available */
if (*num_dcs == 0) {
get_sorted_dc_list(domain->name, NULL, &ip_list, &iplist_size,
- False);
+ false);
+ if (iplist_size == 0) {
+ if (domain->alt_name != NULL) {
+ get_sorted_dc_list(domain->alt_name, NULL, &ip_list,
+ &iplist_size, true);
+ }
+ }
for ( i=0; i<iplist_size; i++ ) {
char addr[INET6_ADDRSTRLEN];
static bool find_new_dc(TALLOC_CTX *mem_ctx,
struct winbindd_domain *domain,
- fstring dcname, struct sockaddr_storage *pss, int *fd)
+ char **dcname, struct sockaddr_storage *pss, int *fd)
{
struct dc_name_ip *dcs = NULL;
int num_dcs = 0;
&dcnames, &num_dcnames)) {
return False;
}
- if (!add_sockaddr_to_array(mem_ctx, &dcs[i].ss, 445,
+ if (!add_sockaddr_to_array(mem_ctx, &dcs[i].ss, TCP_SMB_PORT,
&addrs, &num_addrs)) {
return False;
}
return False;
status = smbsock_any_connect(addrs, dcnames, NULL, NULL, NULL,
- num_addrs, 0, fd, &fd_index, NULL);
+ num_addrs, 0, 10, fd, &fd_index, NULL);
if (!NT_STATUS_IS_OK(status)) {
for (i=0; i<num_dcs; i++) {
char ab[INET6_ADDRSTRLEN];
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;
+ *dcname = talloc_strdup(mem_ctx, dcnames[fd_index]);
+ if (*dcname == NULL) {
+ return false;
+ }
+ return true;
}
/* Try to figure out the name */
char *key = NULL;
char *value = NULL;
- if (cli == NULL) {
- return;
- }
- if (cli->fd == -1) {
+ if (!cli_state_is_connected(cli)) {
return;
}
- get_peer_addr(cli->fd, addr, sizeof(addr));
+
+ print_sockaddr(addr, sizeof(addr),
+ smbXcli_conn_remote_sockaddr(cli->conn));
key = current_dc_key(talloc_tos(), domain_name);
if (key == NULL) {
const char *domain_name,
char **p_dc_name, char **p_dc_ip)
{
- char *key, *value, *p;
+ char *key, *p;
+ char *value = NULL;
bool ret = false;
char *dc_name = NULL;
char *dc_ip = NULL;
if (key == NULL) {
goto done;
}
- if (!gencache_get(key, &value, NULL)) {
+ if (!gencache_get(key, mem_ctx, &value, NULL)) {
goto done;
}
p = strchr(value, ' ');
TALLOC_FREE(dc_name);
TALLOC_FREE(dc_ip);
TALLOC_FREE(key);
+ TALLOC_FREE(value);
return ret;
}
+NTSTATUS wb_open_internal_pipe(TALLOC_CTX *mem_ctx,
+ const struct ndr_interface_table *table,
+ struct rpc_pipe_client **ret_pipe)
+{
+ struct rpc_pipe_client *cli = NULL;
+ const struct auth_session_info *session_info;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+
+ session_info = get_session_info_system();
+ SMB_ASSERT(session_info != NULL);
+
+ /* create a connection to the specified pipe */
+ if (lp_parm_bool(-1, "winbindd", "use external pipes", false)) {
+ status = rpc_pipe_open_interface(mem_ctx,
+ table,
+ session_info,
+ NULL,
+ winbind_messaging_context(),
+ &cli);
+ } else {
+ status = rpc_pipe_open_internal(mem_ctx,
+ &table->syntax_id,
+ session_info,
+ NULL,
+ winbind_messaging_context(),
+ &cli);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("open_internal_pipe: Could not connect to %s pipe: %s\n",
+ table->name, nt_errstr(status)));
+ return status;
+ }
+
+ if (ret_pipe) {
+ *ret_pipe = cli;
+ }
+
+ return NT_STATUS_OK;
+}
+
static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
struct winbindd_cm_conn *new_conn)
{
TALLOC_CTX *mem_ctx;
NTSTATUS result;
- char *saf_servername = saf_fetch( domain->name );
+ char *saf_servername;
int retries;
if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
- SAFE_FREE(saf_servername);
set_domain_offline(domain);
return NT_STATUS_NO_MEMORY;
}
+ saf_servername = saf_fetch(mem_ctx, domain->name );
+
/* we have to check the server affinity cache here since
later we select a DC based on response time and not preference */
/* convert an ip address to a name */
if (is_ipaddress( saf_servername ) ) {
- fstring saf_name;
+ char *dcname = NULL;
struct sockaddr_storage ss;
if (!interpret_string_addr(&ss, saf_servername,
AI_NUMERICHOST)) {
+ TALLOC_FREE(mem_ctx);
return NT_STATUS_UNSUCCESSFUL;
}
- if (dcip_to_name(mem_ctx, domain, &ss, saf_name )) {
- fstrcpy( domain->dcname, saf_name );
+ if (dcip_to_name(mem_ctx, domain, &ss, &dcname)) {
+ domain->dcname = talloc_strdup(domain,
+ dcname);
+ if (domain->dcname == NULL) {
+ TALLOC_FREE(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
} else {
winbind_add_failed_connection_entry(
domain, saf_servername,
NT_STATUS_UNSUCCESSFUL);
}
} else {
- fstrcpy( domain->dcname, saf_servername );
+ domain->dcname = talloc_strdup(domain, saf_servername);
+ if (domain->dcname == NULL) {
+ TALLOC_FREE(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
}
-
- SAFE_FREE( saf_servername );
}
for (retries = 0; retries < 3; retries++) {
int fd = -1;
bool retry = False;
+ char *dcname = NULL;
result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
DEBUG(10,("cm_open_connection: dcname is '%s' for domain %s\n",
- domain->dcname, domain->name ));
+ domain->dcname ? domain->dcname : "", domain->name ));
- if (*domain->dcname
+ if (domain->dcname != NULL
&& NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
&& (resolve_name(domain->dcname, &domain->dcaddr, 0x20, true)))
{
status = smbsock_connect(&domain->dcaddr, 0,
NULL, -1, NULL, -1,
- &fd, NULL);
+ &fd, NULL, 10);
if (!NT_STATUS_IS_OK(status)) {
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, &dcname, &domain->dcaddr, &fd))
{
/* This is the one place where we will
set the global winbindd offline state
set_global_winbindd_state_offline();
break;
}
+ if (dcname != NULL) {
+ talloc_free(domain->dcname);
+
+ domain->dcname = talloc_move(domain, &dcname);
+ if (domain->dcname == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ break;
+ }
+ }
new_conn->cli = NULL;
result = cm_prepare_connection(domain, fd, domain->dcname,
&new_conn->cli, &retry);
+ if (!NT_STATUS_IS_OK(result)) {
+ /* Don't leak the smb connection socket */
+ close(fd);
+ }
if (!retry)
break;
}
if (NT_STATUS_IS_OK(result)) {
+ bool seal_pipes = true;
winbindd_set_locator_kdc_envs(domain);
*/
store_current_dc_in_gencache(domain->name, domain->dcname,
new_conn->cli);
+
+ seal_pipes = lp_winbind_sealed_pipes();
+ seal_pipes = lp_parm_bool(-1, "winbind sealed pipes",
+ domain->name,
+ seal_pipes);
+
+ if (seal_pipes) {
+ new_conn->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+ } else {
+ new_conn->auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+ }
} else {
/* Ensure we setup the retry handler. */
set_domain_offline(domain);
}
}
+ conn->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+ conn->netlogon_force_reauth = false;
+ conn->netlogon_flags = 0;
+ TALLOC_FREE(conn->netlogon_creds);
+
if (conn->cli) {
cli_shutdown(conn->cli);
}
void close_conns_after_fork(void)
{
struct winbindd_domain *domain;
+ struct winbindd_cli_state *cli_state;
for (domain = domain_list(); domain; domain = domain->next) {
- struct cli_state *cli = domain->conn.cli;
-
/*
* first close the low level SMB TCP connection
* so that we don't generate any SMBclose
* requests in invalidate_cm_connection()
*/
- if (cli && cli->fd != -1) {
- close(domain->conn.cli->fd);
- domain->conn.cli->fd = -1;
+ if (cli_state_is_connected(domain->conn.cli)) {
+ smbXcli_conn_disconnect(domain->conn.cli->conn, NT_STATUS_OK);
}
invalidate_cm_connection(&domain->conn);
}
+
+ for (cli_state = winbindd_client_list();
+ cli_state != NULL;
+ cli_state = cli_state->next) {
+ if (cli_state->sock >= 0) {
+ close(cli_state->sock);
+ cli_state->sock = -1;
+ }
+ }
}
static bool connection_ok(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)
+static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain, bool need_rw_dc)
{
NTSTATUS result;
-
- /* Internal connections never use the network. */
- if (domain->internal) {
- domain->initialized = True;
- return NT_STATUS_OK;
+ bool skip_connection = domain->internal;
+ if (need_rw_dc && domain->rodc) {
+ skip_connection = false;
}
- if (!winbindd_can_contact_domain(domain)) {
- invalidate_cm_connection(&domain->conn);
- domain->initialized = True;
- return NT_STATUS_OK;
+ /* Internal connections never use the network. */
+ if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
- if (connection_ok(domain)) {
+ /* Still ask the internal LSA and SAMR server about the local domain */
+ if (skip_connection || connection_ok(domain)) {
if (!domain->initialized) {
set_dc_type_and_flags(domain);
}
return result;
}
-NTSTATUS init_dc_connection(struct winbindd_domain *domain)
+NTSTATUS init_dc_connection(struct winbindd_domain *domain, bool need_rw_dc)
{
- if (domain->internal) {
+ if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
}
- return init_dc_connection_network(domain);
+ return init_dc_connection_network(domain, need_rw_dc);
}
-static NTSTATUS init_dc_connection_rpc(struct winbindd_domain *domain)
+static NTSTATUS init_dc_connection_rpc(struct winbindd_domain *domain, bool need_rw_dc)
{
NTSTATUS status;
- status = init_dc_connection(domain);
+ status = init_dc_connection(domain, need_rw_dc);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return False;
}
+ mem_ctx = talloc_stackframe();
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;
+ if (our_domain->internal) {
+ result = init_dc_connection(our_domain, false);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3,("set_dc_type_and_flags_trustinfo: "
+ "Not able to make a connection to our domain: %s\n",
+ nt_errstr(result)));
+ TALLOC_FREE(mem_ctx);
+ return false;
+ }
}
/* This won't work unless our domain is AD */
-
if ( !our_domain->active_directory ) {
+ TALLOC_FREE(mem_ctx);
return False;
}
- /* Use DsEnumerateDomainTrusts to get us the trust direction
- and type */
-
- result = cm_connect_netlogon(our_domain, &cli);
+ if (our_domain->internal) {
+ result = wb_open_internal_pipe(mem_ctx, &ndr_table_netlogon, &cli);
+ } else if (!connection_ok(our_domain)) {
+ DEBUG(3,("set_dc_type_and_flags_trustinfo: "
+ "No connection to our domain!\n"));
+ TALLOC_FREE(mem_ctx);
+ return False;
+ } else {
+ 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)));
+ TALLOC_FREE(mem_ctx);
return False;
}
-
b = cli->binding_handle;
- 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;
- }
-
+ /* Use DsEnumerateDomainTrusts to get us the trust direction and type. */
result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
cli->desthost,
flags,
DEBUG(0,("set_dc_type_and_flags_trustinfo: "
"failed to query trusted domain list: %s\n",
nt_errstr(result)));
- talloc_destroy(mem_ctx);
+ TALLOC_FREE(mem_ctx);
return false;
}
if (!W_ERROR_IS_OK(werr)) {
DEBUG(0,("set_dc_type_and_flags_trustinfo: "
"failed to query trusted domain list: %s\n",
win_errstr(werr)));
- talloc_destroy(mem_ctx);
+ TALLOC_FREE(mem_ctx);
return false;
}
domain->domain_type = trusts.array[i].trust_type;
domain->domain_trust_attribs = trusts.array[i].trust_attributes;
- if ( domain->domain_type == NETR_TRUST_TYPE_UPLEVEL )
+ if ( domain->domain_type == LSA_TRUST_TYPE_UPLEVEL )
domain->active_directory = True;
/* This flag is only set if the domain is *our*
"running active directory.\n", domain->name,
domain->active_directory ? "" : "NOT "));
+ domain->can_do_ncacn_ip_tcp = domain->active_directory;
domain->initialized = True;
}
}
- talloc_destroy( mem_ctx );
+ TALLOC_FREE(mem_ctx);
return domain->initialized;
}
union dssetup_DsRoleInfo info;
union lsa_PolicyInformation *lsa_info = NULL;
- if (!connection_ok(domain)) {
+ if (!domain->internal && !connection_ok(domain)) {
return;
}
DEBUG(5, ("set_dc_type_and_flags_connect: domain %s\n", domain->name ));
- status = cli_rpc_pipe_open_noauth(domain->conn.cli,
- &ndr_table_dssetup.syntax_id,
- &cli);
+ if (domain->internal) {
+ status = wb_open_internal_pipe(mem_ctx,
+ &ndr_table_dssetup,
+ &cli);
+ } else {
+ status = cli_rpc_pipe_open_noauth(domain->conn.cli,
+ &ndr_table_dssetup,
+ &cli);
+ }
if (!NT_STATUS_IS_OK(status)) {
DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
}
no_dssetup:
- status = cli_rpc_pipe_open_noauth(domain->conn.cli,
- &ndr_table_lsarpc.syntax_id, &cli);
-
+ if (domain->internal) {
+ status = wb_open_internal_pipe(mem_ctx,
+ &ndr_table_lsarpc,
+ &cli);
+ } else {
+ status = cli_rpc_pipe_open_noauth(domain->conn.cli,
+ &ndr_table_lsarpc, &cli);
+ }
if (!NT_STATUS_IS_OK(status)) {
DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
"PI_LSARPC on domain %s: (%s)\n",
domain->active_directory = True;
if (lsa_info->dns.name.string) {
- fstrcpy(domain->name, lsa_info->dns.name.string);
+ talloc_free(domain->name);
+ domain->name = talloc_strdup(domain,
+ lsa_info->dns.name.string);
+ if (domain->name == NULL) {
+ goto done;
+ }
}
if (lsa_info->dns.dns_domain.string) {
- fstrcpy(domain->alt_name,
- lsa_info->dns.dns_domain.string);
+ talloc_free(domain->alt_name);
+ domain->alt_name =
+ talloc_strdup(domain,
+ lsa_info->dns.dns_domain.string);
+ if (domain->alt_name == NULL) {
+ goto done;
+ }
}
/* See if we can set some domain trust flags about
ourself */
if (lsa_info->dns.dns_forest.string) {
- fstrcpy(domain->forest_name,
- lsa_info->dns.dns_forest.string);
+ talloc_free(domain->forest_name);
+ domain->forest_name =
+ talloc_strdup(domain,
+ lsa_info->dns.dns_forest.string);
+ if (domain->forest_name == NULL) {
+ goto done;
+ }
if (strequal(domain->forest_name, domain->alt_name)) {
domain->domain_flags |= NETR_TRUST_FLAG_TREEROOT;
if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
if (lsa_info->account_domain.name.string) {
- fstrcpy(domain->name,
- lsa_info->account_domain.name.string);
+ talloc_free(domain->name);
+ domain->name =
+ talloc_strdup(domain,
+ lsa_info->account_domain.name.string);
}
if (lsa_info->account_domain.sid) {
domain->name, domain->active_directory ? "" : "NOT "));
domain->can_do_ncacn_ip_tcp = domain->active_directory;
- domain->can_do_validation6 = domain->active_directory;
TALLOC_FREE(cli);
{
/* we always have to contact our primary domain */
- if ( domain->primary ) {
+ if ( domain->primary || domain->internal) {
DEBUG(10,("set_dc_type_and_flags: setting up flags for "
- "primary domain\n"));
+ "primary or internal domain\n"));
set_dc_type_and_flags_connect( domain );
return;
}
***********************************************************************/
static NTSTATUS cm_get_schannel_creds(struct winbindd_domain *domain,
- struct netlogon_creds_CredentialState **ppdc)
+ struct netlogon_creds_cli_context **ppdc)
{
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
struct rpc_pipe_client *netlogon_pipe;
- if (lp_client_schannel() == False) {
- return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ *ppdc = NULL;
+
+ if ((!IS_DC) && (!domain->primary)) {
+ return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
+ }
+
+ if (domain->conn.netlogon_creds != NULL) {
+ if (!(domain->conn.netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
+ return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
+ }
+ *ppdc = domain->conn.netlogon_creds;
+ return NT_STATUS_OK;
}
result = cm_connect_netlogon(domain, &netlogon_pipe);
return result;
}
- /* Return a pointer to the struct netlogon_creds_CredentialState from the
- netlogon pipe. */
+ if (domain->conn.netlogon_creds == NULL) {
+ return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
+ }
- if (!domain->conn.netlogon_pipe->dc) {
- return NT_STATUS_INTERNAL_ERROR; /* This shouldn't happen. */
+ if (!(domain->conn.netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
+ return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
}
- *ppdc = domain->conn.netlogon_pipe->dc;
+ *ppdc = domain->conn.netlogon_creds;
return NT_STATUS_OK;
}
NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+ bool need_rw_dc,
struct rpc_pipe_client **cli, struct policy_handle *sam_handle)
{
struct winbindd_cm_conn *conn;
NTSTATUS status, result;
- struct netlogon_creds_CredentialState *p_creds;
+ struct netlogon_creds_cli_context *p_creds;
char *machine_password = NULL;
char *machine_account = NULL;
- char *domain_name = NULL;
+ const char *domain_name = NULL;
- if (sid_check_is_domain(&domain->sid)) {
- return open_internal_samr_conn(mem_ctx, domain, cli, sam_handle);
+ if (sid_check_is_our_sam(&domain->sid)) {
+ if (domain->rodc == false || need_rw_dc == false) {
+ return open_internal_samr_conn(mem_ctx, domain, cli, sam_handle);
+ }
}
- status = init_dc_connection_rpc(domain);
+ status = init_dc_connection_rpc(domain, need_rw_dc);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
/* We have an authenticated connection. Use a NTLMSSP SPNEGO
authenticated SAMR pipe with sign & seal. */
- status = cli_rpc_pipe_open_spnego_ntlmssp(conn->cli,
- &ndr_table_samr.syntax_id,
- NCACN_NP,
- DCERPC_AUTH_LEVEL_PRIVACY,
- domain_name,
- machine_account,
- machine_password,
- &conn->samr_pipe);
+ status = cli_rpc_pipe_open_spnego(conn->cli,
+ &ndr_table_samr,
+ NCACN_NP,
+ GENSEC_OID_NTLMSSP,
+ conn->auth_level,
+ smbXcli_conn_remote_name(conn->cli->conn),
+ domain_name,
+ machine_account,
+ machine_password,
+ &conn->samr_pipe);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10,("cm_connect_sam: failed to connect to SAMR "
goto anonymous;
}
status = cli_rpc_pipe_open_schannel_with_key
- (conn->cli, &ndr_table_samr.syntax_id, NCACN_NP,
- DCERPC_AUTH_LEVEL_PRIVACY,
- domain->name, &p_creds, &conn->samr_pipe);
+ (conn->cli, &ndr_table_samr, NCACN_NP,
+ domain->name, p_creds, &conn->samr_pipe);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for "
anonymous:
/* Finally fall back to anonymous. */
- status = cli_rpc_pipe_open_noauth(conn->cli, &ndr_table_samr.syntax_id,
+ status = cli_rpc_pipe_open_noauth(conn->cli, &ndr_table_samr,
&conn->samr_pipe);
if (!NT_STATUS_IS_OK(status)) {
struct rpc_pipe_client **cli)
{
struct winbindd_cm_conn *conn;
- struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_cli_context *creds;
NTSTATUS status;
DEBUG(10,("cm_connect_lsa_tcp\n"));
- status = init_dc_connection_rpc(domain);
+ status = init_dc_connection_rpc(domain, false);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
if (conn->lsa_pipe_tcp &&
conn->lsa_pipe_tcp->transport->transport == NCACN_IP_TCP &&
- conn->lsa_pipe_tcp->auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY &&
+ conn->lsa_pipe_tcp->auth->auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY &&
rpccli_is_connected(conn->lsa_pipe_tcp)) {
goto done;
}
}
status = cli_rpc_pipe_open_schannel_with_key(conn->cli,
- &ndr_table_lsarpc.syntax_id,
+ &ndr_table_lsarpc,
NCACN_IP_TCP,
- DCERPC_AUTH_LEVEL_PRIVACY,
domain->name,
- &creds,
+ creds,
&conn->lsa_pipe_tcp);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10,("cli_rpc_pipe_open_schannel_with_key failed: %s\n",
{
struct winbindd_cm_conn *conn;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
- struct netlogon_creds_CredentialState *p_creds;
+ struct netlogon_creds_cli_context *p_creds;
- result = init_dc_connection_rpc(domain);
+ result = init_dc_connection_rpc(domain, false);
if (!NT_STATUS_IS_OK(result))
return result;
/* We have an authenticated connection. Use a NTLMSSP SPNEGO
* authenticated LSA pipe with sign & seal. */
- result = cli_rpc_pipe_open_spnego_ntlmssp
- (conn->cli, &ndr_table_lsarpc.syntax_id, NCACN_NP,
- DCERPC_AUTH_LEVEL_PRIVACY,
+ result = cli_rpc_pipe_open_spnego
+ (conn->cli, &ndr_table_lsarpc, NCACN_NP,
+ GENSEC_OID_NTLMSSP,
+ conn->auth_level,
+ smbXcli_conn_remote_name(conn->cli->conn),
conn->cli->domain, conn->cli->user_name, conn->cli->password,
&conn->lsa_pipe);
goto anonymous;
}
result = cli_rpc_pipe_open_schannel_with_key
- (conn->cli, &ndr_table_lsarpc.syntax_id, NCACN_NP,
- DCERPC_AUTH_LEVEL_PRIVACY,
- domain->name, &p_creds, &conn->lsa_pipe);
+ (conn->cli, &ndr_table_lsarpc, NCACN_NP,
+ domain->name, p_creds, &conn->lsa_pipe);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
anonymous:
result = cli_rpc_pipe_open_noauth(conn->cli,
- &ndr_table_lsarpc.syntax_id,
+ &ndr_table_lsarpc,
&conn->lsa_pipe);
if (!NT_STATUS_IS_OK(result)) {
- result = NT_STATUS_PIPE_NOT_AVAILABLE;
goto done;
}
return result;
}
+/****************************************************************************
+Open a LSA connection to a DC, suiteable for LSA lookup calls.
+****************************************************************************/
+
+NTSTATUS cm_connect_lsat(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client **cli,
+ struct policy_handle *lsa_policy)
+{
+ NTSTATUS status;
+
+ if (domain->can_do_ncacn_ip_tcp) {
+ status = cm_connect_lsa_tcp(domain, mem_ctx, cli);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
+ invalidate_cm_connection(&domain->conn);
+ status = cm_connect_lsa_tcp(domain, mem_ctx, cli);
+ }
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * we tried twice to connect via ncan_ip_tcp and schannel and
+ * failed - maybe it is a trusted domain we can't connect to ?
+ * do not try tcp next time - gd
+ */
+ domain->can_do_ncacn_ip_tcp = false;
+ }
+
+ status = cm_connect_lsa(domain, mem_ctx, cli, lsa_policy);
+
+ return status;
+}
+
/****************************************************************************
Open the netlogon pipe to this DC. Use schannel if specified in client conf.
session key stored in conn->netlogon_pipe->dc->sess_key.
NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
struct rpc_pipe_client **cli)
{
+ struct messaging_context *msg_ctx = winbind_messaging_context();
struct winbindd_cm_conn *conn;
NTSTATUS result;
-
- uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
- uint8 mach_pwd[16];
enum netr_SchannelType sec_chan_type;
+ const char *_account_name;
const char *account_name;
- struct rpc_pipe_client *netlogon_pipe = NULL;
+ struct samr_Password current_nt_hash;
+ struct samr_Password *previous_nt_hash = NULL;
+ struct netlogon_creds_CredentialState *creds = NULL;
+ bool ok;
*cli = NULL;
- result = init_dc_connection_rpc(domain);
+ result = init_dc_connection_rpc(domain, true);
if (!NT_STATUS_IS_OK(result)) {
return result;
}
}
TALLOC_FREE(conn->netlogon_pipe);
-
- result = cli_rpc_pipe_open_noauth(conn->cli,
- &ndr_table_netlogon.syntax_id,
- &netlogon_pipe);
- if (!NT_STATUS_IS_OK(result)) {
- return result;
- }
+ conn->netlogon_flags = 0;
+ TALLOC_FREE(conn->netlogon_creds);
if ((!IS_DC) && (!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;
+ ok = get_trust_pw_hash(domain->name,
+ current_nt_hash.hash,
+ &_account_name,
+ &sec_chan_type);
+ if (!ok) {
+ DEBUG(1, ("get_trust_pw_hash failed for %s, "
+ "unable to get NETLOGON credentials\n",
+ domain->name));
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
- if (!get_trust_pw_hash(domain->name, mach_pwd, &account_name,
- &sec_chan_type))
- {
- TALLOC_FREE(netlogon_pipe);
- return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ account_name = talloc_asprintf(talloc_tos(), "%s$", _account_name);
+ if (account_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
- result = rpccli_netlogon_setup_creds(
- netlogon_pipe,
- domain->dcname, /* server name. */
- domain->name, /* domain name */
- global_myname(), /* client name */
- account_name, /* machine account */
- mach_pwd, /* machine password */
- sec_chan_type, /* from get_trust_pw */
- &neg_flags);
+ result = rpccli_create_netlogon_creds(domain->dcname,
+ domain->name,
+ account_name,
+ sec_chan_type,
+ msg_ctx,
+ domain,
+ &conn->netlogon_creds);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(1, ("rpccli_create_netlogon_creds failed for %s, "
+ "unable to create NETLOGON credentials: %s\n",
+ domain->name, nt_errstr(result)));
+ SAFE_FREE(previous_nt_hash);
+ return result;
+ }
+ result = rpccli_setup_netlogon_creds(conn->cli,
+ conn->netlogon_creds,
+ conn->netlogon_force_reauth,
+ current_nt_hash,
+ previous_nt_hash);
+ conn->netlogon_force_reauth = false;
+ SAFE_FREE(previous_nt_hash);
if (!NT_STATUS_IS_OK(result)) {
- TALLOC_FREE(netlogon_pipe);
+ DEBUG(1, ("rpccli_setup_netlogon_creds failed for %s, "
+ "unable to setup NETLOGON credentials: %s\n",
+ domain->name, nt_errstr(result)));
return result;
}
- if ((lp_client_schannel() == True) &&
- ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
- DEBUG(3, ("Server did not offer schannel\n"));
- TALLOC_FREE(netlogon_pipe);
- return NT_STATUS_ACCESS_DENIED;
+ result = netlogon_creds_cli_get(conn->netlogon_creds,
+ talloc_tos(),
+ &creds);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(1, ("netlogon_creds_cli_get failed for %s, "
+ "unable to get NETLOGON credentials: %s\n",
+ domain->name, nt_errstr(result)));
+ return result;
}
+ conn->netlogon_flags = creds->negotiate_flags;
+ TALLOC_FREE(creds);
no_schannel:
- if ((lp_client_schannel() == False) ||
- ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
- /*
- * NetSamLogonEx only works for schannel
- */
- domain->can_do_samlogon_ex = False;
+ if (!(conn->netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
+ result = cli_rpc_pipe_open_noauth(conn->cli,
+ &ndr_table_netlogon,
+ &conn->netlogon_pipe);
+ if (!NT_STATUS_IS_OK(result)) {
+ invalidate_cm_connection(conn);
+ return result;
+ }
- /* We're done - just keep the existing connection to NETLOGON
- * open */
- conn->netlogon_pipe = netlogon_pipe;
*cli = conn->netlogon_pipe;
return NT_STATUS_OK;
}
*/
result = cli_rpc_pipe_open_schannel_with_key(
- conn->cli, &ndr_table_netlogon.syntax_id, NCACN_NP,
- DCERPC_AUTH_LEVEL_PRIVACY, domain->name, &netlogon_pipe->dc,
+ conn->cli, &ndr_table_netlogon, NCACN_NP,
+ domain->name,
+ conn->netlogon_creds,
&conn->netlogon_pipe);
-
- /* We can now close the initial netlogon pipe. */
- TALLOC_FREE(netlogon_pipe);
-
if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
"was %s\n", nt_errstr(result)));
return result;
}
- /*
- * Always try netr_LogonSamLogonEx. We will fall back for NT4
- * which gives DCERPC_FAULT_OP_RNG_ERROR (function not
- * supported). We used to only try SamLogonEx for AD, but
- * Samba DCs can also do it. And because we don't distinguish
- * between Samba and NT4, always try it once.
- */
- domain->can_do_samlogon_ex = true;
-
*cli = conn->netlogon_pipe;
return NT_STATUS_OK;
}
for (domain = domain_list(); domain != NULL; domain = domain->next) {
char sockaddr[INET6_ADDRSTRLEN];
- if (domain->conn.cli == NULL) {
- continue;
- }
- if (domain->conn.cli->fd == -1) {
+
+ if (!cli_state_is_connected(domain->conn.cli)) {
continue;
}
- client_socket_addr(domain->conn.cli->fd, sockaddr,
- sizeof(sockaddr));
+
+ print_sockaddr(sockaddr, sizeof(sockaddr),
+ smbXcli_conn_local_sockaddr(domain->conn.cli->conn));
+
if (strequal(sockaddr, addr)) {
- close(domain->conn.cli->fd);
- domain->conn.cli->fd = -1;
+ smbXcli_conn_disconnect(domain->conn.cli->conn, NT_STATUS_OK);
}
}
TALLOC_FREE(freeit);