[SSSD] AD: read flat name and SID of the AD domain

Sumit Bose sbose at redhat.com
Tue May 7 09:05:28 UTC 2013


On Tue, May 07, 2013 at 11:03:38AM +0200, Sumit Bose wrote:
> On Mon, May 06, 2013 at 10:05:41PM +0200, Jakub Hrozek wrote:
> > On Mon, May 06, 2013 at 06:14:56PM +0200, Sumit Bose wrote:
> > > Hi,
> > > 
> > > this patch reads the flat name and the SID from AD and stores then to
> > > the cache. It fixes https://fedorahosted.org/sssd/ticket/1468 directly
> > > and the flat name is needed e.g. for
> > > https://fedorahosted.org/sssd/ticket/1648 and the SID e.g. for
> > > https://fedorahosted.org/sssd/ticket/1558 .
> > > 
> > > bye,
> > > Sumit
> > 
> > Hi,
> > 
> > mostly looks good to me and seems to work fine. I just have a couple of
> > suggestions and a question:
> > 
> > I think the AD subdomains provider should be present in the configAPI,
> > mostly for completeness' sake.
> > 
> > Now that we can match the domain and subdomain in the re_expression in
> > the AD provider, too think we should document the fact.
> > 
> > See attached mini-patche for these two suggestions, feel free to squash
> > them in if you agree.
> 
> Thank you for the review, I squashed your changes in as you suggested.
> 
> > 
> > And one question -- do you think it would make sense to default to the
> > part of ad_domain until the first dot if the discovery fails? I would
> > rather not use the special option I posted earlier but maybe some kind
> > of fallback would be nice.
> 
> I think we should not try to guess the name here. Since the name is
> stored in the cache it must be resolved only once successfully. I guess
> the most common case when he discovery fails during the initial startup
> is when the connection fails, e.g. SSSD is offline. But here chances are
> that other lookups will fail, too, and having a short name won't help
> much.
> 
> bye,
> Sumit

and now with patch

bye,
Sumit
-------------- next part --------------
>From 5983158cccf4dba875856ad9e8f2a68bb992ca2a Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Thu, 2 May 2013 20:28:30 +0200
Subject: [PATCH] AD: read flat name and SID of the AD domain

For various features either the flat/short/NetBIOS domain name or the
domain SID is needed. Since the responders already try to do a subdomain
lookup when and known domain name is encountered I added a subdomain
lookup to the AD provider which currently only reads the SID from the
base DN and the NetBIOS name from a reply of a LDAP ping. The results
are written to the cache to have them available even if SSSD is started
in offline mode. Looking up trusted domains can be added later.

Since all the needed responder code is already available from the
corresponding work for the IPA provider this patch fixes

https://fedorahosted.org/sssd/ticket/1468
---
 Makefile.am                            |    2 +
 src/config/etc/sssd.api.d/sssd-ad.conf |    2 +
 src/man/sssd-ad.5.xml                  |    4 +
 src/man/sssd.conf.5.xml                |    4 +
 src/providers/ad/ad_init.c             |   31 ++
 src/providers/ad/ad_subdomains.c       |  522 ++++++++++++++++++++++++++++++++
 src/providers/ad/ad_subdomains.h       |   37 +++
 7 files changed, 602 insertions(+), 0 deletions(-)
 create mode 100644 src/providers/ad/ad_subdomains.c
 create mode 100644 src/providers/ad/ad_subdomains.h

diff --git a/Makefile.am b/Makefile.am
index fe3d183..ecd7183 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1643,6 +1643,8 @@ libsss_ad_la_SOURCES = \
     src/providers/ad/ad_access.h \
     src/providers/ad/ad_opts.h \
     src/providers/ad/ad_srv.c \
+    src/providers/ad/ad_subdomains.c \
+    src/providers/ad/ad_subdomains.h \
     src/util/find_uid.c \
     src/util/user_info_msg.c \
     src/util/sss_krb5.c \
diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
index b4b1d0b..3be25e8 100644
--- a/src/config/etc/sssd.api.d/sssd-ad.conf
+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
@@ -126,3 +126,5 @@ krb5_use_enterprise_principal = bool, None, false
 [provider/ad/chpass]
 krb5_kpasswd = str, None, false
 krb5_backup_kpasswd = str, None, false
+
+[provider/ad/subdomains]
diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
index c196077..4dcd552 100644
--- a/src/man/sssd-ad.5.xml
+++ b/src/man/sssd-ad.5.xml
@@ -95,6 +95,10 @@ ldap_id_mapping = False
                             specified as the lower-case version of the long
                             version of the Active Directory domain.
                         </para>
+                        <para>
+                            The short domain name (also known as the NetBIOS
+                            or the flat name) is autodetected by the SSSD.
+                        </para>
                     </listitem>
                 </varlistentry>
 
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 04c6999..99337fb 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -1481,6 +1481,10 @@ override_homedir = /home/%u
                             Regular expression for this domain that describes
                             how to parse the string containing user name and
                             domain into these components.
+                            The "domain" can match either the SSSD
+                            configuration domain name, or, in the case
+                            of IPA trust subdomains and Active Directory
+                            domains, the flat (NetBIOS) name of the domain.
                         </para>
                         <para>
                             Default for the AD and IPA provider:
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index 2f5a5da..f90df2a 100644
--- a/src/providers/ad/ad_init.c
+++ b/src/providers/ad/ad_init.c
@@ -37,6 +37,7 @@
 #include "providers/ad/ad_id.h"
 #include "providers/ad/ad_srv.h"
 #include "providers/dp_dyndns.h"
+#include "providers/ad/ad_subdomains.h"
 
 struct ad_options *ad_options = NULL;
 
@@ -361,3 +362,33 @@ ad_shutdown(struct be_req *req)
     /* TODO: Clean up any internal data */
     sdap_handler_done(req, DP_ERR_OK, EOK, NULL);
 }
+
+int sssm_ad_subdomains_init(struct be_ctx *bectx,
+                            struct bet_ops **ops,
+                            void **pvt_data)
+{
+    int ret;
+    struct ad_id_ctx *id_ctx;
+    const char *ad_domain;
+
+    ret = sssm_ad_id_init(bectx, ops, (void **) &id_ctx);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("sssm_ad_id_init failed.\n"));
+        return ret;
+    }
+
+    if (ad_options == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Global AD options not available.\n"));
+        return EINVAL;
+    }
+
+    ad_domain = dp_opt_get_string(ad_options->basic, AD_DOMAIN);
+
+    ret = ad_subdom_init(bectx, id_ctx, ad_domain, ops, pvt_data);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("ad_subdom_init failed.\n"));
+        return ret;
+    }
+
+    return EOK;
+}
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
new file mode 100644
index 0000000..1da343f
--- /dev/null
+++ b/src/providers/ad/ad_subdomains.c
@@ -0,0 +1,522 @@
+/*
+    SSSD
+
+    AD Subdomains Module
+
+    Authors:
+        Sumit Bose <sbose at redhat.com>
+
+    Copyright (C) 2013 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    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 <ctype.h>
+#include <ndr.h>
+#include <ndr/ndr_nbt.h>
+
+#define AD_AT_OBJECT_SID "objectSID"
+#define AD_AT_DNS_DOMAIN "DnsDomain"
+#define AD_AT_NT_VERSION "NtVer"
+#define AD_AT_NETLOGON "netlogon"
+
+#define MASTER_DOMAIN_SID_FILTER "objectclass=domain"
+
+/* do not refresh more often than every 5 seconds for now */
+#define AD_SUBDOMAIN_REFRESH_LIMIT 5
+
+/* refresh automatically every 4 hours */
+#define AD_SUBDOMAIN_REFRESH_PERIOD (3600 * 4)
+
+struct ad_subdomains_ctx {
+    struct be_ctx *be_ctx;
+    struct sdap_id_ctx *sdap_id_ctx;
+    struct sss_idmap_ctx *idmap_ctx;
+    char *domain_name;
+
+    time_t last_refreshed;
+    struct tevent_timer *timer_event;
+};
+
+struct ad_subdomains_req_ctx {
+    struct be_req *be_req;
+    struct ad_subdomains_ctx *sd_ctx;
+    struct sdap_id_op *sdap_op;
+
+    char *current_filter;
+    size_t base_iter;
+
+    size_t reply_count;
+    struct sysdb_attrs **reply;
+
+    char *master_sid;
+    char *flat_name;
+};
+
+static void ad_subdomains_get_conn_done(struct tevent_req *req);
+static errno_t ad_subdomains_get_master_sid(struct ad_subdomains_req_ctx *ctx);
+static void ad_subdomains_get_master_sid_done(struct tevent_req *req);
+static void ad_subdomains_get_netlogon_done(struct tevent_req *req);
+
+static void ad_subdomains_retrieve(struct ad_subdomains_ctx *ctx,
+                                   struct be_req *be_req)
+{
+    struct ad_subdomains_req_ctx *req_ctx = NULL;
+    struct tevent_req *req;
+    int dp_error = DP_ERR_FATAL;
+    int ret;
+
+    req_ctx = talloc(be_req, struct ad_subdomains_req_ctx);
+    if (req_ctx == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    req_ctx->be_req = be_req;
+    req_ctx->sd_ctx = ctx;
+    req_ctx->current_filter = NULL;
+    req_ctx->base_iter = 0;
+    req_ctx->reply_count = 0;
+    req_ctx->reply = NULL;
+
+    req_ctx->sdap_op = sdap_id_op_create(req_ctx,
+                                         ctx->sdap_id_ctx->conn_cache);
+    if (req_ctx->sdap_op == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+
+    req = sdap_id_op_connect_send(req_ctx->sdap_op, req_ctx, &ret);
+    if (req == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_connect_send failed: %d(%s).\n",
+                                  ret, strerror(ret)));
+        goto done;
+    }
+
+    tevent_req_set_callback(req, ad_subdomains_get_conn_done, req_ctx);
+
+    return;
+
+done:
+    talloc_free(req_ctx);
+    if (ret == EOK) {
+        dp_error = DP_ERR_OK;
+    }
+    be_req_terminate(be_req, dp_error, ret, NULL);
+}
+
+static void ad_subdomains_get_conn_done(struct tevent_req *req)
+{
+    int ret;
+    int dp_error = DP_ERR_FATAL;
+    struct ad_subdomains_req_ctx *ctx;
+
+    ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
+
+    ret = sdap_id_op_connect_recv(req, &dp_error);
+    talloc_zfree(req);
+    if (ret) {
+        if (dp_error == DP_ERR_OFFLINE) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  ("No AD server is available, cannot get the "
+                   "subdomain list while offline\n"));
+        } else {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  ("Failed to connect to AD server: [%d](%s)\n",
+                   ret, strerror(ret)));
+        }
+
+        goto fail;
+    }
+
+    ret = ad_subdomains_get_master_sid(ctx);
+    if (ret == EAGAIN) {
+        return;
+    } else if (ret != EOK) {
+        goto fail;
+    }
+
+    DEBUG(SSSDBG_OP_FAILURE, ("No search base available.\n"));
+    ret = EINVAL;
+
+fail:
+    be_req_terminate(ctx->be_req, dp_error, ret, NULL);
+}
+
+static errno_t ad_subdomains_get_master_sid(struct ad_subdomains_req_ctx *ctx)
+{
+    struct tevent_req *req;
+    struct sdap_search_base *base;
+    const char *master_sid_attrs[] = {AD_AT_OBJECT_SID, NULL};
+
+
+    base = ctx->sd_ctx->sdap_id_ctx->opts->search_bases[ctx->base_iter];
+    if (base == NULL) {
+        return EOK;
+    }
+
+    req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
+                           ctx->sd_ctx->sdap_id_ctx->opts,
+                           sdap_id_op_handle(ctx->sdap_op),
+                           base->basedn, LDAP_SCOPE_BASE,
+                           MASTER_DOMAIN_SID_FILTER, master_sid_attrs,
+                           NULL, 0,
+                           dp_opt_get_int(ctx->sd_ctx->sdap_id_ctx->opts->basic,
+                                          SDAP_SEARCH_TIMEOUT),
+                           false);
+
+    if (req == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_get_generic_send failed.\n"));
+        return ENOMEM;
+    }
+
+    tevent_req_set_callback(req, ad_subdomains_get_master_sid_done, ctx);
+
+    return EAGAIN;
+}
+
+static void ad_subdomains_get_master_sid_done(struct tevent_req *req)
+{
+    int ret;
+    size_t reply_count;
+    struct sysdb_attrs **reply = NULL;
+    struct ad_subdomains_req_ctx *ctx;
+    struct ldb_message_element *el;
+    char *sid_str;
+    enum idmap_error_code err;
+    static const char *attrs[] = {AD_AT_NETLOGON, NULL};
+    char *filter;
+    char *ntver;
+
+    ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
+
+    ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
+    talloc_zfree(req);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_get_generic_send request failed.\n"));
+        goto done;
+    }
+
+    if (reply_count == 0) {
+        ctx->base_iter++;
+        ret = ad_subdomains_get_master_sid(ctx);
+        if (ret == EAGAIN) {
+            return;
+        } else if (ret != EOK) {
+            goto done;
+        }
+    } else if (reply_count == 1) {
+        ret = sysdb_attrs_get_el(reply[0], AD_AT_OBJECT_SID, &el);
+        if (ret != EOK || el->num_values != 1) {
+            DEBUG(SSSDBG_OP_FAILURE, ("sdap_attrs_get_el failed.\n"));
+            goto done;
+        }
+
+        err = sss_idmap_bin_sid_to_sid(ctx->sd_ctx->idmap_ctx,
+                                       el->values[0].data,
+                                       el->values[0].length,
+                                       &sid_str);
+        if (err != IDMAP_SUCCESS) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  ("Could not convert SID: [%s].\n", idmap_error_string(err)));
+            ret = EFAULT;
+            goto done;
+        }
+
+        ctx->master_sid = talloc_steal(ctx, sid_str);
+    } else {
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("More than one result for domain SID found.\n"));
+        ret = EINVAL;
+        goto done;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, ("Found SID [%s].\n", ctx->master_sid));
+
+    ntver = sss_ldap_encode_ndr_uint32(ctx, NETLOGON_NT_VERSION_5EX |
+                                       NETLOGON_NT_VERSION_WITH_CLOSEST_SITE);
+    if (ntver == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("sss_ldap_encode_ndr_uint32 failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+
+    filter = talloc_asprintf(ctx, "(&(%s=%s)(%s=%s))",
+                             AD_AT_DNS_DOMAIN, ctx->sd_ctx->domain_name,
+                             AD_AT_NT_VERSION, ntver);
+    if (filter == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("talloc_asprintf failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+
+    req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
+                           ctx->sd_ctx->sdap_id_ctx->opts,
+                           sdap_id_op_handle(ctx->sdap_op),
+                           "", LDAP_SCOPE_BASE, filter, attrs, NULL, 0,
+                           dp_opt_get_int(ctx->sd_ctx->sdap_id_ctx->opts->basic,
+                                          SDAP_SEARCH_TIMEOUT),
+                           false);
+    if (req == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_get_generic_send failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+
+    tevent_req_set_callback(req, ad_subdomains_get_netlogon_done, ctx);
+    return;
+
+done:
+    be_req_terminate(ctx->be_req, DP_ERR_FATAL, ret, NULL);
+}
+
+static void ad_subdomains_get_netlogon_done(struct tevent_req *req)
+{
+    int ret;
+    size_t reply_count;
+    struct sysdb_attrs **reply = NULL;
+    struct ad_subdomains_req_ctx *ctx;
+    struct ldb_message_element *el;
+    DATA_BLOB blob;
+    enum ndr_err_code ndr_err;
+    struct ndr_pull *ndr_pull = NULL;
+    struct netlogon_samlogon_response response;
+
+    ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
+
+    ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
+    talloc_zfree(req);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_get_generic_send request failed.\n"));
+        goto done;
+    }
+
+    if (reply_count == 0) {
+        DEBUG(SSSDBG_TRACE_FUNC, ("No netlogon data available.\n"));
+    } else if (reply_count > 1) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("More than one netlogon info returned.\n"));
+        ret = EINVAL;
+        goto done;
+    }
+
+    ret = sysdb_attrs_get_el(reply[0], AD_AT_NETLOGON, &el);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_el() failed\n"));
+        goto done;
+    }
+
+    if (el->num_values == 0) {
+        DEBUG(SSSDBG_OP_FAILURE, ("netlogon has no value\n"));
+        ret = ENOENT;
+        goto done;
+    } else if (el->num_values > 1) {
+        DEBUG(SSSDBG_OP_FAILURE, ("More than one netlogon value?\n"));
+        ret = EIO;
+        goto done;
+    }
+
+    blob.data =  el->values[0].data;
+    blob.length = el->values[0].length;
+
+    ndr_pull = ndr_pull_init_blob(&blob, ctx);
+    if (ndr_pull == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("ndr_pull_init_blob() failed.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ndr_err = ndr_pull_netlogon_samlogon_response(ndr_pull, NDR_SCALARS,
+                                                  &response);
+    if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+        DEBUG(SSSDBG_OP_FAILURE, ("ndr_pull_netlogon_samlogon_response() "
+                                  "failed [%d]\n", ndr_err));
+        ret = EBADMSG;
+        goto done;
+    }
+
+    if (!(response.ntver & NETLOGON_NT_VERSION_5EX)) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Wrong version returned [%x]\n",
+                                  response.ntver));
+        ret = EBADMSG;
+        goto done;
+    }
+
+    if (response.data.nt5_ex.domain_name != NULL &&
+        *response.data.nt5_ex.domain_name != '\0') {
+        ctx->flat_name = talloc_strdup(ctx, response.data.nt5_ex.domain_name);
+        if (ctx->flat_name == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, ("Found flat name [%s].\n", ctx->flat_name));
+
+    ret = sysdb_master_domain_add_info(ctx->sd_ctx->be_ctx->domain,
+                                       NULL, ctx->flat_name, ctx->master_sid);
+
+    ret = EOK;
+
+done:
+
+    if (ret == EOK) {
+        ctx->sd_ctx->last_refreshed = time(NULL);
+    }
+    be_req_terminate(ctx->be_req, DP_ERR_FATAL, ret, NULL);
+}
+
+static void ad_subdom_online_cb(void *pvt);
+
+static void ad_subdom_timer_refresh(struct tevent_context *ev,
+                                     struct tevent_timer *te,
+                                     struct timeval current_time,
+                                     void *pvt)
+{
+    ad_subdom_online_cb(pvt);
+}
+
+static void ad_subdom_be_req_callback(struct be_req *be_req,
+                                       int dp_err, int dp_ret,
+                                       const char *errstr)
+{
+    talloc_free(be_req);
+}
+
+static void ad_subdom_online_cb(void *pvt)
+{
+    struct ad_subdomains_ctx *ctx;
+    struct be_req *be_req;
+    struct timeval tv;
+
+    ctx = talloc_get_type(pvt, struct ad_subdomains_ctx);
+    if (!ctx) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Bad private pointer\n"));
+        return;
+    }
+
+    be_req = be_req_create(ctx, NULL, ctx->be_ctx,
+                           ad_subdom_be_req_callback, NULL);
+    if (be_req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("be_req_create() failed.\n"));
+        return;
+    }
+
+    ad_subdomains_retrieve(ctx, be_req);
+
+    tv = tevent_timeval_current_ofs(AD_SUBDOMAIN_REFRESH_PERIOD, 0);
+    ctx->timer_event = tevent_add_timer(ctx->be_ctx->ev, ctx, tv,
+                                        ad_subdom_timer_refresh, ctx);
+    if (!ctx->timer_event) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add subdom timer event\n"));
+    }
+}
+
+static void ad_subdom_offline_cb(void *pvt)
+{
+    struct ad_subdomains_ctx *ctx;
+
+    ctx = talloc_get_type(pvt, struct ad_subdomains_ctx);
+
+    if (ctx) {
+        talloc_zfree(ctx->timer_event);
+    }
+}
+
+void ad_subdomains_handler(struct be_req *be_req)
+{
+    struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
+    struct ad_subdomains_ctx *ctx;
+    time_t now;
+
+    ctx = talloc_get_type(be_ctx->bet_info[BET_SUBDOMAINS].pvt_bet_data,
+                          struct ad_subdomains_ctx);
+    if (!ctx) {
+        be_req_terminate(be_req, DP_ERR_FATAL, EINVAL, NULL);
+        return;
+    }
+
+    now = time(NULL);
+
+    if (ctx->last_refreshed > now - AD_SUBDOMAIN_REFRESH_LIMIT) {
+        be_req_terminate(be_req, DP_ERR_OK, EOK, NULL);
+        return;
+    }
+
+    ad_subdomains_retrieve(ctx, be_req);
+}
+
+struct bet_ops ad_subdomains_ops = {
+    .handler = ad_subdomains_handler,
+    .finalize = NULL
+};
+
+static void *idmap_talloc(size_t size, void *pvt)
+{
+    return talloc_size(pvt, size);
+}
+
+static void idmap_free(void *ptr, void *pvt)
+{
+    talloc_free(ptr);
+}
+
+int ad_subdom_init(struct be_ctx *be_ctx,
+                   struct ad_id_ctx *id_ctx,
+                   const char *ad_domain,
+                   struct bet_ops **ops,
+                   void **pvt_data)
+{
+    struct ad_subdomains_ctx *ctx;
+    int ret;
+    enum idmap_error_code err;
+
+    ctx = talloc_zero(id_ctx, struct ad_subdomains_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_zero failed.\n"));
+        return ENOMEM;
+    }
+
+    ctx->be_ctx = be_ctx;
+    ctx->sdap_id_ctx = id_ctx->sdap_id_ctx;
+    ctx->domain_name = talloc_strdup(ctx, ad_domain);
+    if (ctx->domain_name == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
+        return ENOMEM;
+    }
+    *ops = &ad_subdomains_ops;
+    *pvt_data = ctx;
+
+    ret = be_add_online_cb(ctx, be_ctx, ad_subdom_online_cb, ctx, NULL);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add subdom online callback"));
+    }
+
+    ret = be_add_offline_cb(ctx, be_ctx, ad_subdom_offline_cb, ctx, NULL);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add subdom offline callback"));
+    }
+
+    err = sss_idmap_init(idmap_talloc, ctx, idmap_free, &ctx->idmap_ctx);
+    if (err != IDMAP_SUCCESS) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to initialize idmap context.\n"));
+        return EFAULT;
+    }
+
+    return EOK;
+}
diff --git a/src/providers/ad/ad_subdomains.h b/src/providers/ad/ad_subdomains.h
new file mode 100644
index 0000000..b1a418f
--- /dev/null
+++ b/src/providers/ad/ad_subdomains.h
@@ -0,0 +1,37 @@
+/*
+    SSSD
+
+    AD Subdomains Module
+
+    Authors:
+        Sumit Bose <sbose at redhat.com>
+
+    Copyright (C) 2013 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    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/>.
+*/
+
+#ifndef _IPA_SUBDOMAINS_H_
+#define _IPA_SUBDOMAINS_H_
+
+#include "providers/dp_backend.h"
+#include "providers/ad/ad_common.h"
+
+int ad_subdom_init(struct be_ctx *be_ctx,
+                   struct ad_id_ctx *id_ctx,
+                   const char *ad_domain,
+                   struct bet_ops **ops,
+                   void **pvt_data);
+
+#endif /* _IPA_SUBDOMAINS_H_ */
-- 
1.7.7.6



More information about the sssd-devel mailing list