ad_subdomains.c revision c02b8482375837b57cb618ed56d4bede0e006d9d
/*
SSSD
AD Subdomains Module
Authors:
Sumit Bose <sbose@redhat.com>
Copyright (C) 2013 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 "providers/ldap/sdap_async.h"
#include "providers/ad/ad_subdomains.h"
#include "providers/ad/ad_domain_info.h"
#include "providers/ad/ad_common.h"
#include "providers/ldap/sdap_idmap.h"
#include "util/util_sss_idmap.h"
#include <ctype.h>
#include <ndr.h>
/* Attributes of AD trusted domains */
#define AD_AT_FLATNAME "flatName"
#define AD_AT_SID "securityIdentifier"
#define AD_AT_TRUST_TYPE "trustType"
#define AD_AT_TRUST_PARTNER "trustPartner"
#define AD_AT_TRUST_ATTRS "trustAttributes"
/* trustType=2 denotes uplevel (NT5 and later) trusted domains. See
* for example.
*
* The absence of msDS-TrustForestTrustInfo attribute denotes a domain from
* the same forest. See http://msdn.microsoft.com/en-us/library/cc223786.aspx
* for more information.
*/
#define SLAVE_DOMAIN_FILTER_BASE "(objectclass=trustedDomain)(trustType=2)(!(msDS-TrustForestTrustInfo=*))"
/* do not refresh more often than every 5 seconds for now */
#define AD_SUBDOMAIN_REFRESH_LIMIT 5
struct ad_subdomains_ctx {
struct sdap_id_ctx *sdap_id_ctx;
struct sdap_domain *sdom;
struct sdap_id_conn_ctx *ldap_ctx;
struct sss_idmap_ctx *idmap_ctx;
char *domain_name;
struct tevent_timer *timer_event;
};
struct ad_subdomains_req_ctx {
struct ad_subdomains_ctx *sd_ctx;
struct sdap_id_op *sdap_op;
char *current_filter;
struct ad_id_ctx *root_id_ctx;
struct sdap_id_op *root_op;
struct sysdb_attrs *root_domain_attrs;
struct sss_domain_info *root_domain;
struct sysdb_attrs **reply;
char *master_sid;
char *flat_name;
char *site;
char *forest;
};
static errno_t
struct sss_domain_info *subdom,
struct ad_id_ctx **_subdom_id_ctx)
{
struct ad_options *ad_options;
const char *gc_service_name;
struct ad_srv_plugin_ctx *srv_ctx;
char *ad_domain;
char *ad_site_override;
struct sdap_domain *sdom;
const char *realm;
const char *hostname;
const char *keytab;
return EINVAL;
}
if (ad_options == NULL) {
return ENOMEM;
}
if (gc_service_name == NULL) {
return ENOMEM;
}
return ret;
}
return ENOMEM;
}
/* use AD plugin */
return ENOMEM;
}
return ret;
}
return EFAULT;
}
/* Set up the ID mapping object */
return EOK;
}
static errno_t
struct sss_domain_info *parent)
{
int ret;
struct sdap_domain *sditer;
struct ad_id_ctx *subdom_id_ctx;
return ret;
}
} else {
}
}
}
return EOK;
}
struct sysdb_attrs *attrs,
bool *_enumerates)
{
const char *name;
return ret;
}
return EOK;
}
static errno_t
struct sss_domain_info *domain,
struct sysdb_attrs *subdom_attrs,
bool enumerate)
{
const char *name;
char *realm;
const char *flat;
enum idmap_error_code err;
struct ldb_message_element *el;
bool mpg;
goto done;
}
&trust_type);
goto done;
}
goto done;
}
if (!realm) {
goto done;
}
if (ret) {
name);
goto done;
}
goto done;
}
&sid_str);
if (err != IDMAP_SUCCESS) {
goto done;
}
name,
sid_str);
goto done;
}
done:
return ret;
}
int count, bool root_domain,
struct sysdb_attrs **reply,
bool *changes)
{
struct sdap_domain *sdom;
const char *value;
int c, h;
int ret;
bool enumerate;
h = 0;
if (root_domain) {
&root_name);
goto done;
}
}
/* check existing subdomains */
/* If we are handling root domain, skip all the other domains. We don't
* want to accidentally remove non-root domains
*/
continue;
}
for (c = 0; c < count; c++) {
if (handled[c]) {
continue;
}
goto done;
}
break;
}
}
if (c >= count) {
/* ok this subdomain does not exist anymore, let's clean up */
goto done;
}
continue;
}
/* Remove the subdomain from the list of LDAP domains */
/* terminate all requests for this subdomain so we can free it */
} else {
/* ok let's try to update it */
goto done;
}
if (ret) {
/* Nothing we can do about the error. Let's at least try
* to reuse the existing domains
*/
"will try to use cached subdomain\n");
}
handled[c] = true;
h++;
}
}
if (count == h) {
/* all domains were already accounted for and have been updated */
*changes = false;
goto done;
}
/* if we get here it means we have changes to the subdomains list */
*changes = true;
for (c = 0; c < count; c++) {
if (handled[c]) {
continue;
}
/* Nothing we can do about the error. Let's at least try
* to reuse the existing domains.
*/
goto done;
}
if (ret) {
"will try to use cached subdomain\n");
}
}
done:
ctx->last_refreshed = 0;
} else {
}
return ret;
}
{
/* Just continue */
}
return ret;
}
/* Just continue */
}
return ret;
}
return EOK;
}
{
struct tevent_req *req;
int dp_error = DP_ERR_FATAL;
int ret;
goto done;
}
req_ctx->root_base_iter = 0;
req_ctx->reply_count = 0;
goto done;
}
goto done;
}
return;
done:
}
}
{
int ret;
int dp_error = DP_ERR_FATAL;
struct ad_subdomains_req_ctx *ctx;
if (ret) {
if (dp_error == DP_ERR_OFFLINE) {
"No AD server is available, cannot get the "
"subdomain list while offline\n");
} else {
"Failed to connect to AD server: [%d](%s)\n",
}
goto fail;
}
goto fail;
}
return;
fail:
}
{
struct ad_subdomains_req_ctx *ctx;
const char *realm;
goto done;
}
goto done;
}
goto done;
}
"SSSD needs to look up the forest root domain\n");
} else {
"Connected to forest root, looking up child domains..\n");
}
return;
goto done;
}
done:
}
{
struct tevent_req *req;
struct sdap_search_base *base;
struct sdap_id_ctx *sdap_id_ctx;
char *filter;
return EOK;
}
return ENOMEM;
}
NULL, 0,
false);
return ENOMEM;
}
return EAGAIN;
}
{
int ret;
struct ad_subdomains_req_ctx *ctx;
int dp_error = DP_ERR_FATAL;
bool has_changes = false;
goto fail;
}
if (reply_count == 0) {
/* If no root domain was found in the default search base, try the
* next one, if available
*/
ctx->root_base_iter++;
return;
}
goto fail;
} else if (reply_count > 1) {
"Multiple results for root domain search, "
"domain list might be incomplete!\n");
return;
}
goto fail;
}
/* Exactly one result, good. */
/* We won't use the operation to the local LDAP anymore, but
* read from the forest root
*/
if (dp_error == DP_ERR_OFFLINE) {
"No AD server is available, cannot get the "
"subdomain list while offline\n");
} else {
"Failed to search the AD server: [%d](%s)\n",
}
goto fail;
}
goto fail;
}
if (has_changes) {
goto fail;
}
}
goto fail;
}
goto fail;
}
goto fail;
}
goto fail;
}
return;
fail:
}
}
{
const char *name;
struct sss_domain_info *root;
return NULL;
}
/* With a subsequent run, the root should already be known */
name, false);
return root;
}
{
struct sdap_domain *sdom;
struct ad_id_ctx *root_id_ctx;
ctx->root_domain);
return NULL;
}
&root_id_ctx);
return NULL;
}
} else {
}
return root_id_ctx;
}
{
int ret;
int dp_error = DP_ERR_FATAL;
struct ad_subdomains_req_ctx *ctx;
if (ret) {
"Failed to connect to AD server: [%d](%s)\n",
goto fail;
}
return;
goto fail;
}
fail:
}
{
struct tevent_req *req;
struct sdap_search_base *base;
return EOK;
}
NULL, 0,
false);
return ENOMEM;
}
return EAGAIN;
}
struct sss_domain_info *domain,
struct sysdb_attrs *root,
struct sysdb_attrs ***_sd_out)
{
struct sysdb_attrs **sd_out;
const char *sd_name;
/* We are connected directly to the root domain. The 'sd'
* list is complete and we can just use it
*/
return EOK;
}
/* If we searched for root separately, we must:
* a) treat the root domain as a subdomain
* b) filter the subdomain we are connected to from the subdomain
* list, from our point of view, it's the master domain
*/
return ENOMEM;
}
sdi = 0;
for (i = 0; i < nsd; i++) {
goto fail;
}
"Not including primary domain %s in the subdomain list\n",
continue;
}
sdi++;
}
/* Now include the root */
return EOK;
fail:
return ret;
}
{
int ret;
struct ad_subdomains_req_ctx *ctx;
int dp_error = DP_ERR_FATAL;
bool refresh_has_changes = false;
struct sysdb_attrs **subdoms;
goto done;
}
if (reply_count) {
goto done;
}
reply_count * sizeof(struct sysdb_attrs *));
}
/* Search in progress */
return;
}
if (dp_error == DP_ERR_OFFLINE) {
"No AD server is available, cannot get the "
"subdomain list while offline\n");
} else {
"Failed to search the AD server: [%d](%s)\n",
}
return;
}
/* Based on whether we are connected to the forest root or not, we might
* need to exclude the subdomain we are connected to from the list of
* subdomains
*/
return;
}
/* Got all the subdomains, let's process them */
goto done;
}
if (refresh_has_changes) {
goto done;
}
}
done:
}
}
static void ad_subdom_online_cb(void *pvt);
struct tevent_timer *te,
struct timeval current_time,
void *pvt)
{
}
const char *errstr)
{
}
static void ad_subdom_online_cb(void *pvt)
{
struct ad_subdomains_ctx *ctx;
if (!ctx) {
return;
}
return;
}
if (!ctx->timer_event) {
}
}
static void ad_subdom_offline_cb(void *pvt)
{
struct ad_subdomains_ctx *ctx;
if (ctx) {
}
}
{
struct ad_subdomains_ctx *ctx;
struct ad_subdomains_ctx);
if (!ctx) {
return;
}
return;
}
}
struct bet_ops ad_subdomains_ops = {
};
const char *ad_domain,
void **pvt_data)
{
struct ad_subdomains_ctx *ctx;
int ret;
enum idmap_error_code err;
return ENOMEM;
}
return ENOMEM;
}
*ops = &ad_subdomains_ops;
}
}
if (err != IDMAP_SUCCESS) {
return EFAULT;
}
"Users from trusted domains might not be resolved correctly\n");
/* Ignore this error and try to discover the subdomains later */
}
return EOK;
}