#include "includes.h"
#include "winbindd.h"
+#include "lib/util_unixsids.h"
#include "secrets.h"
#include "../libcli/security/security.h"
#include "../libcli/auth/pam_errors.h"
#include "passdb.h"
#include "source4/lib/messaging/messaging.h"
#include "librpc/gen_ndr/ndr_lsa.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
#include "auth/credentials/credentials.h"
+#include "libsmb/samlogon_cache.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
-static struct winbindd_domain *
-add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc,
- struct winbindd_methods *methods);
-
-extern struct winbindd_methods cache_methods;
-
/**
* @file winbindd_util.c
*
If the domain already exists in the list,
return it and don't re-initialize. */
-static struct winbindd_domain *
-add_trusted_domain(const char *domain_name, const char *alt_name,
- struct winbindd_methods *methods, const struct dom_sid *sid)
+static NTSTATUS add_trusted_domain(const char *domain_name,
+ const char *dns_name,
+ const struct dom_sid *sid,
+ uint32_t trust_type,
+ uint32_t trust_flags,
+ uint32_t trust_attribs,
+ enum netr_SchannelType secure_channel_type,
+ struct winbindd_domain **_d)
{
- struct winbindd_tdc_domain tdc;
-
- ZERO_STRUCT(tdc);
-
- tdc.domain_name = domain_name;
- tdc.dns_name = alt_name;
- if (sid) {
- sid_copy(&tdc.sid, sid);
- }
-
- return add_trusted_domain_from_tdc(&tdc, methods);
-}
-
-/* Add a trusted domain out of a trusted domain cache
- entry
-*/
-static struct winbindd_domain *
-add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc,
- struct winbindd_methods *methods)
-{
- struct winbindd_domain *domain;
- const char *alternative_name = NULL;
- const char **ignored_domains, **dom;
+ struct winbindd_domain *domain = NULL;
+ const char **ignored_domains = NULL;
+ const char **dom = NULL;
int role = lp_server_role();
- const char *domain_name = tdc->domain_name;
- const struct dom_sid *sid = &tdc->sid;
if (is_null_sid(sid)) {
- sid = NULL;
+ DBG_ERR("Got null SID for domain [%s]\n", domain_name);
+ return NT_STATUS_INVALID_PARAMETER;
}
ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
for (dom=ignored_domains; dom && *dom; dom++) {
if (gen_fnmatch(*dom, domain_name) == 0) {
DEBUG(2,("Ignoring domain '%s'\n", domain_name));
- return NULL;
+ return NT_STATUS_NO_SUCH_DOMAIN;
}
}
- /* use alt_name if available to allow DNS lookups */
-
- if (tdc->dns_name && *tdc->dns_name) {
- alternative_name = tdc->dns_name;
- }
-
- /* We can't call domain_list() as this function is called from
- init_domain_list() and we'll get stuck in a loop. */
+ /*
+ * We can't call domain_list() as this function is called from
+ * init_domain_list() and we'll get stuck in a loop.
+ */
for (domain = _domain_list; domain; domain = domain->next) {
- if (strequal(domain_name, domain->name) ||
- strequal(domain_name, domain->alt_name))
- {
+ if (strequal(domain_name, domain->name)) {
break;
}
+ }
- if (alternative_name) {
- if (strequal(alternative_name, domain->name) ||
- strequal(alternative_name, domain->alt_name))
- {
+ if (domain != NULL) {
+ struct winbindd_domain *check_domain = NULL;
+
+ for (check_domain = _domain_list;
+ check_domain != NULL;
+ check_domain = check_domain->next)
+ {
+ if (check_domain == domain) {
+ continue;
+ }
+
+ if (dom_sid_equal(&check_domain->sid, sid)) {
break;
}
}
- if (sid != NULL) {
- if (dom_sid_equal(sid, &domain->sid)) {
+ if (check_domain != NULL) {
+ DBG_ERR("SID [%s] already used by domain [%s], "
+ "expected [%s]\n",
+ sid_string_dbg(sid), check_domain->name,
+ domain->name);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if ((domain != NULL) && (dns_name != NULL)) {
+ struct winbindd_domain *check_domain = NULL;
+
+ for (check_domain = _domain_list;
+ check_domain != NULL;
+ check_domain = check_domain->next)
+ {
+ if (check_domain == domain) {
+ continue;
+ }
+
+ if (strequal(check_domain->alt_name, dns_name)) {
break;
}
}
+
+ if (check_domain != NULL) {
+ DBG_ERR("DNS name [%s] used by domain [%s], "
+ "expected [%s]\n",
+ dns_name, check_domain->name,
+ domain->name);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
}
if (domain != NULL) {
- /*
- * We found a match on domain->name or
- * domain->alt_name. Possibly update the SID
- * if the stored SID was the NULL SID
- * and return the matching entry.
- */
- if ((sid != NULL)
- && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
- sid_copy( &domain->sid, sid );
- }
- return domain;
+ *_d = domain;
+ return NT_STATUS_OK;
}
/* Create new domain entry */
domain = talloc_zero(NULL, struct winbindd_domain);
if (domain == NULL) {
- return NULL;
+ return NT_STATUS_NO_MEMORY;
}
domain->children = talloc_zero_array(domain,
lp_winbind_max_domain_connections());
if (domain->children == NULL) {
TALLOC_FREE(domain);
- return NULL;
+ return NT_STATUS_NO_MEMORY;
}
domain->name = talloc_strdup(domain, domain_name);
if (domain->name == NULL) {
TALLOC_FREE(domain);
- return NULL;
+ return NT_STATUS_NO_MEMORY;
}
- if (alternative_name) {
- domain->alt_name = talloc_strdup(domain, alternative_name);
+ if (dns_name != NULL) {
+ domain->alt_name = talloc_strdup(domain, dns_name);
if (domain->alt_name == NULL) {
TALLOC_FREE(domain);
- return NULL;
+ return NT_STATUS_NO_MEMORY;
}
}
- domain->methods = methods;
domain->backend = NULL;
domain->internal = is_internal_domain(sid);
+ domain->secure_channel_type = secure_channel_type;
domain->sequence_number = DOM_SEQUENCE_NONE;
domain->last_seq_check = 0;
domain->initialized = false;
domain->online = is_internal_domain(sid);
domain->check_online_timeout = 0;
domain->dc_probe_pid = (pid_t)-1;
- if (sid != NULL) {
- sid_copy(&domain->sid, sid);
- }
- domain->domain_flags = tdc->trust_flags;
- domain->domain_type = tdc->trust_type;
- domain->domain_trust_attribs = tdc->trust_attribs;
+ domain->domain_flags = trust_flags;
+ domain->domain_type = trust_type;
+ domain->domain_trust_attribs = trust_attribs;
+ domain->secure_channel_type = secure_channel_type;
+ sid_copy(&domain->sid, sid);
/* Is this our primary domain ? */
- if (strequal(domain_name, get_global_sam_name()) &&
- (role != ROLE_DOMAIN_MEMBER)) {
- domain->primary = true;
- } else if (strequal(domain_name, lp_workgroup()) &&
- (role == ROLE_DOMAIN_MEMBER)) {
- domain->primary = true;
+ if (role == ROLE_DOMAIN_MEMBER) {
+ domain->primary = strequal(domain_name, lp_workgroup());
+ } else {
+ domain->primary = strequal(domain_name, get_global_sam_name());
}
if (domain->primary) {
setup_domain_child(domain);
- DEBUG(2,
- ("Added domain %s %s %s\n", domain->name, domain->alt_name,
- !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));
+ DBG_NOTICE("Added domain [%s] [%s] [%s]\n",
+ domain->name, domain->alt_name,
+ sid_string_dbg(&domain->sid));
- return domain;
+ *_d = domain;
+ return NT_STATUS_OK;
+}
+
+bool set_routing_domain(struct winbindd_domain *domain,
+ const struct winbindd_domain *routing_domain)
+{
+ if (domain->routing_domain == NULL) {
+ domain->routing_domain = routing_domain;
+ return true;
+ }
+ if (domain->routing_domain != routing_domain) {
+ return false;
+ }
+ return true;
+}
+
+bool add_trusted_domain_from_auth(uint16_t validation_level,
+ struct info3_text *info3,
+ struct info6_text *info6)
+{
+ struct winbindd_domain *domain = NULL;
+ struct dom_sid domain_sid;
+ const char *dns_domainname = NULL;
+ NTSTATUS status;
+ bool ok;
+
+ /*
+ * We got a successfull auth from a domain that might not yet be in our
+ * domain list. If we're a member we trust our DC who authenticated the
+ * user from that domain and add the domain to our list on-the-fly. If
+ * we're a DC we rely on configured trusts and don't add on-the-fly.
+ */
+
+ if (IS_DC) {
+ return true;
+ }
+
+ ok = dom_sid_parse(info3->dom_sid, &domain_sid);
+ if (!ok) {
+ DBG_NOTICE("dom_sid_parse [%s] failed\n", info3->dom_sid);
+ return false;
+ }
+
+ if (validation_level == 6) {
+ dns_domainname = &info6->dns_domainname[0];
+ }
+
+ status = add_trusted_domain(info3->logon_dom,
+ dns_domainname,
+ &domain_sid,
+ 0,
+ NETR_TRUST_FLAG_OUTBOUND,
+ 0,
+ SEC_CHAN_NULL,
+ &domain);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
+ {
+ DBG_DEBUG("Adding domain [%s] with sid [%s] failed\n",
+ info3->logon_dom, info3->dom_sid);
+ return false;
+ }
+
+ ok = set_routing_domain(domain, find_default_route_domain());
+ if (!ok) {
+ return false;
+ }
+
+ return true;
}
bool domain_is_forest_root(const struct winbindd_domain *domain)
state->request.length = sizeof(state->request);
state->request.cmd = WINBINDD_LIST_TRUSTDOM;
- req = wb_domain_request_send(state, winbind_event_context(),
+ req = wb_domain_request_send(state, server_event_context(),
domain, &state->request);
if (req == NULL) {
DEBUG(1, ("wb_domain_request_send failed\n"));
struct winbindd_response *response;
int res, err;
char *p;
- struct winbindd_tdc_domain trust_params = {0};
ptrdiff_t extra_len;
+ bool within_forest = false;
+ NTSTATUS status;
+ bool ok;
+
+ /*
+ * Only when we enumerate our primary domain
+ * or our forest root domain, we should keep
+ * the NETR_TRUST_FLAG_IN_FOREST flag, in
+ * all other cases we need to clear it as the domain
+ * is not part of our forest.
+ */
+ if (state->domain->primary) {
+ within_forest = true;
+ } else if (domain_is_forest_root(state->domain)) {
+ within_forest = true;
+ }
res = wb_domain_request_recv(req, state, &response, &err);
if ((res == -1) || (response->result != WINBINDD_OK)) {
- DBG_WARNING("Could not receive trustdoms\n");
+ DBG_WARNING("Could not receive trusts for domain %s\n",
+ state->domain->name);
TALLOC_FREE(state);
return;
}
p = (char *)response->extra_data.data;
while ((p - (char *)response->extra_data.data) < extra_len) {
- char *q, *sidstr, *alt_name;
+ struct winbindd_domain *domain = NULL;
+ char *name, *q, *sidstr, *alt_name;
+ struct dom_sid sid;
+ uint32_t trust_type;
+ uint32_t trust_attribs;
+ uint32_t trust_flags;
DBG_DEBUG("parsing response line '%s'\n", p);
- ZERO_STRUCT(trust_params);
- trust_params.domain_name = p;
+ name = p;
alt_name = strchr(p, '\\');
if (alt_name == NULL) {
sidstr += 1;
/* use the real alt_name if we have one, else pass in NULL */
- if (!strequal(alt_name, "(null)")) {
- trust_params.dns_name = alt_name;
+ if (strequal(alt_name, "(null)")) {
+ alt_name = NULL;
}
q = strtok(sidstr, "\\");
break;
}
- if (!string_to_sid(&trust_params.sid, sidstr)) {
+ if (!string_to_sid(&sid, sidstr)) {
DEBUG(0, ("Got invalid trustdom response\n"));
break;
}
break;
}
- trust_params.trust_flags = (uint32_t)strtoul(q, NULL, 10);
+ trust_flags = (uint32_t)strtoul(q, NULL, 10);
q = strtok(NULL, "\\");
if (q == NULL) {
break;
}
- trust_params.trust_type = (uint32_t)strtoul(q, NULL, 10);
+ trust_type = (uint32_t)strtoul(q, NULL, 10);
q = strtok(NULL, "\n");
if (q == NULL) {
break;
}
- trust_params.trust_attribs = (uint32_t)strtoul(q, NULL, 10);
+ trust_attribs = (uint32_t)strtoul(q, NULL, 10);
+
+ if (!within_forest) {
+ trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
+ }
+
+ if (!state->domain->primary) {
+ trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
+ }
/*
* We always call add_trusted_domain() cause on an existing
* This is important because we need the SID for sibling
* domains.
*/
- (void)add_trusted_domain_from_tdc(&trust_params,
- &cache_methods);
+ status = add_trusted_domain(name,
+ alt_name,
+ &sid,
+ trust_type,
+ trust_flags,
+ trust_attribs,
+ SEC_CHAN_NULL,
+ &domain);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
+ {
+ DBG_NOTICE("add_trusted_domain returned %s\n",
+ nt_errstr(status));
+ return;
+ }
+
+ ok = set_routing_domain(domain, find_default_route_domain());
+ if (!ok) {
+ DBG_ERR("set_routing_domain failed\n");
+ return;
+ }
p = q + strlen(q) + 1;
}
struct winbindd_tdc_domain *dom_list = NULL;
size_t num_trusts = 0;
int i;
+ NTSTATUS status;
+ bool ok;
/* The only transitive trusts supported by Windows 2003 AD are
(a) Parent-Child, (b) Tree-Root, and (c) Forest. The
/* Here's the forest root */
d = find_domain_from_name_noinit( dom_list[i].domain_name );
-
- if ( !d ) {
- d = add_trusted_domain_from_tdc(&dom_list[i],
- &cache_methods);
+ if (d == NULL) {
+ status = add_trusted_domain(dom_list[i].domain_name,
+ dom_list[i].dns_name,
+ &dom_list[i].sid,
+ dom_list[i].trust_type,
+ dom_list[i].trust_flags,
+ dom_list[i].trust_attribs,
+ SEC_CHAN_NULL,
+ &d);
+
+ if (!NT_STATUS_IS_OK(status) &&
+ NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
+ {
+ DBG_ERR("add_trusted_domain returned %s\n",
+ nt_errstr(status));
+ return;
+ }
+ ok = set_routing_domain(d, find_default_route_domain());
+ if (!ok) {
+ DBG_ERR("set_routing_domain failed\n");
+ return;
+ }
}
-
if (d == NULL) {
continue;
}
struct winbindd_tdc_domain *dom_list = NULL;
size_t num_trusts = 0;
int i;
+ NTSTATUS status;
+ bool ok;
/* The only transitive trusts supported by Windows 2003 AD are
(a) Parent-Child, (b) Tree-Root, and (c) Forest. The
/* add the trusted domain if we don't know
about it */
- if ( !d ) {
- d = add_trusted_domain_from_tdc(&dom_list[i],
- &cache_methods);
+ if (d == NULL) {
+ status = add_trusted_domain(
+ dom_list[i].domain_name,
+ dom_list[i].dns_name,
+ &dom_list[i].sid,
+ type,
+ flags,
+ attribs,
+ SEC_CHAN_NULL,
+ &d);
+ if (!NT_STATUS_IS_OK(status) &&
+ NT_STATUS_EQUAL(status,
+ NT_STATUS_NO_SUCH_DOMAIN))
+ {
+ DBG_ERR("add_trusted_domain: %s\n",
+ nt_errstr(status));
+ return;
+ }
+ ok = set_routing_domain(
+ d, find_default_route_domain());
+ if (!ok) {
+ DBG_ERR("set_routing_domain failed\n");
+ return;
+ }
}
if (d == NULL) {
DATA_BLOB *data)
{
TALLOC_CTX *frame = talloc_stackframe();
+ enum netr_SchannelType secure_channel_type = SEC_CHAN_DOMAIN;
struct lsa_TrustDomainInfoInfoEx info;
enum ndr_err_code ndr_err;
struct winbindd_domain *d = NULL;
+ uint32_t trust_flags = 0;
+ NTSTATUS status;
+ bool ok;
DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
return;
}
- d = add_trusted_domain(info.netbios_name.string,
- info.domain_name.string,
- &cache_methods,
- info.sid);
- if (d == NULL) {
- TALLOC_FREE(frame);
- return;
+ if (info.trust_type == LSA_TRUST_TYPE_UPLEVEL) {
+ secure_channel_type = SEC_CHAN_DNS_DOMAIN;
}
-
- if (d->internal) {
- TALLOC_FREE(frame);
- return;
- }
-
- if (d->primary) {
- TALLOC_FREE(frame);
- return;
- }
-
if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
- d->domain_flags |= NETR_TRUST_FLAG_INBOUND;
+ trust_flags |= NETR_TRUST_FLAG_INBOUND;
}
if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
- d->domain_flags |= NETR_TRUST_FLAG_OUTBOUND;
+ trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
}
if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
- d->domain_flags |= NETR_TRUST_FLAG_IN_FOREST;
+ trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
+ }
+
+ status = add_trusted_domain(info.netbios_name.string,
+ info.domain_name.string,
+ info.sid,
+ info.trust_type,
+ trust_flags,
+ info.trust_attributes,
+ secure_channel_type,
+ &d);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
+ {
+ DBG_NOTICE("add_trusted_domain returned %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(frame);
+ return;
+ }
+ ok = set_routing_domain(d, find_default_route_domain());
+ if (!ok) {
+ TALLOC_FREE(frame);
+ return;
}
- d->domain_type = info.trust_type;
- d->domain_trust_attribs = info.trust_attributes;
-
TALLOC_FREE(frame);
}
bool init_domain_list(void)
{
int role = lp_server_role();
+ struct pdb_domain_info *pdb_domain_info = NULL;
+ struct winbindd_domain *domain = NULL;
NTSTATUS status;
/* Free existing list */
/* BUILTIN domain */
- (void)add_trusted_domain("BUILTIN", NULL, &cache_methods,
- &global_sid_Builtin);
+ status = add_trusted_domain("BUILTIN",
+ NULL,
+ &global_sid_Builtin,
+ LSA_TRUST_TYPE_DOWNLEVEL,
+ 0, /* trust_flags */
+ 0, /* trust_attribs */
+ SEC_CHAN_LOCAL,
+ &domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
+ nt_errstr(status));
+ return false;
+ }
/* Local SAM */
+ /*
+ * In case the passdb backend is passdb_dsdb the domain SID comes from
+ * dsdb, not from secrets.tdb. As we use the domain SID in various
+ * places, we must ensure the domain SID is migrated from dsdb to
+ * secrets.tdb before get_global_sam_sid() is called the first time.
+ *
+ * The migration is done as part of the passdb_dsdb initialisation,
+ * calling pdb_get_domain_info() triggers it.
+ */
+ pdb_domain_info = pdb_get_domain_info(talloc_tos());
+
if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
- struct winbindd_domain *domain;
+ uint32_t trust_flags;
+ bool is_root;
enum netr_SchannelType sec_chan_type;
const char *account_name;
struct samr_Password current_nt_hash;
- struct pdb_domain_info *pdb_domain_info;
bool ok;
- pdb_domain_info = pdb_get_domain_info(talloc_tos());
if (pdb_domain_info == NULL) {
DEBUG(0, ("Failed to fetch our own, local AD "
"domain info from sam.ldb\n"));
return false;
}
- domain = add_trusted_domain(pdb_domain_info->name,
- pdb_domain_info->dns_domain,
- &cache_methods,
- &pdb_domain_info->sid);
+
+ trust_flags = NETR_TRUST_FLAG_PRIMARY;
+ trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
+ trust_flags |= NETR_TRUST_FLAG_NATIVE;
+ trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
+
+ is_root = strequal(pdb_domain_info->dns_domain,
+ pdb_domain_info->dns_forest);
+ if (is_root) {
+ trust_flags |= NETR_TRUST_FLAG_TREEROOT;
+ }
+
+ status = add_trusted_domain(pdb_domain_info->name,
+ pdb_domain_info->dns_domain,
+ &pdb_domain_info->sid,
+ LSA_TRUST_TYPE_UPLEVEL,
+ trust_flags,
+ LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
+ SEC_CHAN_BDC,
+ &domain);
TALLOC_FREE(pdb_domain_info);
- if (domain == NULL) {
- DEBUG(0, ("Failed to add our own, local AD "
- "domain to winbindd's internal list\n"));
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("Failed to add our own, local AD "
+ "domain to winbindd's internal list\n");
return false;
}
*/
ok = migrate_secrets_tdb_to_ldb(domain);
- if (ok == false) {
+ if (!ok) {
DEBUG(0, ("Failed to migrate our own, "
"local AD domain join password for "
"winbindd's internal use into "
current_nt_hash.hash,
&account_name,
&sec_chan_type);
- if (ok == false) {
+ if (!ok) {
DEBUG(0, ("Failed to find our our own, just "
"written local AD domain join "
"password for winbindd's internal "
return false;
}
}
+
+ domain->secure_channel_type = sec_chan_type;
if (sec_chan_type == SEC_CHAN_RODC) {
domain->rodc = true;
}
} else {
- (void)add_trusted_domain(get_global_sam_name(), NULL,
- &cache_methods, get_global_sam_sid());
+ uint32_t trust_flags;
+ enum netr_SchannelType secure_channel_type;
+
+ trust_flags = NETR_TRUST_FLAG_OUTBOUND;
+ if (role != ROLE_DOMAIN_MEMBER) {
+ trust_flags |= NETR_TRUST_FLAG_PRIMARY;
+ }
+
+ if (role > ROLE_DOMAIN_MEMBER) {
+ secure_channel_type = SEC_CHAN_BDC;
+ } else {
+ secure_channel_type = SEC_CHAN_LOCAL;
+ }
+
+ status = add_trusted_domain(get_global_sam_name(),
+ NULL,
+ get_global_sam_sid(),
+ LSA_TRUST_TYPE_DOWNLEVEL,
+ trust_flags,
+ 0, /* trust_attribs */
+ secure_channel_type,
+ &domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("Failed to add local SAM to "
+ "domain to winbindd's internal list\n");
+ return false;
+ }
}
/* Add ourselves as the first entry. */
if ( role == ROLE_DOMAIN_MEMBER ) {
- struct winbindd_domain *domain;
struct dom_sid our_sid;
+ uint32_t trust_type;
if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
DEBUG(0, ("Could not fetch our SID - did we join?\n"));
return False;
}
- domain = add_trusted_domain( lp_workgroup(), lp_realm(),
- &cache_methods, &our_sid);
- if (domain) {
+ if (lp_realm() != NULL) {
+ trust_type = LSA_TRUST_TYPE_UPLEVEL;
+ } else {
+ trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
+ }
+
+ status = add_trusted_domain(lp_workgroup(),
+ lp_realm(),
+ &our_sid,
+ trust_type,
+ NETR_TRUST_FLAG_PRIMARY|
+ NETR_TRUST_FLAG_OUTBOUND,
+ 0, /* trust_attribs */
+ SEC_CHAN_WKSTA,
+ &domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("Failed to add local SAM to "
+ "domain to winbindd's internal list\n");
+ return false;
+ }
+ /* Even in the parent winbindd we'll need to
+ talk to the DC, so try and see if we can
+ contact it. Theoretically this isn't neccessary
+ as the init_dc_connection() in init_child_recv()
+ will do this, but we can start detecting the DC
+ early here. */
+ set_domain_online_request(domain);
+
+ }
+
+ if (IS_DC && (pdb_capabilities() & PDB_CAP_TRUSTED_DOMAINS_EX)) {
+ uint32_t num_domains = 0;
+ struct pdb_trusted_domain **domains = NULL;
+ uint32_t i;
+
+ status = pdb_enum_trusted_domains(talloc_tos(), &num_domains, &domains);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("pdb_enum_trusted_domains() failed - %s\n",
+ nt_errstr(status));
+ return false;
+ }
+
+ for (i = 0; i < num_domains; i++) {
+ enum netr_SchannelType sec_chan_type = SEC_CHAN_DOMAIN;
+ uint32_t trust_flags = 0;
+
+ if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
+ sec_chan_type = SEC_CHAN_DNS_DOMAIN;
+ }
+
+ if (!(domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
+ sec_chan_type = SEC_CHAN_NULL;
+ }
+
+ if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
+ trust_flags |= NETR_TRUST_FLAG_INBOUND;
+ }
+ if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
+ trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
+ }
+ if (domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
+ trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
+ }
+
+ status = add_trusted_domain(domains[i]->netbios_name,
+ domains[i]->domain_name,
+ &domains[i]->security_identifier,
+ domains[i]->trust_type,
+ trust_flags,
+ domains[i]->trust_attributes,
+ sec_chan_type,
+ &domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_NOTICE("add_trusted_domain returned %s\n",
+ nt_errstr(status));
+ return false;
+ }
+
+ if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
+ domain->active_directory = true;
+ }
+ domain->domain_type = domains[i]->trust_type;
+ domain->domain_trust_attribs = domains[i]->trust_attributes;
+
+ if (sec_chan_type != SEC_CHAN_NULL) {
+ /* Even in the parent winbindd we'll need to
+ talk to the DC, so try and see if we can
+ contact it. Theoretically this isn't neccessary
+ as the init_dc_connection() in init_child_recv()
+ will do this, but we can start detecting the DC
+ early here. */
+ set_domain_online_request(domain);
+ }
+ }
+
+ for (i = 0; i < num_domains; i++) {
+ struct ForestTrustInfo fti;
+ uint32_t fi;
+ enum ndr_err_code ndr_err;
+ struct winbindd_domain *routing_domain = NULL;
+ bool ok;
+
+ if (domains[i]->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
+ continue;
+ }
+
+ if (!(domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
+ continue;
+ }
+
+ if (domains[i]->trust_forest_trust_info.length == 0) {
+ continue;
+ }
+
+ routing_domain = find_domain_from_name_noinit(
+ domains[i]->netbios_name);
+ if (routing_domain == NULL) {
+ DBG_ERR("Can't find winbindd domain [%s]\n",
+ domains[i]->netbios_name);
+ return false;
+ }
+
+ ndr_err = ndr_pull_struct_blob_all(
+ &domains[i]->trust_forest_trust_info,
+ talloc_tos(), &fti,
+ (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_ERR("ndr_pull_ForestTrustInfo(%s) - %s\n",
+ domains[i]->netbios_name,
+ ndr_map_error2string(ndr_err));
+ return false;
+ }
+
+ for (fi = 0; fi < fti.count; fi++) {
+ struct ForestTrustInfoRecord *rec =
+ &fti.records[fi].record;
+ struct ForestTrustDataDomainInfo *drec = NULL;
+
+ if (rec->type != FOREST_TRUST_DOMAIN_INFO) {
+ continue;
+ }
+ drec = &rec->data.info;
+
+ if (rec->flags & LSA_NB_DISABLED_MASK) {
+ continue;
+ }
+
+ if (rec->flags & LSA_SID_DISABLED_MASK) {
+ continue;
+ }
+
+ /*
+ * TODO:
+ * also try to find a matching
+ * LSA_TLN_DISABLED_MASK ???
+ */
+
+ domain = find_domain_from_name_noinit(drec->netbios_name.string);
+ if (domain != NULL) {
+ continue;
+ }
+
+ status = add_trusted_domain(drec->netbios_name.string,
+ drec->dns_name.string,
+ &drec->sid,
+ LSA_TRUST_TYPE_UPLEVEL,
+ NETR_TRUST_FLAG_OUTBOUND,
+ 0,
+ SEC_CHAN_NULL,
+ &domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_NOTICE("add_trusted_domain returned %s\n",
+ nt_errstr(status));
+ return false;
+ }
+ if (domain == NULL) {
+ continue;
+ }
+ ok = set_routing_domain(domain, routing_domain);
+ if (!ok) {
+ DBG_ERR("set_routing_domain on [%s] to "
+ "[%s] failed\n",
+ domain->name,
+ routing_domain->name);
+ return false;
+ }
+ }
+ }
+ } else if (IS_DC) {
+ uint32_t num_domains = 0;
+ struct trustdom_info **domains = NULL;
+ uint32_t i;
+
+ status = pdb_enum_trusteddoms(talloc_tos(), &num_domains, &domains);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("pdb_enum_trusteddoms() failed - %s\n",
+ nt_errstr(status));
+ return false;
+ }
+
+ for (i = 0; i < num_domains; i++) {
+ status = add_trusted_domain(domains[i]->name,
+ NULL,
+ &domains[i]->sid,
+ LSA_TRUST_TYPE_DOWNLEVEL,
+ NETR_TRUST_FLAG_OUTBOUND,
+ 0,
+ SEC_CHAN_DOMAIN,
+ &domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_NOTICE("add_trusted_domain returned %s\n",
+ nt_errstr(status));
+ return false;
+ }
+
/* Even in the parent winbindd we'll need to
talk to the DC, so try and see if we can
contact it. Theoretically this isn't neccessary
/* Search through list */
for (domain = domain_list(); domain != NULL; domain = domain->next) {
- if (strequal(domain_name, domain->name) ||
- (domain->alt_name != NULL &&
- strequal(domain_name, domain->alt_name))) {
+ if (strequal(domain_name, domain->name)) {
+ return domain;
+ }
+ if (domain->alt_name == NULL) {
+ continue;
+ }
+ if (strequal(domain_name, domain->alt_name)) {
return domain;
}
}
return NULL;
}
+/**
+ * Given a domain name, return the struct winbindd domain if it's a direct
+ * outgoing trust
+ *
+ * @return The domain structure for the named domain, if it is a direct outgoing trust
+ */
+struct winbindd_domain *find_trust_from_name_noinit(const char *domain_name)
+{
+ struct winbindd_domain *domain = NULL;
+
+ domain = find_domain_from_name_noinit(domain_name);
+ if (domain == NULL) {
+ return NULL;
+ }
+
+ if (domain->secure_channel_type != SEC_CHAN_NULL) {
+ return domain;
+ }
+
+ return NULL;
+}
+
struct winbindd_domain *find_domain_from_name(const char *domain_name)
{
struct winbindd_domain *domain;
return NULL;
}
+/**
+ * Given a domain sid, return the struct winbindd domain if it's a direct
+ * outgoing trust
+ *
+ * @return The domain structure for the specified domain, if it is a direct outgoing trust
+ */
+struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid)
+{
+ struct winbindd_domain *domain = NULL;
+
+ domain = find_domain_from_sid_noinit(sid);
+ if (domain == NULL) {
+ return NULL;
+ }
+
+ if (domain->secure_channel_type != SEC_CHAN_NULL) {
+ return domain;
+ }
+
+ return NULL;
+}
+
/* Given a domain sid, return the struct winbindd domain info for it */
struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
return NULL;
}
-struct winbindd_domain *find_root_domain(void)
+struct winbindd_domain *find_default_route_domain(void)
{
- struct winbindd_domain *ours = find_our_domain();
-
- if (ours->forest_name == NULL) {
- return NULL;
+ if (!IS_DC) {
+ return find_our_domain();
}
-
- return find_domain_from_name( ours->forest_name );
-}
-
-struct winbindd_domain *find_builtin_domain(void)
-{
- struct winbindd_domain *domain;
-
- domain = find_domain_from_sid(&global_sid_Builtin);
- if (domain == NULL) {
- smb_panic("Could not find BUILTIN domain");
- }
-
- return domain;
+ DBG_ERR("Routing logic not yet implemented on a DC");
+ return NULL;
}
/* Find the appropriate domain to lookup a name or SID */
struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
{
- /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
+ DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
+
+ /*
+ * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
+ * by our passdb.
+ */
if ( sid_check_is_in_unix_groups(sid) ||
sid_check_is_unix_groups(sid) ||
sid_check_is_in_unix_users(sid) ||
- sid_check_is_unix_users(sid) )
+ sid_check_is_unix_users(sid) ||
+ sid_check_is_wellknown_domain(sid, NULL) ||
+ sid_check_is_in_wellknown_domain(sid) )
{
return find_domain_from_sid(get_global_sam_sid());
}
* one to contact the external DC's. On member servers the internal
* domains are different: These are part of the local SAM. */
- DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
-
if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
DEBUG(10, ("calling find_domain_from_sid\n"));
return find_domain_from_sid(sid);
if ( !strequal(lp_workgroup(), domain) )
return False;
- if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
+ if ( lp_winbind_use_default_domain() )
return True;
}
if ( !p ) {
fstrcpy(user, domuser);
+ p = strchr(domuser, '@');
- if ( assume_domain(lp_workgroup())) {
+ if ( assume_domain(lp_workgroup()) && p == NULL) {
fstrcpy(domain, lp_workgroup());
- } else if ((p = strchr(domuser, '@')) != NULL) {
+ } else if (p != NULL) {
fstrcpy(domain, p + 1);
user[PTR_DIFF(p, domuser)] = 0;
} else {
If we are a PDC or BDC, and this is for our domain, do likewise.
- Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
- username is then unqualified in unix
-
On an AD DC we always fill DOMAIN\\USERNAME.
We always canonicalize as UPPERCASE DOMAIN, lowercase username.
return _num_clients;
}
-NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
- TALLOC_CTX *mem_ctx,
+NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
const struct dom_sid *user_sid,
uint32_t *p_num_groups, struct dom_sid **user_sids)
{
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
- if (info3->base.groups.count == 0) {
- TALLOC_FREE(info3);
- return NT_STATUS_UNSUCCESSFUL;
- }
-
/*
* Before bug #7843 the "Domain Local" groups were added with a
* lookupuseraliases call, but this isn't done anymore for our domain
********************************************************************/
NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
- struct winbindd_domain *domain,
+ const char *domain_name,
const char *name,
char **normalized)
{
+ struct winbindd_domain *domain = NULL;
NTSTATUS nt_status;
if (!name || !normalized) {
return NT_STATUS_PROCEDURE_NOT_FOUND;
}
+ domain = find_domain_from_name_noinit(domain_name);
+ if (domain == NULL) {
+ DBG_ERR("Failed to find domain '%s'\n", domain_name);
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
/* Alias support and whitespace replacement are mutually
exclusive */
bool is_domain_offline(const struct winbindd_domain *domain)
{
- if (!lp_winbind_offline_logon()) {
- return false;
- }
if (get_global_winbindd_state_offline()) {
return true;
}
DEBUG(1, ("Could not parse sid %s\n", p));
return false;
}
- if ((q == NULL) || (q[0] != '\n')) {
+ if (q[0] != '\n') {
DEBUG(1, ("Got invalid sidstr: %s\n", p));
return false;
}