/*
SSSD
IPA Identity Backend Module for sub-domains
Authors:
Sumit Bose <sbose@redhat.com>
Copyright (C) 2012 Red Hat
it under the terms of the GNU General Public License as published by
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,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
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, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include "util/strtonum.h"
#include "providers/ldap/ldap_common.h"
#include "providers/ldap/sdap_async.h"
#include "providers/ldap/sdap_async_ad.h"
#include "providers/ipa/ipa_subdomains.h"
static struct tevent_req *
struct tevent_context *ev,
struct ipa_id_ctx *ipa_ctx,
struct sysdb_attrs *override_attrs,
struct dp_id_data *ar);
static errno_t
struct ipa_subdomain_account_state {
bool ipa_server_mode;
bool server_retry;
int entry_type;
const char *filter;
int filter_type;
char *object_sid;
int dp_error;
};
struct dp_id_data *ar);
struct tevent_context *ev,
struct ipa_id_ctx *ipa_ctx,
struct dp_id_data *ar)
{
int ret;
return NULL;
}
goto fail;
}
goto fail;
}
/* With views we cannot got directly to the look up the AD objects but
* have to check first if the request matches an override in the given
* view. But there are cases where this can be skipped and the AD object
* can be searched directly:
* - if no view is defined, i.e. the server does not supprt views yet
* - searches by SID: because we do not override the SID
* - if the responder does not send the EXTRA_INPUT_MAYBE_WITH_VIEW flags,
* because in this case the entry was found in the cache and the
* original value is used for the search (e.g. during cache updates) */
|| (!state->ipa_server_mode
EXTRA_INPUT_MAYBE_WITH_VIEW) != 0 )) {
"ipa_subdomain_account_get_original_step failed.\n");
goto fail;
}
return req;
}
if (!subreq) {
goto fail;
}
return req;
fail:
return req;
}
{
struct tevent_req);
struct ipa_subdomain_account_state);
int ret;
goto fail;
}
goto fail;
}
return;
fail:
return;
}
{
struct tevent_req);
struct ipa_subdomain_account_state);
int ret;
&state->override_attrs);
goto fail;
}
/* The override data was found with a lookup by certificate. for the
* default view the certificate will be added to
* SYSDB_USER_MAPPED_CERT so that cache lookups will find the same
* user. If no override data was found the mapping (if any) should be
* removed. For other view this is not needed because the override
* certificate is store in the cached override object in this case. */
"sysdb_new_attrs failed, ignored.\n");
} else {
"sysdb_attrs_add_base64_blob failed, ignored.\n");
}
}
}
&anchor);
goto fail;
}
OVERRIDE_ANCHOR_SID_PREFIX_LEN) == 0) {
&ar);
goto fail;
}
/* save the SID so that SYSDB_USER_MAPPED_CERT can be added
* later to the object */
"talloc_strdup failed, ignored.\n");
}
}
if (state->ipa_server_mode
== BE_REQ_INITGROUPS) {
"Switching back to BE_REQ_INITGROUPS.\n");
}
} else {
"Unsupported override anchor type [%s].\n", anchor);
goto fail;
}
} else {
/* remove certifcate (if any) if no matching override was found */
"some cached entries might contain "
"invalid mapping data.\n");
}
}
}
"ipa_subdomain_account_get_original_step failed.\n");
goto fail;
}
return;
fail:
return;
}
struct dp_id_data *ar)
{
struct ipa_subdomain_account_state);
if (state->ipa_server_mode) {
} else {
}
return ENOMEM;
}
return EOK;
}
{
struct tevent_req);
struct ipa_subdomain_account_state);
int ret;
if (state->ipa_server_mode) {
} else {
}
return;
}
state->object_sid);
"sysdb_set_entry_attr failed, ignoring.\n");
}
"mapped attribute, ignoring.\n");
} else {
"sysdb_search_object_by_sid failed, cannot add mapped "
"attribute, ignoring.\n");
}
}
return;
}
{
struct ipa_subdomain_account_state);
if (dp_error_out) {
}
return EOK;
}
struct ipa_get_subdom_acct {
int entry_type;
const char *filter;
int filter_type;
const char *extra_value;
bool use_pac;
int dp_error;
};
struct tevent_context *ev,
struct ipa_id_ctx *ipa_ctx,
struct sysdb_attrs *override_attrs,
struct dp_id_data *ar)
{
int ret;
goto fail;
}
goto fail;
}
switch (state->entry_type) {
case BE_REQ_USER:
case BE_REQ_GROUP:
case BE_REQ_BY_SECID:
case BE_REQ_BY_CERT:
case BE_REQ_USER_AND_GROUP:
break;
case BE_REQ_INITGROUPS:
}
break;
default:
}
if (!subreq) {
goto fail;
}
return req;
fail:
return req;
}
{
struct tevent_req);
struct ipa_get_subdom_acct);
int ret;
char *endptr;
char *shortname;
return;
}
/* With V1 of the extdom plugin a user lookup will resolve the full
* group membership of the user. */
} else {
/* This means the user entry is already in the cache and has
* the pac attached, we only have look up the missing groups
* and add the user to all groups. */
"ipa_get_subdom_acct_process_pac failed.\n");
return;
}
return;
}
/* Fall through if there is no PAC */
"by the IPA provider but are resolved " \
"by the responder directly from the " \
"cache.\n");
return;
}
}
return;
}
switch (state->filter_type) {
case BE_FILTER_NAME:
/* The extdom plugin expects the shortname and domain separately,
} else {
"Cannot parse internal name [%s]: %d\n",
return;
}
}
return;
}
break;
case BE_FILTER_IDNUM:
return;
}
break;
case BE_FILTER_SECID:
return;
}
break;
case BE_FILTER_CERT:
return;
}
} else {
"Lookup by certificate not supported by the server.\n");
return;
}
break;
default:
return;
}
if (!subreq) {
return;
}
return;
}
{
struct tevent_req);
struct ipa_get_subdom_acct);
int ret;
/* retry */
if (!subreq) {
return;
}
return;
}
return;
}
/* FIXME: do we need some special handling of ENOENT */
}
{
struct ipa_get_subdom_acct);
if (dp_error_out) {
}
return EOK;
}
/* IPA lookup for server mode. Directly to AD. */
struct ipa_get_ad_acct_state {
int dp_error;
char *object_sid;
};
struct sss_domain_info *dom);
static struct tevent_req *
struct tevent_context *ev,
struct ipa_id_ctx *ipa_ctx,
struct sysdb_attrs *override_attrs,
struct dp_id_data *ar)
{
/* This can only be a subdomain request, verify subdomain */
goto fail;
}
/* Let's see if this subdomain has a ad_id_ctx */
goto fail;
}
/* We read users and groups from GC. From groups, we may switch to
* using LDAP connection in the group request itself, but in order
* to resolve Universal group memberships, we also need the GC
* connection
*/
case BE_REQ_INITGROUPS:
case BE_REQ_BY_SECID:
case BE_REQ_GROUP:
break;
default:
break;
}
goto fail;
}
/* Now we already need ad_id_ctx in particular sdap_id_conn_ctx */
goto fail;
}
goto fail;
}
return req;
fail:
return req;
}
static struct ad_id_ctx *
struct sss_domain_info *dom)
{
}
}
static errno_t
{
const char *homedir;
goto done;
}
"Original home directory for user: %s is empty.\n", fqname);
goto done;
}
/* To be compatible with the old winbind based user lookups and IPA
* clients the user name in the home directory path will be lower-case. */
false, &homedir_ctx);
goto done;
}
goto done;
}
done:
return ret;
}
static errno_t
{
bool in_transaction = false;
goto done;
}
goto done;
}
goto done;
}
goto done;
}
in_transaction = true;
"Failed to update homedir information!\n");
goto done;
}
"Cannot commit sysdb transaction [%d]: %s.\n",
goto done;
}
in_transaction = false;
done:
if (in_transaction) {
}
}
return ret;
}
static errno_t
struct ldb_message *msg)
{
const char *fqname;
const char *original;
size_t c;
goto done;
}
for (c = 0; c < msg_el->num_values; c++) {
break;
}
}
if (c == msg_el->num_values) {
"User objectclass not found, object is not a user.\n");
goto done;
}
goto done;
}
if (uid == 0) {
fqname);
goto done;
}
}
&homedir);
"get_subdomain_homedir_of_user failed: [%d]: [%s]\n",
if (ret == ERR_HOMEDIR_IS_NULL) {
/* This is not fatal, fallback_homedir will be used. */
}
goto done;
}
"store_homedir_of_user failed: [%d]: [%s]\n",
goto done;
}
done:
return ret;
}
struct sss_domain_info *dom,
struct dp_id_data *ar,
struct ldb_message **_msg)
{
NULL };
&res);
"Failed to make request to our cache: [%d]: [%s]\n",
goto done;
}
goto done;
&res);
"Failed to make request to our cache: [%d]: [%s]\n",
goto done;
}
goto done;
&res);
"Failed to make request to our cache: [%d]: [%s]\n",
goto done;
}
"More than one result found in our cache\n");
goto done;
}
goto done;
errno = 0;
if (errno != 0) {
goto done;
}
case BE_REQ_GROUP:
break;
case BE_REQ_INITGROUPS:
case BE_REQ_USER:
case BE_REQ_USER_AND_GROUP:
== BE_REQ_USER_AND_GROUP) {
}
break;
default:
goto done;
}
case BE_REQ_GROUP:
break;
case BE_REQ_INITGROUPS:
case BE_REQ_USER:
case BE_REQ_USER_AND_GROUP:
if (ar->extra_value
} else {
== BE_REQ_USER_AND_GROUP) {
&msg);
}
}
break;
default:
goto done;
}
} else {
goto done;
}
"Failed to make request to our cache: [%d]: [%s]\n",
goto done;
}
done:
return ret;
}
static void
{
struct tevent_req);
struct ipa_get_ad_acct_state);
const char *sid;
if (ret == ERR_SUBDOM_INACTIVE) {
return;
return;
}
return;
goto fail;
}
"apply_subdomain_homedir failed: [%d]: [%s].\n",
goto fail;
}
goto fail;
}
goto fail;
}
goto fail;
}
ar);
goto fail;
}
} else {
"ipa_get_ad_apply_override_step failed.\n");
goto fail;
}
}
return;
fail:
return;
}
static void
{
struct tevent_req);
struct ipa_get_ad_acct_state);
&state->override_attrs);
return;
}
goto fail;
}
return;
fail:
return;
}
{
struct ipa_get_ad_acct_state);
"Object not found, ending request\n");
return EOK;
return ret;
}
}
/* Resolve ghost members */
ghosts);
return ENOMEM;
}
return EAGAIN;
}
return EOK;
}
{
struct tevent_req);
int ret;
ret);
return;
}
return;
}
{
struct ipa_get_ad_acct_state);
const char *obj_name;
int entry_type;
/* We are in ipa-server-mode, so the view is the default view by
* definition. */
return ret;
}
}
if (entry_type != BE_REQ_INITGROUPS
&& entry_type != BE_REQ_USER
&& entry_type != BE_REQ_BY_SECID
&& entry_type != BE_REQ_GROUP) {
return EOK;
}
/* expand ghost members, if any, to get group members with overrides
* right. */
if (entry_type == BE_REQ_GROUP) {
return EOK;
return EOK;
} else {
return ret;
}
}
/* Replace ID with name in search filter */
|| (entry_type == BE_REQ_INITGROUPS
|| entry_type == BE_REQ_BY_SECID) {
"Object not found, ending request\n");
return EOK;
return ret;
}
}
NULL);
return EINVAL;
}
return ENOMEM;
}
}
/* Lookup all groups the user is a member of which do not have ORIGINALAD
* attributes set, i.e. where overrides might not have been applied. */
return ret;
}
return ENOMEM;
}
return EOK;
}
return ret;
}
return EOK;
}
{
struct tevent_req);
"IPA resolve user groups overrides failed [%d].\n", ret);
return;
}
return;
}
return;
}
{
struct ipa_get_ad_acct_state);
/* For initgroups request we have to check IPA group memberships of AD
* users. This has to be done for other user-request as well to make sure
* IPA related attributes are not overwritten. */
return ENOMEM;
}
return EOK;
}
static void
{
struct tevent_req);
struct ipa_get_ad_acct_state);
ret);
return;
}
}
static errno_t
{
struct ipa_get_ad_acct_state);
if (dp_error_out) {
}
return EOK;
}
struct ipa_srv_ad_acct_state {
bool retry;
int dp_error;
};
static struct tevent_req *
struct tevent_context *ev,
struct ipa_id_ctx *ipa_ctx,
struct sysdb_attrs *override_attrs,
struct dp_id_data *ar)
{
return NULL;
}
goto fail;
}
goto fail;
}
return req;
fail:
return req;
}
{
struct ipa_srv_ad_acct_state);
return ENOMEM;
}
return EOK;
}
{
struct tevent_req);
struct ipa_srv_ad_acct_state);
"Subdomain lookup failed, will try to reset subdomain.\n");
goto fail;
}
return;
goto fail;
}
return;
fail:
}
{
struct tevent_req);
struct ipa_srv_ad_acct_state);
}
}
}
static errno_t
{
struct ipa_srv_ad_acct_state);
if (dp_error_out) {
}
return EOK;
}