#include "passdb.h"
#include "source4/lib/messaging/messaging.h"
#include "librpc/gen_ndr/ndr_lsa.h"
+#include "auth/credentials/credentials.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;
/**
domain = domain->next;
}
- if ((domain != NULL)
- && sid_check_is_our_sam(&domain->sid)) {
+ if ((domain != NULL) &&
+ (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) &&
+ sid_check_is_our_sam(&domain->sid))
+ {
domain = domain->next;
}
+
return domain;
}
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 struct winbindd_domain *
+add_trusted_domain(const char *domain_name, const char *alt_name,
+ struct winbindd_methods *methods, const struct dom_sid *sid)
+{
+ 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;
- char *idmap_config_option;
- const char *param;
const char **ignored_domains, **dom;
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;
+ }
ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
for (dom=ignored_domains; dom && *dom; dom++) {
/* use alt_name if available to allow DNS lookups */
- if (alt_name && *alt_name) {
- alternative_name = alt_name;
+ if (tdc->dns_name && *tdc->dns_name) {
+ alternative_name = tdc->dns_name;
}
/* We can't call domain_list() as this function is called from
break;
}
- if (alternative_name && *alternative_name)
- {
+ if (alternative_name) {
if (strequal(alternative_name, domain->name) ||
strequal(alternative_name, domain->alt_name))
{
}
}
- if (sid)
- {
- if (is_null_sid(sid)) {
- continue;
- }
-
+ if (sid != NULL) {
if (dom_sid_equal(sid, &domain->sid)) {
break;
}
domain->internal = is_internal_domain(sid);
domain->sequence_number = DOM_SEQUENCE_NONE;
domain->last_seq_check = 0;
- domain->initialized = False;
+ domain->initialized = false;
domain->online = is_internal_domain(sid);
domain->check_online_timeout = 0;
domain->dc_probe_pid = (pid_t)-1;
- if (sid) {
+ 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;
/* Is this our primary domain ? */
if (strequal(domain_name, get_global_sam_name()) &&
if (lp_security() == SEC_ADS) {
domain->active_directory = true;
}
+ } else if (!domain->internal) {
+ if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
+ domain->active_directory = true;
+ }
}
/* Link to domain list */
- DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
+ DLIST_ADD_END(_domain_list, domain);
wcache_tdc_add_domain( domain );
- idmap_config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
- domain->name);
- if (idmap_config_option == NULL) {
- DEBUG(0, ("talloc failed, not looking for idmap config\n"));
- goto done;
- }
-
- param = lp_parm_const_string(-1, idmap_config_option, "range", NULL);
-
- DEBUG(10, ("%s : range = %s\n", idmap_config_option,
- param ? param : "not defined"));
-
- if (param != NULL) {
- unsigned low_id, high_id;
- if (sscanf(param, "%u - %u", &low_id, &high_id) != 2) {
- DEBUG(1, ("invalid range syntax in %s: %s\n",
- idmap_config_option, param));
- goto done;
- }
- if (low_id > high_id) {
- DEBUG(1, ("invalid range in %s: %s\n",
- idmap_config_option, param));
- goto done;
- }
- domain->have_idmap_config = true;
- domain->id_range_low = low_id;
- domain->id_range_high = high_id;
- }
-
-done:
-
setup_domain_child(domain);
- DEBUG(2,("Added domain %s %s %s\n",
- domain->name, domain->alt_name,
- &domain->sid?sid_string_dbg(&domain->sid):""));
+ DEBUG(2,
+ ("Added domain %s %s %s\n", domain->name, domain->alt_name,
+ !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));
return domain;
}
struct winbindd_response *response;
int res, err;
char *p;
+ struct winbindd_tdc_domain trust_params = {0};
+ ptrdiff_t extra_len;
res = wb_domain_request_recv(req, state, &response, &err);
if ((res == -1) || (response->result != WINBINDD_OK)) {
- DEBUG(1, ("Could not receive trustdoms\n"));
+ DBG_WARNING("Could not receive trusts for domain %s\n",
+ state->domain->name);
+ TALLOC_FREE(state);
+ return;
+ }
+
+ if (response->length < sizeof(struct winbindd_response)) {
+ DBG_ERR("ill-formed trustdom response - short length\n");
TALLOC_FREE(state);
return;
}
+ extra_len = response->length - sizeof(struct winbindd_response);
+
p = (char *)response->extra_data.data;
- while ((p != NULL) && (*p != '\0')) {
+ while ((p - (char *)response->extra_data.data) < extra_len) {
char *q, *sidstr, *alt_name;
- struct dom_sid sid;
- char *alternate_name = NULL;
+
+ DBG_DEBUG("parsing response line '%s'\n", p);
+
+ ZERO_STRUCT(trust_params);
+ trust_params.domain_name = p;
alt_name = strchr(p, '\\');
if (alt_name == NULL) {
- DEBUG(0, ("Got invalid trustdom response\n"));
+ DBG_ERR("Got invalid trustdom response\n");
break;
}
sidstr = strchr(alt_name, '\\');
if (sidstr == NULL) {
- DEBUG(0, ("Got invalid trustdom response\n"));
+ DBG_ERR("Got invalid trustdom response\n");
break;
}
*sidstr = '\0';
sidstr += 1;
- q = strchr(sidstr, '\n');
- if (q != NULL)
- *q = '\0';
+ /* 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 (!string_to_sid(&sid, sidstr)) {
+ q = strtok(sidstr, "\\");
+ if (q == NULL) {
+ DBG_ERR("Got invalid trustdom response\n");
+ break;
+ }
+
+ if (!string_to_sid(&trust_params.sid, sidstr)) {
DEBUG(0, ("Got invalid trustdom response\n"));
break;
}
- /* use the real alt_name if we have one, else pass in NULL */
+ q = strtok(NULL, "\\");
+ if (q == NULL) {
+ DBG_ERR("Got invalid trustdom response\n");
+ break;
+ }
+
+ trust_params.trust_flags = (uint32_t)strtoul(q, NULL, 10);
+
+ q = strtok(NULL, "\\");
+ if (q == NULL) {
+ DBG_ERR("Got invalid trustdom response\n");
+ break;
+ }
+
+ trust_params.trust_type = (uint32_t)strtoul(q, NULL, 10);
+
+ q = strtok(NULL, "\n");
+ if (q == NULL) {
+ DBG_ERR("Got invalid trustdom response\n");
+ break;
+ }
- if ( !strequal( alt_name, "(null)" ) )
- alternate_name = alt_name;
+ trust_params.trust_attribs = (uint32_t)strtoul(q, NULL, 10);
/*
* 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(p, alternate_name,
- &cache_methods,
- &sid);
+ (void)add_trusted_domain_from_tdc(&trust_params,
+ &cache_methods);
- p=q;
- if (p != NULL)
- p += 1;
+ p = q + strlen(q) + 1;
}
/*
d = find_domain_from_name_noinit( dom_list[i].domain_name );
if ( !d ) {
- d = add_trusted_domain( dom_list[i].domain_name,
- dom_list[i].dns_name,
- &cache_methods,
- &dom_list[i].sid );
+ d = add_trusted_domain_from_tdc(&dom_list[i],
+ &cache_methods);
}
if (d == NULL) {
return;
for ( i=0; i<num_trusts; i++ ) {
- uint32 flags = dom_list[i].trust_flags;
- uint32 type = dom_list[i].trust_type;
- uint32 attribs = dom_list[i].trust_attribs;
+ uint32_t flags = dom_list[i].trust_flags;
+ uint32_t type = dom_list[i].trust_type;
+ uint32_t attribs = dom_list[i].trust_attribs;
d = find_domain_from_name_noinit( dom_list[i].domain_name );
about it */
if ( !d ) {
- d = add_trusted_domain( dom_list[i].domain_name,
- dom_list[i].dns_name,
- &cache_methods,
- &dom_list[i].sid );
+ d = add_trusted_domain_from_tdc(&dom_list[i],
+ &cache_methods);
}
if (d == NULL) {
TALLOC_FREE(frame);
}
+/*
+ * We did not get the secret when we queried secrets.tdb, so read it
+ * from secrets.tdb and re-sync the databases
+ */
+static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
+{
+ bool ok;
+ struct cli_credentials *creds;
+ NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
+ NULL, domain, &creds);
+ if (!NT_STATUS_IS_OK(can_migrate)) {
+ DEBUG(0, ("Failed to fetch our own, local AD domain join "
+ "password for winbindd's internal use, both from "
+ "secrets.tdb and secrets.ldb: %s\n",
+ nt_errstr(can_migrate)));
+ return false;
+ }
+
+ /*
+ * NOTE: It is very unlikely we end up here if there is an
+ * oldpass, because a new password is created at
+ * classicupgrade, so this is not a concern.
+ */
+ ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
+ NULL /* oldpass */,
+ cli_credentials_get_domain(creds),
+ cli_credentials_get_realm(creds),
+ cli_credentials_get_salt_principal(creds),
+ 0, /* Supported enc types, unused */
+ &domain->sid,
+ cli_credentials_get_password_last_changed_time(creds),
+ cli_credentials_get_secure_channel_type(creds),
+ false /* do_delete: Do not delete */);
+ TALLOC_FREE(creds);
+ if (ok == false) {
+ DEBUG(0, ("Failed to write our our own, "
+ "local AD domain join password for "
+ "winbindd's internal use into secrets.tdb\n"));
+ return false;
+ }
+ return true;
+}
+
/* Look up global info for the winbind daemon */
bool init_domain_list(void)
{
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;
- domain = add_trusted_domain(get_global_sam_name(), lp_dnsdomain(),
- &cache_methods, get_global_sam_sid());
+ 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);
+ TALLOC_FREE(pdb_domain_info);
if (domain == NULL) {
- DEBUG(0, ("Failed to add our own, local AD domain to winbindd's internal list\n"));
+ DEBUG(0, ("Failed to add our own, local AD "
+ "domain to winbindd's internal list\n"));
return false;
}
&account_name,
&sec_chan_type);
if (!ok) {
- DEBUG(0, ("Failed to fetch our own, local AD domain join password for winbindd's internal use\n"));
- return false;
+ /*
+ * If get_trust_pw_hash() fails, then try and
+ * fetch the password from the more recent of
+ * secrets.{ldb,tdb} using the
+ * pdb_get_trust_credentials()
+ */
+ ok = migrate_secrets_tdb_to_ldb(domain);
+
+ if (ok == false) {
+ DEBUG(0, ("Failed to migrate our own, "
+ "local AD domain join password for "
+ "winbindd's internal use into "
+ "secrets.tdb\n"));
+ return false;
+ }
+ ok = get_trust_pw_hash(domain->name,
+ current_nt_hash.hash,
+ &account_name,
+ &sec_chan_type);
+ if (ok == false) {
+ DEBUG(0, ("Failed to find our our own, just "
+ "written local AD domain join "
+ "password for winbindd's internal "
+ "use in secrets.tdb\n"));
+ return false;
+ }
}
if (sec_chan_type == SEC_CHAN_RODC) {
domain->rodc = true;
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.
*/
void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
{
fstring tmp_user;
+ if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
+ can_assume = false;
+ }
+
fstrcpy(tmp_user, user);
(void)strlower_m(tmp_user);
{
char *tmp_user, *name;
+ if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
+ can_assume = false;
+ }
+
tmp_user = talloc_strdup(mem_ctx, user);
if (!strlower_m(tmp_user)) {
TALLOC_FREE(tmp_user);
return _client_list;
}
+/* Return list-tail of all connected clients */
+
+struct winbindd_cli_state *winbindd_client_list_tail(void)
+{
+ return DLIST_TAIL(_client_list);
+}
+
+/* Return previous (read:newer) client in list */
+
+struct winbindd_cli_state *
+winbindd_client_list_prev(struct winbindd_cli_state *cli)
+{
+ return DLIST_PREV(cli);
+}
+
/* Add a connection to the list */
void winbindd_add_client(struct winbindd_cli_state *cli)
{
+ cli->last_access = time(NULL);
DLIST_ADD(_client_list, cli);
_num_clients++;
}
_num_clients--;
}
+/* Move a client to head or list */
+
+void winbindd_promote_client(struct winbindd_cli_state *cli)
+{
+ cli->last_access = time(NULL);
+ DLIST_PROMOTE(_client_list, cli);
+}
+
/* Return number of open clients */
int winbindd_num_clients(void)
}
return True;
}
+
+bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
+ struct unixid **pxids, uint32_t *pnum_xids)
+{
+ const char *p;
+ struct unixid *xids = NULL;
+ uint32_t num_xids = 0;
+
+ p = xidstr;
+ if (p == NULL) {
+ return false;
+ }
+
+ while (p[0] != '\0') {
+ struct unixid *tmp;
+ struct unixid xid;
+ unsigned long long id;
+ char *endp;
+
+ switch (p[0]) {
+ case 'U':
+ xid = (struct unixid) { .type = ID_TYPE_UID };
+ break;
+ case 'G':
+ xid = (struct unixid) { .type = ID_TYPE_GID };
+ break;
+ default:
+ return false;
+ }
+
+ p += 1;
+
+ id = strtoull(p, &endp, 10);
+ if ((id == ULLONG_MAX) && (errno == ERANGE)) {
+ goto fail;
+ }
+ if (*endp != '\n') {
+ goto fail;
+ }
+ p = endp+1;
+
+ xid.id = id;
+ if ((unsigned long long)xid.id != id) {
+ goto fail;
+ }
+
+ tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
+ if (tmp == NULL) {
+ return 0;
+ }
+ xids = tmp;
+
+ xids[num_xids] = xid;
+ num_xids += 1;
+ }
+
+ *pxids = xids;
+ *pnum_xids = num_xids;
+ return true;
+
+fail:
+ TALLOC_FREE(xids);
+ return false;
+}