[SSSD] [PATCH] Look up trusted users directly with AD ID calls if IPA server mode is on

Jakub Hrozek jhrozek at redhat.com
Fri Jun 28 19:23:27 UTC 2013


On Fri, Jun 28, 2013 at 08:59:38PM +0200, Sumit Bose wrote:
> On Fri, Jun 28, 2013 at 06:43:48PM +0200, Jakub Hrozek wrote:
> > Hi,
> > 
> > the attached patches implement
> > https://fedorahosted.org/sssd/ticket/1962. When a new option,
> > ipa_server_mode is set to True, then subdomain/trusted users are not
> > looked up using the extop plugin but AD ID context is initialized and
> > the users are looked up directly with AD code. This is in support of
> > legacy clients looking up trusted AD users and groups.
> 
> Patches are working well, now trusted domain users and groups can have
> algorithmically mapped IDs or IDs from POSIX attributes from the trusted
> DC.
> 
> [PATCH 1/8] IPA: Add a server mode option
> ACK
> 
> [PATCH 2/8] LDAP: Add utility function sdap_copy_map
> > 
> > +
> > +    for (i = 0; i < num_entries; i++) {
> > +        map[i].opt_name = src_map[i].opt_name;
> > +        map[i].def_name = src_map[i].def_name;
> > +        map[i].name = discard_const(src_map[i].def_name);
> > +        map[i].sys_name = src_map[i].sys_name;
> > +
> 

Yes, it would. I have changed the patch. I was just trying to avoid
doing more mallocs than necessary, but actually that already burned me
once with the code as some other part of the back end assumes that the
map is talloc context.

> I wonder if it would be safer in the long run to copy the values instead
> of the references. I think currently the options are not modified, but
> if a future patch starts to modify values there might be unexpected side
> effects?
> 
> [PATCH 3/8] AD: decouple ad_id_ctx initialization
> ACK
> 
> [PATCH 4/8] AD: initialize failover with custom realm, domain and failover service
> ACK
> 
> I think it would be a good idea if someone is working on some code other
> then the initialization routines and sees some calls to configuration
> option to evaluate if the call is really needed at this place or if it
> would be possible to hand the value over as a parameter. This should
> make code more reusable.
> 
> Using calls to the samba configuration management was identified as one
> of the reasons why some of the samba libraries are hard to use in other
> projects. Because it forces the other project to parse a smb.conf file.
> 

I completely agree, the use of confdb_get_* and dp_opt_get_ through the
code was the main reason for this refactoring. But until now the
providers were really self-contained and even the top-level ad_options
or ipa_options variables are provider-global..

But this is something we should think about in the future.. I will add a
note to https://fedorahosted.org/sssd/ticket/1985 so that this best
practice would be captured in a document somewhere and not forgotten in
a patch review thread.

> [PATCH 5/8] IPA: Initialize server mode ctx if server mode is on
> ACK
> 
> [PATCH 6/8] AD: Move storing sdap_domain for subdomain to genericLDAP code
> ACK
> 
> [PATCH 7/8] IPA: Create and remove AD id_ctx for subdomains discovered in server mode
> ACK
> 
> [PATCH 8/8] IPA: Look up AD users directly if IPA server mode is on
> ACK
> 
> Thank you.

Thank you for the review, new patches are attached.
-------------- next part --------------
>From 09ba8e4118f4d15aee77a2339924c6370d949e89 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 17 Jun 2013 09:32:07 +0200
Subject: [PATCH 1/8] IPA: Add a server mode option

https://fedorahosted.org/sssd/ticket/1993

SSSD needs to know that it is running on an IPA server and should not
look up trusted users and groups with the help of the extdom plugin
but do the lookups on its own. For this a new boolean configuration
option, is introduced which defaults to false but is set to true during
ipa-server-install or during updates of the FreeIPA server if it is not
already set.
---
 src/config/etc/sssd.api.d/sssd-ipa.conf |  1 +
 src/man/sssd-ipa.5.xml                  | 19 +++++++++++++++++++
 src/providers/ipa/ipa_common.h          |  1 +
 src/providers/ipa/ipa_opts.h            |  1 +
 4 files changed, 22 insertions(+)

diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
index 8a7e75f2a820e5fac604201586257342787d4a01..bc14fbe3d4153bd7a7ca4ffe0351edf0b8c02ee4 100644
--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
@@ -128,6 +128,7 @@ ldap_idmap_default_domain_sid = str, None, false
 ldap_groups_use_matching_rule_in_chain = bool, None, false
 ldap_initgroups_use_matching_rule_in_chain = bool, None, false
 ldap_rfc2307_fallback_to_local_users = bool, None, false
+ipa_server_mode = bool, None, false
 
 [provider/ipa/auth]
 krb5_ccachedir = str, None, false
diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
index a0c2c3460ac714cd849c176866723eaf90e9920a..2eebe70ffd40060f6aefe072da2b0717fc0d52c4 100644
--- a/src/man/sssd-ipa.5.xml
+++ b/src/man/sssd-ipa.5.xml
@@ -457,6 +457,7 @@
                         </para>
                     </listitem>
                 </varlistentry>
+
                 <varlistentry>
                     <term>ipa_hbac_support_srchost (boolean)</term>
                     <listitem>
@@ -475,6 +476,24 @@
                     </listitem>
                 </varlistentry>
 
+                <varlistentry>
+                    <term>ipa_server_mode (boolean)</term>
+                    <listitem>
+                        <para>
+                            This options should only be set by the IPA
+                            installer.
+                        </para>
+                        <para>
+                            The option denotes that the SSSD is running on
+                            IPA server and should perform lookups of users
+                            and groups from trusted domains differently.
+                        </para>
+                        <para>
+                            Default: false
+                        </para>
+                    </listitem>
+                </varlistentry>
+
                 <varlistentry condition="with_autofs">
                     <term>ipa_automount_location (string)</term>
                     <listitem>
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index 8bf2d3e17596499cc2625174d80a9c7bf16f8a8c..43ccb8e0a30b76da53b0a865b517194fc4a4d7d7 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -50,6 +50,7 @@ enum ipa_basic_opt {
     IPA_AUTOMOUNT_LOCATION,
     IPA_RANGES_SEARCH_BASE,
     IPA_ENABLE_DNS_SITES,
+    IPA_SERVER_MODE,
 
     IPA_OPTS_BASIC /* opts counter */
 };
diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
index 139008b1a2df925f7ddfb3efc91fd23adf3cde2d..9babca73f4cf2e48ec7dff085870fa69429053df 100644
--- a/src/providers/ipa/ipa_opts.h
+++ b/src/providers/ipa/ipa_opts.h
@@ -48,6 +48,7 @@ struct dp_option ipa_basic_opts[] = {
     { "ipa_automount_location", DP_OPT_STRING, { "default" }, NULL_STRING },
     { "ipa_ranges_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ipa_enable_dns_sites", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+    { "ipa_server_mode", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     DP_OPTION_TERMINATOR
 };
 
-- 
1.8.3.1

-------------- next part --------------
>From 4a4b68ab54b3011140e1d98b2bb625455f4a511b Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 19 Jun 2013 19:06:14 +0300
Subject: [PATCH 2/8] LDAP: Add utility function sdap_copy_map

The AD subdomains will only use default options values. This patch
introduces a new utility function sdap_copy_map() that copies the
default options map.

Subtask of:
https://fedorahosted.org/sssd/ticket/1962
---
 src/providers/ldap/sdap.c | 33 +++++++++++++++++++++++++++++++++
 src/providers/ldap/sdap.h |  5 +++++
 2 files changed, 38 insertions(+)

diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
index 0492be05d78b78967989ecd783d92ce94315c551..3765a2a24885b348dd0b5f515e46d5858676bf98 100644
--- a/src/providers/ldap/sdap.c
+++ b/src/providers/ldap/sdap.c
@@ -28,6 +28,39 @@
 
 /* =Retrieve-Options====================================================== */
 
+int sdap_copy_map(TALLOC_CTX *memctx,
+                 struct sdap_attr_map *src_map,
+                 int num_entries,
+                 struct sdap_attr_map **_map)
+{
+    struct sdap_attr_map *map;
+    int i;
+
+    map = talloc_array(memctx, struct sdap_attr_map, num_entries);
+    if (!map) {
+        return ENOMEM;
+    }
+
+    for (i = 0; i < num_entries; i++) {
+        map[i].opt_name = talloc_strdup(map, src_map[i].opt_name);
+        map[i].def_name = talloc_strdup(map, src_map[i].def_name);
+        map[i].name = talloc_strdup(map, src_map[i].def_name);
+        map[i].sys_name = talloc_strdup(map, src_map[i].sys_name);
+
+        if (map[i].opt_name == NULL || map[i].def_name == NULL
+                || map[i].name == NULL || map[i].sys_name == NULL) {
+            return ENOMEM;
+        }
+
+        DEBUG(SSSDBG_TRACE_FUNC, ("Option %s has%s value %s\n",
+              map[i].opt_name, map[i].name ? "" : " no",
+              map[i].name ? map[i].name : ""));
+    }
+
+    *_map = map;
+    return EOK;
+}
+
 int sdap_get_map(TALLOC_CTX *memctx,
                  struct confdb_ctx *cdb,
                  const char *conf_path,
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 9fbe04b6a7071b82cc0170e7d8b371898b20a8a7..24d208a2e62dc088821d866e5b1411c94397e232 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -438,6 +438,11 @@ struct sdap_deref_attrs {
     struct sysdb_attrs *attrs;
 };
 
+int sdap_copy_map(TALLOC_CTX *memctx,
+                 struct sdap_attr_map *src_map,
+                 int num_entries,
+                 struct sdap_attr_map **_map);
+
 int sdap_get_map(TALLOC_CTX *memctx,
                  struct confdb_ctx *cdb,
                  const char *conf_path,
-- 
1.8.3.1

-------------- next part --------------
>From 46e08f7c82f4d481323d424288ed687225744eec Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 17 Jun 2013 18:32:53 +0200
Subject: [PATCH 3/8] AD: decouple ad_id_ctx initialization

The IPA subdomain code will perform lookups on its own in the server
mode. For this, the AD provider must offer a way to initialize the
ad_id_ctx for external consumers.

Subtask of:
https://fedorahosted.org/sssd/ticket/1962
---
 src/providers/ad/ad_common.c | 350 +++++++++++++++++++++++++++++++++----------
 src/providers/ad/ad_common.h |   7 +
 src/providers/ad/ad_init.c   |  30 ++--
 3 files changed, 285 insertions(+), 102 deletions(-)

diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index b06691206f319bf2988f6b56c4d052e02aff423d..2f87bc63ea237e768e550deb7ffe3319d3cf6daf 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -29,6 +29,214 @@ struct ad_server_data {
     bool gc;
 };
 
+errno_t ad_set_search_bases(struct sdap_options *id_opts);
+static errno_t ad_set_ad_id_options(struct ad_options *ad_opts,
+                                    struct sdap_options *id_opts);
+
+static struct sdap_options *
+ad_create_default_sdap_options(TALLOC_CTX *mem_ctx)
+{
+    struct sdap_options *id_opts;
+    errno_t ret;
+
+    id_opts = talloc_zero(mem_ctx, struct sdap_options);
+    if (!id_opts) {
+        return NULL;
+    }
+
+    ret = dp_copy_options(id_opts,
+                          ad_def_ldap_opts,
+                          SDAP_OPTS_BASIC,
+                          &id_opts->basic);
+    if (ret != EOK) {
+        goto fail;
+    }
+
+    /* Get sdap option maps */
+
+    /* General Attribute Map */
+    ret = sdap_copy_map(id_opts,
+                       ad_2008r2_attr_map,
+                       SDAP_AT_GENERAL,
+                       &id_opts->gen_map);
+    if (ret != EOK) {
+        goto fail;
+    }
+
+    /* User map */
+    ret = sdap_copy_map(id_opts,
+                       ad_2008r2_user_map,
+                       SDAP_OPTS_USER,
+                       &id_opts->user_map);
+    if (ret != EOK) {
+        goto fail;
+    }
+
+    /* Group map */
+    ret = sdap_copy_map(id_opts,
+                       ad_2008r2_group_map,
+                       SDAP_OPTS_GROUP,
+                       &id_opts->group_map);
+    if (ret != EOK) {
+        goto fail;
+    }
+
+    /* Netgroup map */
+    ret = sdap_copy_map(id_opts,
+                       ad_netgroup_map,
+                       SDAP_OPTS_NETGROUP,
+                       &id_opts->netgroup_map);
+    if (ret != EOK) {
+        goto fail;
+    }
+
+    /* Services map */
+    ret = sdap_copy_map(id_opts,
+                       ad_service_map,
+                       SDAP_OPTS_SERVICES,
+                       &id_opts->service_map);
+    if (ret != EOK) {
+        goto fail;
+    }
+
+    return id_opts;
+
+fail:
+    talloc_free(id_opts);
+    return NULL;
+}
+
+struct ad_options *
+ad_create_default_options(TALLOC_CTX *mem_ctx,
+                          const char *realm,
+                          const char *hostname)
+{
+    struct ad_options *ad_options;
+    errno_t ret;
+
+    ad_options = talloc_zero(mem_ctx, struct ad_options);
+    if (ad_options == NULL) return NULL;
+
+    ret = dp_copy_options(ad_options,
+                          ad_basic_opts,
+                          AD_OPTS_BASIC,
+                          &ad_options->basic);
+    if (ret != EOK) {
+        talloc_free(ad_options);
+        return NULL;
+    }
+
+    ad_options->id = ad_create_default_sdap_options(ad_options);
+    if (ad_options->id == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot initialize AD LDAP options\n"));
+        talloc_free(ad_options);
+        return NULL;
+    }
+
+    ret = dp_opt_set_string(ad_options->basic, AD_KRB5_REALM, realm);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot set AD domain\n"));
+        talloc_free(ad_options);
+        return NULL;
+    }
+
+    ret = dp_opt_set_string(ad_options->basic, AD_HOSTNAME, hostname);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot set AD domain\n"));
+        talloc_free(ad_options);
+        return NULL;
+    }
+
+    ret = ad_set_ad_id_options(ad_options, ad_options->id);
+    if (ret != EOK) {
+        talloc_free(ad_options);
+        return NULL;
+    }
+
+    return ad_options;
+}
+
+static errno_t
+ad_create_sdap_options(TALLOC_CTX *mem_ctx,
+                       struct confdb_ctx *cdb,
+                       const char *conf_path,
+                       struct sdap_options **_id_opts)
+{
+    struct sdap_options *id_opts;
+    errno_t ret;
+
+    id_opts = talloc_zero(mem_ctx, struct sdap_options);
+    if (!id_opts) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = dp_get_options(id_opts, cdb, conf_path,
+                         ad_def_ldap_opts,
+                         SDAP_OPTS_BASIC,
+                         &id_opts->basic);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* Get sdap option maps */
+
+    /* General Attribute Map */
+    ret = sdap_get_map(id_opts,
+                       cdb, conf_path,
+                       ad_2008r2_attr_map,
+                       SDAP_AT_GENERAL,
+                       &id_opts->gen_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* User map */
+    ret = sdap_get_map(id_opts,
+                       cdb, conf_path,
+                       ad_2008r2_user_map,
+                       SDAP_OPTS_USER,
+                       &id_opts->user_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* Group map */
+    ret = sdap_get_map(id_opts,
+                       cdb, conf_path,
+                       ad_2008r2_group_map,
+                       SDAP_OPTS_GROUP,
+                       &id_opts->group_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* Netgroup map */
+    ret = sdap_get_map(id_opts,
+                       cdb, conf_path,
+                       ad_netgroup_map,
+                       SDAP_OPTS_NETGROUP,
+                       &id_opts->netgroup_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* Services map */
+    ret = sdap_get_map(id_opts,
+                       cdb, conf_path,
+                       ad_service_map,
+                       SDAP_OPTS_SERVICES,
+                       &id_opts->service_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = EOK;
+    *_id_opts = id_opts;
+done:
+    return ret;
+}
+
 errno_t
 ad_get_common_options(TALLOC_CTX *mem_ctx,
                       struct confdb_ctx *cdb,
@@ -576,49 +784,14 @@ done:
     return;
 }
 
-errno_t
-ad_set_search_bases(struct sdap_options *id_opts);
-
-errno_t
-ad_get_id_options(struct ad_options *ad_opts,
-                   struct confdb_ctx *cdb,
-                   const char *conf_path,
-                   struct sdap_options **_opts)
+static errno_t
+ad_set_ad_id_options(struct ad_options *ad_opts,
+                     struct sdap_options *id_opts)
 {
     errno_t ret;
-    TALLOC_CTX *tmp_ctx;
-    struct sdap_options *id_opts;
     char *krb5_realm;
     char *keytab_path;
 
-    tmp_ctx = talloc_new(NULL);
-    if (!tmp_ctx) return ENOMEM;
-
-    id_opts = talloc_zero(tmp_ctx, struct sdap_options);
-    if (!id_opts) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    ret = sdap_domain_add(id_opts,
-                          ad_opts->id_ctx->sdap_id_ctx->be->domain,
-                          NULL);
-    if (ret != EOK) {
-        goto done;
-    }
-
-    ret = dp_get_options(id_opts, cdb, conf_path,
-                         ad_def_ldap_opts,
-                         SDAP_OPTS_BASIC,
-                         &id_opts->basic);
-    if (ret != EOK) {
-        goto done;
-    }
-
-    /* Set up search bases if they were assigned explicitly */
-    ret = ad_set_search_bases(id_opts);
-    if (ret != EOK) goto done;
-
     /* We only support Kerberos password policy with AD, so
      * force that on.
      */
@@ -671,64 +844,49 @@ ad_get_id_options(struct ad_options *ad_opts,
     /* fix schema to AD  */
     id_opts->schema_type = SDAP_SCHEMA_AD;
 
-    /* Get sdap option maps */
+    ad_opts->id = id_opts;
+    ret = EOK;
+done:
+    return ret;
+}
 
-    /* General Attribute Map */
-    ret = sdap_get_map(id_opts,
-                       cdb, conf_path,
-                       ad_2008r2_attr_map,
-                       SDAP_AT_GENERAL,
-                       &id_opts->gen_map);
-    if (ret != EOK) {
-        goto done;
-    }
+errno_t
+ad_get_id_options(struct ad_options *ad_opts,
+                  struct confdb_ctx *cdb,
+                  const char *conf_path,
+                  struct sdap_options **_opts)
+{
+    struct sdap_options *id_opts;
+    errno_t ret;
 
-    /* User map */
-    ret = sdap_get_map(id_opts,
-                       cdb, conf_path,
-                       ad_2008r2_user_map,
-                       SDAP_OPTS_USER,
-                       &id_opts->user_map);
+    ret = ad_create_sdap_options(ad_opts, cdb, conf_path, &id_opts);
     if (ret != EOK) {
-        goto done;
+        return ENOMEM;
     }
 
-    /* Group map */
-    ret = sdap_get_map(id_opts,
-                       cdb, conf_path,
-                       ad_2008r2_group_map,
-                       SDAP_OPTS_GROUP,
-                       &id_opts->group_map);
+    ret = ad_set_ad_id_options(ad_opts, id_opts);
     if (ret != EOK) {
-        goto done;
+        talloc_free(id_opts);
+        return ret;
     }
 
-    /* Netgroup map */
-    ret = sdap_get_map(id_opts,
-                       cdb, conf_path,
-                       ad_netgroup_map,
-                       SDAP_OPTS_NETGROUP,
-                       &id_opts->netgroup_map);
+    ret = sdap_domain_add(id_opts,
+                          ad_opts->id_ctx->sdap_id_ctx->be->domain,
+                          NULL);
     if (ret != EOK) {
-        goto done;
+        talloc_free(id_opts);
+        return ret;
     }
 
-    /* Services map */
-    ret = sdap_get_map(id_opts,
-                       cdb, conf_path,
-                       ad_service_map,
-                       SDAP_OPTS_SERVICES,
-                       &id_opts->service_map);
+    /* Set up search bases if they were assigned explicitly */
+    ret = ad_set_search_bases(id_opts);
     if (ret != EOK) {
-        goto done;
+        talloc_free(id_opts);
+        return ret;
     }
 
-    ad_opts->id = talloc_steal(ad_opts, id_opts);
     *_opts = id_opts;
-    ret = EOK;
-done:
-    talloc_free(tmp_ctx);
-    return ret;
+    return EOK;
 }
 
 errno_t
@@ -898,3 +1056,33 @@ errno_t ad_get_dyndns_options(struct be_ctx *be_ctx,
 
     return EOK;
 }
+
+
+struct ad_id_ctx *
+ad_id_ctx_init(struct ad_options *ad_opts, struct be_ctx *bectx)
+{
+    struct sdap_id_ctx *sdap_ctx;
+    struct ad_id_ctx *ad_ctx;
+
+    ad_ctx = talloc_zero(ad_opts, struct ad_id_ctx);
+    if (ad_ctx == NULL) {
+        return NULL;
+    }
+    ad_ctx->ad_options = ad_opts;
+
+    sdap_ctx = sdap_id_ctx_new(ad_ctx, bectx, ad_opts->service->sdap);
+    if (sdap_ctx == NULL) {
+        talloc_free(ad_ctx);
+        return NULL;
+    }
+    ad_ctx->sdap_id_ctx = sdap_ctx;
+    ad_ctx->ldap_ctx = sdap_ctx->conn;
+
+    ad_ctx->gc_ctx = sdap_id_ctx_conn_add(sdap_ctx, ad_opts->service->gc);
+    if (ad_ctx->gc_ctx == NULL) {
+        talloc_free(ad_ctx);
+        return NULL;
+    }
+
+    return ad_ctx;
+}
diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
index 500f49c783d488e217955fad2472177fbf733de5..11075423c15854a236e0acabbdcce4551b6097b2 100644
--- a/src/providers/ad/ad_common.h
+++ b/src/providers/ad/ad_common.h
@@ -82,6 +82,10 @@ ad_get_common_options(TALLOC_CTX *mem_ctx,
                       struct sss_domain_info *dom,
                       struct ad_options **_opts);
 
+struct ad_options *ad_create_default_options(TALLOC_CTX *mem_ctx,
+                                             const char *realm,
+                                             const char *hostname);
+
 errno_t
 ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *ctx,
                  const char *primary_servers,
@@ -104,6 +108,9 @@ errno_t
 ad_get_dyndns_options(struct be_ctx *be_ctx,
                       struct ad_options *ad_opts);
 
+struct ad_id_ctx *
+ad_id_ctx_init(struct ad_options *ad_opts, struct be_ctx *bectx);
+
 /* AD dynamic DNS updates */
 errno_t ad_dyndns_init(struct be_ctx *be_ctx,
                        struct ad_options *ctx);
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index 5c6b6f5c84afc3597ff2a65e91e20d2fb7e69f9a..5efe05e6424784484ebbad0a950849fc128bc81d 100644
--- a/src/providers/ad/ad_init.c
+++ b/src/providers/ad/ad_init.c
@@ -109,7 +109,6 @@ sssm_ad_id_init(struct be_ctx *bectx,
 {
     errno_t ret;
     struct ad_id_ctx *ad_ctx;
-    struct sdap_id_ctx *sdap_ctx;
     const char *hostname;
     const char *ad_domain;
     struct ad_srv_plugin_ctx *srv_ctx;
@@ -128,26 +127,14 @@ sssm_ad_id_init(struct be_ctx *bectx,
         return EOK;
     }
 
-    ad_ctx = talloc_zero(ad_options, struct ad_id_ctx);
+
+    ad_ctx = ad_id_ctx_init(ad_options, bectx);
     if (ad_ctx == NULL) {
         return ENOMEM;
     }
-    ad_ctx->ad_options = ad_options;
     ad_options->id_ctx = ad_ctx;
 
-    sdap_ctx = sdap_id_ctx_new(ad_options, bectx, ad_options->service->sdap);
-    if (sdap_ctx == NULL) {
-        return ENOMEM;
-    }
-    ad_ctx->sdap_id_ctx = sdap_ctx;
-    ad_ctx->ldap_ctx = sdap_ctx->conn;
-
-    ad_ctx->gc_ctx = sdap_id_ctx_conn_add(sdap_ctx, ad_options->service->gc);
-    if (ad_ctx->gc_ctx == NULL) {
-        return ENOMEM;
-    }
-
-    ret = ad_dyndns_init(sdap_ctx->be, ad_options);
+    ret = ad_dyndns_init(ad_ctx->sdap_id_ctx->be, ad_options);
     if (ret != EOK) {
         DEBUG(SSSDBG_MINOR_FAILURE,
              ("Failure setting up automatic DNS update\n"));
@@ -165,22 +152,23 @@ sssm_ad_id_init(struct be_ctx *bectx,
     /* Set up various SDAP options */
     ret = ad_get_id_options(ad_options, bectx->cdb,
                             bectx->conf_path,
-                            &sdap_ctx->opts);
+                            &ad_ctx->sdap_id_ctx->opts);
     if (ret != EOK) {
         goto done;
     }
 
-    ret = sdap_id_setup_tasks(sdap_ctx);
+    ret = sdap_id_setup_tasks(ad_ctx->sdap_id_ctx);
     if (ret != EOK) {
         goto done;
     }
 
     /* Set up the ID mapping object */
-    ret = sdap_idmap_init(sdap_ctx, sdap_ctx, &sdap_ctx->opts->idmap_ctx);
+    ret = sdap_idmap_init(ad_ctx->sdap_id_ctx, ad_ctx->sdap_id_ctx,
+                          &ad_ctx->sdap_id_ctx->opts->idmap_ctx);
     if (ret != EOK) goto done;
 
 
-    ret = setup_tls_config(sdap_ctx->opts->basic);
+    ret = setup_tls_config(ad_ctx->sdap_id_ctx->opts->basic);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE,
               ("setup_tls_config failed [%s]\n", strerror(ret)));
@@ -217,7 +205,7 @@ sssm_ad_id_init(struct be_ctx *bectx,
     ret = be_refresh_add_cb(bectx->refresh_ctx, BE_REFRESH_TYPE_NETGROUPS,
                             sdap_refresh_netgroups_send,
                             sdap_refresh_netgroups_recv,
-                            sdap_ctx);
+                            ad_ctx->sdap_id_ctx);
     if (ret != EOK && ret != EEXIST) {
         DEBUG(SSSDBG_MINOR_FAILURE, ("Periodical refresh of netgroups "
               "will not work [%d]: %s\n", ret, strerror(ret)));
-- 
1.8.3.1

-------------- next part --------------
>From beee5ef886113817fe0ff576d1237abe340c41e4 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 19 Jun 2013 10:49:05 +0200
Subject: [PATCH 4/8] AD: initialize failover with custom realm, domain and
 failover service

This is needed so we can initialize failover using IPA realm and
on-the-fly discovered DNS domain. The subdomains discovered on-thefly
will use the subdomain name for realm, domain and failover service to
avoid conflicts.

Subtaks of:
https://fedorahosted.org/sssd/ticket/1962
---
 src/providers/ad/ad_common.c | 58 ++++++++++++++++++++++++--------------------
 src/providers/ad/ad_common.h |  5 +++-
 src/providers/ad/ad_init.c   |  6 ++++-
 3 files changed, 41 insertions(+), 28 deletions(-)

diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index 2f87bc63ea237e768e550deb7ffe3319d3cf6daf..700ac033f42ac700b4e255a74350d774a3340358 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -356,14 +356,15 @@ static errno_t
 _ad_servers_init(TALLOC_CTX *mem_ctx,
                  struct ad_service *service,
                  struct be_ctx *bectx,
+                 const char *fo_service,
+                 const char *fo_gc_service,
                  const char *servers,
-                 struct ad_options *options,
+                 const char *ad_domain,
                  bool primary)
 {
     size_t i;
     errno_t ret = 0;
     char **list;
-    char *ad_domain;
     struct ad_server_data *sdata;
     TALLOC_CTX *tmp_ctx;
 
@@ -377,8 +378,6 @@ _ad_servers_init(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
-    ad_domain = dp_opt_get_string(options->basic, AD_DOMAIN);
-
     /* Add each of these servers to the failover service */
     for (i = 0; list[i]; i++) {
         if (be_fo_is_srv_identifier(list[i])) {
@@ -397,7 +396,7 @@ _ad_servers_init(TALLOC_CTX *mem_ctx,
             }
             sdata->gc = true;
 
-            ret = be_fo_add_srv_server(bectx, AD_GC_SERVICE_NAME, "gc",
+            ret = be_fo_add_srv_server(bectx, fo_gc_service, "gc",
                                        ad_domain, BE_FO_PROTO_TCP,
                                        false, sdata);
             if (ret != EOK) {
@@ -414,7 +413,7 @@ _ad_servers_init(TALLOC_CTX *mem_ctx,
             }
             sdata->gc = false;
 
-            ret = be_fo_add_srv_server(bectx, AD_SERVICE_NAME, "ldap",
+            ret = be_fo_add_srv_server(bectx, fo_service, "ldap",
                                        ad_domain, BE_FO_PROTO_TCP,
                                        false, sdata);
             if (ret != EOK) {
@@ -442,7 +441,7 @@ _ad_servers_init(TALLOC_CTX *mem_ctx,
         }
         sdata->gc = true;
 
-        ret = be_fo_add_server(bectx, AD_SERVICE_NAME, list[i], 0, sdata, primary);
+        ret = be_fo_add_server(bectx, fo_service, list[i], 0, sdata, primary);
         if (ret && ret != EEXIST) {
             DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to add server\n"));
             goto done;
@@ -455,7 +454,7 @@ _ad_servers_init(TALLOC_CTX *mem_ctx,
         }
         sdata->gc = false;
 
-        ret = be_fo_add_server(bectx, AD_SERVICE_NAME, list[i], 0, sdata, primary);
+        ret = be_fo_add_server(bectx, fo_service, list[i], 0, sdata, primary);
         if (ret && ret != EEXIST) {
             DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to add server\n"));
             goto done;
@@ -471,17 +470,21 @@ done:
 static inline errno_t
 ad_primary_servers_init(TALLOC_CTX *mem_ctx, struct ad_service *service,
                         struct be_ctx *bectx, const char *servers,
-                        struct ad_options *options)
+                        const char *fo_service, const char *fo_gc_service,
+                        const char *ad_domain)
 {
-    return _ad_servers_init(mem_ctx, service, bectx, servers, options, true);
+    return _ad_servers_init(mem_ctx, service, bectx, fo_service,
+                            fo_gc_service, servers, ad_domain, true);
 }
 
 static inline errno_t
 ad_backup_servers_init(TALLOC_CTX *mem_ctx, struct ad_service *service,
                         struct be_ctx *bectx, const char *servers,
-                        struct ad_options *options)
+                        const char *fo_service, const char *fo_gc_service,
+                        const char *ad_domain)
 {
-    return _ad_servers_init(mem_ctx, service, bectx, servers, options, false);
+    return _ad_servers_init(mem_ctx, service, bectx, fo_service,
+                            fo_gc_service, servers, ad_domain, false);
 }
 
 static int ad_user_data_cmp(void *ud1, void *ud2)
@@ -522,13 +525,15 @@ errno_t
 ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
                  const char *primary_servers,
                  const char *backup_servers,
-                 struct ad_options *options,
+                 const char *krb5_realm,
+                 const char *ad_service,
+                 const char *ad_gc_service,
+                 const char *ad_domain,
                  struct ad_service **_service)
 {
     errno_t ret;
     TALLOC_CTX *tmp_ctx;
     struct ad_service *service;
-    char *realm;
 
     tmp_ctx = talloc_new(mem_ctx);
     if (!tmp_ctx) return ENOMEM;
@@ -546,8 +551,8 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
         goto done;
     }
 
-    service->sdap->name = talloc_strdup(service->sdap, AD_SERVICE_NAME);
-    service->gc->name = talloc_strdup(service->gc, AD_GC_SERVICE_NAME);
+    service->sdap->name = talloc_strdup(service->sdap, ad_service);
+    service->gc->name = talloc_strdup(service->gc, ad_gc_service);
     if (!service->sdap->name || !service->gc->name) {
         ret = ENOMEM;
         goto done;
@@ -559,20 +564,20 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
         goto done;
     }
 
-    ret = be_fo_add_service(bectx, AD_SERVICE_NAME, ad_user_data_cmp);
+    ret = be_fo_add_service(bectx, ad_service, ad_user_data_cmp);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to create failover service!\n"));
         goto done;
     }
 
-    ret = be_fo_add_service(bectx, AD_GC_SERVICE_NAME, ad_user_data_cmp);
+    ret = be_fo_add_service(bectx, ad_gc_service, ad_user_data_cmp);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to create GC failover service!\n"));
         goto done;
     }
 
     service->krb5_service->name = talloc_strdup(service->krb5_service,
-                                                AD_SERVICE_NAME);
+                                                ad_service);
     if (!service->krb5_service->name) {
         ret = ENOMEM;
         goto done;
@@ -580,14 +585,13 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
     service->sdap->kinit_service_name = service->krb5_service->name;
     service->gc->kinit_service_name = service->krb5_service->name;
 
-    realm = dp_opt_get_string(options->basic, AD_KRB5_REALM);
-    if (!realm) {
+    if (!krb5_realm) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("No Kerberos realm set\n"));
         ret = EINVAL;
         goto done;
     }
     service->krb5_service->realm =
-        talloc_strdup(service->krb5_service, realm);
+        talloc_strdup(service->krb5_service, krb5_realm);
     if (!service->krb5_service->realm) {
         ret = ENOMEM;
         goto done;
@@ -600,14 +604,16 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
     }
 
     ret = ad_primary_servers_init(mem_ctx, service, bectx,
-                                  primary_servers, options);
+                                  primary_servers, ad_service,
+                                  ad_gc_service, ad_domain);
     if (ret != EOK) {
         goto done;
     }
 
     if (backup_servers) {
         ret = ad_backup_servers_init(mem_ctx, service, bectx,
-                                     backup_servers, options);
+                                     backup_servers, ad_service,
+                                     ad_gc_service, ad_domain);
         if (ret != EOK) {
             goto done;
         }
@@ -619,7 +625,7 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
         return ret;
     }
 
-    ret = be_fo_service_add_callback(mem_ctx, bectx, AD_SERVICE_NAME,
+    ret = be_fo_service_add_callback(mem_ctx, bectx, ad_service,
                                      ad_resolve_callback, service);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE,
@@ -627,7 +633,7 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
         goto done;
     }
 
-    ret = be_fo_service_add_callback(mem_ctx, bectx, AD_GC_SERVICE_NAME,
+    ret = be_fo_service_add_callback(mem_ctx, bectx, ad_gc_service,
                                      ad_resolve_callback, service);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE,
diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
index 11075423c15854a236e0acabbdcce4551b6097b2..98aeb2165273b5dbfafd3b8757180d74b4504c98 100644
--- a/src/providers/ad/ad_common.h
+++ b/src/providers/ad/ad_common.h
@@ -90,7 +90,10 @@ errno_t
 ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *ctx,
                  const char *primary_servers,
                  const char *backup_servers,
-                 struct ad_options *options,
+                 const char *krb5_realm,
+                 const char *ad_service,
+                 const char *ad_gc_service,
+                 const char *ad_domain,
                  struct ad_service **_service);
 
 errno_t
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index 5efe05e6424784484ebbad0a950849fc128bc81d..c5d3fac235dd2473ce98c425adfc9aef0e7b9219 100644
--- a/src/providers/ad/ad_init.c
+++ b/src/providers/ad/ad_init.c
@@ -71,6 +71,7 @@ common_ad_init(struct be_ctx *bectx)
     errno_t ret;
     char *ad_servers = NULL;
     char *ad_backup_servers = NULL;
+    char *ad_realm;
 
     /* Get AD-specific options */
     ret = ad_get_common_options(bectx, bectx->cdb,
@@ -86,9 +87,12 @@ common_ad_init(struct be_ctx *bectx)
 
     ad_servers = dp_opt_get_string(ad_options->basic, AD_SERVER);
     ad_backup_servers = dp_opt_get_string(ad_options->basic, AD_BACKUP_SERVER);
+    ad_realm = dp_opt_get_string(ad_options->basic, AD_KRB5_REALM);
 
     /* Set up the failover service */
-    ret = ad_failover_init(ad_options, bectx, ad_servers, ad_backup_servers, ad_options,
+    ret = ad_failover_init(ad_options, bectx, ad_servers, ad_backup_servers, ad_realm,
+                           AD_SERVICE_NAME, AD_GC_SERVICE_NAME,
+                           dp_opt_get_string(ad_options->basic, AD_DOMAIN),
                            &ad_options->service);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE,
-- 
1.8.3.1

-------------- next part --------------
>From d9537ab2354292605be936521e265041d00d2bb7 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 19 Jun 2013 10:50:44 +0200
Subject: [PATCH 5/8] IPA: Initialize server mode ctx if server mode is on

This patch introduces a new structure that holds information about a
subdomain and its ad_id_ctx. This structure will be used only in server
mode to make it possible to search subdomains with a particular
ad_id_ctx.

Subtask of:
https://fedorahosted.org/sssd/ticket/1962
---
 Makefile.am                        |  7 +++++++
 src/providers/ipa/ipa_common.h     |  5 +++++
 src/providers/ipa/ipa_init.c       |  6 ++++++
 src/providers/ipa/ipa_subdomains.c | 33 +++++++++++++++++++++++++++++++++
 src/providers/ipa/ipa_subdomains.h | 18 ++++++++++++++++++
 5 files changed, 69 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index da1d26c6d9ecba3ad187a1dca9a149fdf889c01b..515843420834bbbd0e5b4c86c114294c89afa752 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1575,6 +1575,11 @@ libsss_ipa_la_SOURCES = \
     src/providers/ipa/ipa_selinux_common.c \
     src/providers/ipa/ipa_srv.c \
     src/providers/ipa/ipa_idmap.c \
+    src/providers/ad/ad_common.c \
+    src/providers/ad/ad_common.h \
+    src/providers/ad/ad_dyndns.c \
+    src/providers/ad/ad_id.c \
+    src/providers/ad/ad_srv.c \
     src/util/user_info_msg.c \
     src/util/find_uid.c \
     src/util/sss_ldap.c \
@@ -1583,10 +1588,12 @@ libsss_ipa_la_CFLAGS = \
     $(AM_CFLAGS) \
     $(LDAP_CFLAGS) \
     $(DHASH_CFLAGS) \
+    $(NDR_NBT_CFLAGS)
     $(KRB5_CFLAGS)
 libsss_ipa_la_LIBADD = \
     $(OPENLDAP_LIBS) \
     $(DHASH_LIBS) \
+    $(NDR_NBT_LIBS) \
     $(KEYUTILS_LIBS) \
     $(KRB5_LIBS) \
     libsss_ldap_common.la \
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index 43ccb8e0a30b76da53b0a865b517194fc4a4d7d7..2af20e1dec3c2d64df563d800b27f95695242759 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -112,9 +112,14 @@ struct ipa_auth_ctx {
     struct dp_option *ipa_options;
 };
 
+/* In server mode, each subdomain corresponds to an AD context */
+
 struct ipa_id_ctx {
     struct sdap_id_ctx *sdap_id_ctx;
     struct ipa_options *ipa_options;
+
+    /* Only used with server mode */
+    struct ipa_server_mode_ctx *server_mode;
 };
 
 struct ipa_options {
diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
index 7297fc936c948e548b7ee8989f76c215fafe41e1..fe13b18722d7a2506ea52850e17a4cf20073bc56 100644
--- a/src/providers/ipa/ipa_init.c
+++ b/src/providers/ipa/ipa_init.c
@@ -528,6 +528,12 @@ int sssm_ipa_subdomains_init(struct be_ctx *bectx,
         return ret;
     }
 
+    ret = ipa_ad_subdom_init(bectx, id_ctx);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("ipa_ad_subdom_init failed.\n"));
+        return ret;
+    }
+
     return EOK;
 }
 
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index a67526c83b425e3479492f3dd29556c85136278e..652726dafee563d2b1739c497aa35bdc082d1cff 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -925,3 +925,36 @@ int ipa_subdom_init(struct be_ctx *be_ctx,
 
     return EOK;
 }
+
+int ipa_ad_subdom_init(struct be_ctx *be_ctx,
+                       struct ipa_id_ctx *id_ctx)
+{
+    char *realm;
+    char *hostname;
+
+    if (dp_opt_get_bool(id_ctx->ipa_options->basic,
+                        IPA_SERVER_MODE) == false) {
+        return EOK;
+    }
+
+    realm = dp_opt_get_string(id_ctx->ipa_options->basic, IPA_KRB5_REALM);
+    if (realm == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("No Kerberos realm for IPA?\n"));
+        return EINVAL;
+    }
+
+    hostname = dp_opt_get_string(id_ctx->ipa_options->basic, IPA_HOSTNAME);
+    if (hostname == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("No host name for IPA?\n"));
+        return EINVAL;
+    }
+
+    id_ctx->server_mode = talloc(id_ctx, struct ipa_server_mode_ctx);
+    if (id_ctx->server_mode == NULL) {
+        return ENOMEM;
+    }
+    id_ctx->server_mode->realm = realm;
+    id_ctx->server_mode->hostname = hostname;
+
+    return EOK;
+}
diff --git a/src/providers/ipa/ipa_subdomains.h b/src/providers/ipa/ipa_subdomains.h
index c9ab82a25df2dee06dfb8cc0da754ff3a359d0e6..315ce9e06c5159406782d00ffacef58b503c7118 100644
--- a/src/providers/ipa/ipa_subdomains.h
+++ b/src/providers/ipa/ipa_subdomains.h
@@ -38,6 +38,24 @@ int ipa_subdom_init(struct be_ctx *be_ctx,
                     struct bet_ops **ops,
                     void **pvt_data);
 
+/* The following are used in server mode only */
+struct ipa_ad_server_ctx {
+    struct sss_domain_info *dom;
+    struct ad_id_ctx *ad_id_ctx;
+
+    struct ipa_ad_server_ctx *next, *prev;
+};
+
+struct ipa_server_mode_ctx {
+    const char *realm;
+    const char *hostname;
+
+    struct ipa_ad_server_ctx *trusts;
+};
+
+int ipa_ad_subdom_init(struct be_ctx *be_ctx,
+                       struct ipa_id_ctx *id_ctx);
+
 enum req_input_type {
     REQ_INP_NAME,
     REQ_INP_ID,
-- 
1.8.3.1

-------------- next part --------------
>From dab898ad5253f33f4202479439d3cb2e0270c464 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 19 Jun 2013 13:00:41 +0200
Subject: [PATCH 6/8] AD: Move storing sdap_domain for subdomain to generic
 LDAP code

Makes creating the sdap_domain structure for a subdomain reusable
outside AD subdomain code where it was created initially.

Subtask of:
    https://fedorahosted.org/sssd/ticket/1962
---
 src/providers/ad/ad_subdomains.c | 66 +-----------------------------------
 src/providers/ldap/ldap_common.c | 73 ++++++++++++++++++++++++++++++++++++++++
 src/providers/ldap/ldap_common.h |  4 +++
 3 files changed, 78 insertions(+), 65 deletions(-)

diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index 724d0736bf89913d49d19183a9c8f370bc80feb1..be4781cc5bc01152ffa1fbedf0ad5352f72939ae 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -89,71 +89,7 @@ static errno_t
 ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx,
                       struct sss_domain_info *parent)
 {
-    struct sss_domain_info *dom;
-    struct sdap_domain *sdom, *sditer;
-    char *basedn;
-    errno_t ret;
-
-    for (dom = get_next_domain(parent, true);
-         dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
-         dom = get_next_domain(dom, false)) {
-
-        DLIST_FOR_EACH(sditer, ctx->sdom) {
-            if (sditer->dom == dom) {
-                break;
-            }
-        }
-
-        if (sditer == NULL) {
-            /* New sdap domain */
-            DEBUG(SSSDBG_TRACE_FUNC, ("subdomain %s is a new one, will "
-                  "create a new sdap domain object\n", dom->name));
-
-            ret = sdap_domain_add(ctx->sdap_id_ctx->opts, dom, &sdom);
-            if (ret != EOK) {
-                DEBUG(SSSDBG_OP_FAILURE,
-                    ("Cannot add new sdap domain for domain %s [%d]: %s\n",
-                    parent->name, ret, strerror(ret)));
-                return ret;
-            }
-            sditer = sdom;
-        }
-
-        /* Convert the domain name into search base */
-        ret = domain_to_basedn(sditer, sditer->dom->name, &basedn);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_OP_FAILURE,
-                ("Cannot convert domain name [%s] to base DN [%d]: %s\n",
-                dom->name, ret, strerror(ret)));
-            talloc_free(basedn);
-            return ret;
-        }
-
-        /* Update search bases */
-        talloc_zfree(sdom->search_bases);
-        sdom->search_bases = talloc_array(sdom, struct sdap_search_base *, 2);
-        if (sdom->search_bases == NULL) {
-            return ret;
-        }
-        sdom->search_bases[1] = NULL;
-
-        ret = sdap_create_search_base(sdom, basedn, LDAP_SCOPE_SUBTREE, NULL,
-                                      &sdom->search_bases[0]);
-        talloc_free(basedn);
-        if (ret) {
-            DEBUG(SSSDBG_OP_FAILURE, ("Cannot create new sdap search base\n"));
-            return ret;
-        }
-
-        sdom->user_search_bases = sdom->search_bases;
-        sdom->group_search_bases = sdom->search_bases;
-        sdom->netgroup_search_bases = sdom->search_bases;
-        sdom->sudo_search_bases = sdom->search_bases;
-        sdom->service_search_bases = sdom->search_bases;
-        sdom->autofs_search_bases = sdom->search_bases;
-    }
-
-    return EOK;
+    return sdap_domain_subdom_add(ctx->sdap_id_ctx, ctx->sdom, parent);
 }
 
 static errno_t
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 96edd3362caf717ff68ab4eb52d031fc745a7b6e..9aa98173c865d0b032f02bd6a0ec80b93682af6d 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -94,6 +94,79 @@ sdap_domain_add(struct sdap_options *opts,
     return EOK;
 }
 
+errno_t
+sdap_domain_subdom_add(struct sdap_id_ctx *sdap_id_ctx,
+                       struct sdap_domain *sdom_list,
+                       struct sss_domain_info *parent)
+{
+    struct sss_domain_info *dom;
+    struct sdap_domain *sdom, *sditer;
+    char *basedn;
+    errno_t ret;
+
+    for (dom = get_next_domain(parent, true);
+         dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
+         dom = get_next_domain(dom, false)) {
+
+        DLIST_FOR_EACH(sditer, sdom_list) {
+            if (sditer->dom == dom) {
+                break;
+            }
+        }
+
+        if (sditer == NULL) {
+            /* New sdap domain */
+            DEBUG(SSSDBG_TRACE_FUNC, ("subdomain %s is a new one, will "
+                  "create a new sdap domain object\n", dom->name));
+
+            ret = sdap_domain_add(sdap_id_ctx->opts, dom, &sdom);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                    ("Cannot add new sdap domain for domain %s [%d]: %s\n",
+                    parent->name, ret, strerror(ret)));
+                return ret;
+            }
+        } else {
+            sdom = sditer;
+        }
+
+        /* Convert the domain name into search base */
+        ret = domain_to_basedn(sdom, sdom->dom->name, &basedn);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                ("Cannot convert domain name [%s] to base DN [%d]: %s\n",
+                dom->name, ret, strerror(ret)));
+            talloc_free(basedn);
+            return ret;
+        }
+
+        /* Update search bases */
+        talloc_zfree(sdom->search_bases);
+        sdom->search_bases = talloc_array(sdom, struct sdap_search_base *, 2);
+        if (sdom->search_bases == NULL) {
+            return ret;
+        }
+        sdom->search_bases[1] = NULL;
+
+        ret = sdap_create_search_base(sdom, basedn, LDAP_SCOPE_SUBTREE, NULL,
+                                      &sdom->search_bases[0]);
+        talloc_free(basedn);
+        if (ret) {
+            DEBUG(SSSDBG_OP_FAILURE, ("Cannot create new sdap search base\n"));
+            return ret;
+        }
+
+        sdom->user_search_bases = sdom->search_bases;
+        sdom->group_search_bases = sdom->search_bases;
+        sdom->netgroup_search_bases = sdom->search_bases;
+        sdom->sudo_search_bases = sdom->search_bases;
+        sdom->service_search_bases = sdom->search_bases;
+        sdom->autofs_search_bases = sdom->search_bases;
+    }
+
+    return EOK;
+}
+
 void
 sdap_domain_remove(struct sdap_options *opts,
                    struct sss_domain_info *dom)
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index 7a708301152dcbf72c90b11353ebae43a21f51de..db2466ad832d7867d9244a835cde1adab39d347d 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -240,6 +240,10 @@ errno_t msgs2attrs_array(TALLOC_CTX *mem_ctx, size_t count,
 errno_t sdap_domain_add(struct sdap_options *opts,
                         struct sss_domain_info *dom,
                         struct sdap_domain **_sdom);
+errno_t
+sdap_domain_subdom_add(struct sdap_id_ctx *sdap_id_ctx,
+                       struct sdap_domain *sdom_list,
+                       struct sss_domain_info *parent);
 
 void
 sdap_domain_remove(struct sdap_options *opts,
-- 
1.8.3.1

-------------- next part --------------
>From a80ba553b3a7dcaf10d978ab051f9eb4a360e20b Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 19 Jun 2013 13:20:50 +0200
Subject: [PATCH 7/8] IPA: Create and remove AD id_ctx for subdomains
 discovered in server mode

When IPA server mode is on, then this patch will create an ad_id_ctx for
each subdomain discovered in IPA provider. The ID context is needed to
perform direct lookups using the AD provider.

Subtask of:
https://fedorahosted.org/sssd/ticket/1962
---
 src/providers/ipa/ipa_subdomains.c | 182 +++++++++++++++++++++++++++++++++++++
 1 file changed, 182 insertions(+)

diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index 652726dafee563d2b1739c497aa35bdc082d1cff..7910e246699e265d1ddd54c66eca6e7c434df204 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -67,6 +67,7 @@ struct ipa_subdomains_req_params {
 
 struct ipa_subdomains_ctx {
     struct be_ctx *be_ctx;
+    struct ipa_id_ctx *id_ctx;
     struct sdap_id_ctx *sdap_id_ctx;
     struct sdap_search_base **search_bases;
     struct sdap_search_base **master_search_bases;
@@ -92,6 +93,175 @@ struct be_ctx *ipa_get_subdomains_be_ctx(struct be_ctx *be_ctx)
     return subdom_ctx->be_ctx;
 }
 
+static errno_t
+ipa_ad_ctx_new(struct be_ctx *be_ctx,
+               struct ipa_id_ctx *id_ctx,
+               struct sss_domain_info *subdom,
+               struct ad_id_ctx **_ad_id_ctx)
+{
+    struct ad_options *ad_options;
+    struct ad_id_ctx *ad_id_ctx;
+    const char *gc_service_name;
+    errno_t ret;
+
+    ad_options = ad_create_default_options(id_ctx, id_ctx->server_mode->realm,
+                                           id_ctx->server_mode->hostname);
+    if (ad_options == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot initialize AD options\n"));
+        talloc_free(ad_options);
+        return ENOMEM;
+    }
+
+    ret = dp_opt_set_string(ad_options->basic, AD_DOMAIN, subdom->name);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot set AD domain\n"));
+        talloc_free(ad_options);
+        return ret;
+    }
+
+    ret = dp_opt_set_string(ad_options->basic, AD_KRB5_REALM,
+                            id_ctx->server_mode->realm);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot set AD realm\n"));
+        talloc_free(ad_options);
+        return ret;
+    }
+
+    gc_service_name = talloc_asprintf(ad_options, "%s%s", "gc_", subdom->name);
+    if (gc_service_name == NULL) {
+        talloc_free(ad_options);
+        return ENOMEM;
+    }
+
+    /* Set KRB5 realm to same as the one of IPA when IPA
+     * is able to attach PAC. For testing, use hardcoded. */
+    ret = ad_failover_init(ad_options, be_ctx, NULL, NULL,
+                           id_ctx->server_mode->realm,
+                           subdom->name, gc_service_name,
+                           subdom->name, &ad_options->service);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot initialize AD failover\n"));
+        talloc_free(ad_options);
+        return ret;
+    }
+
+    ad_id_ctx = ad_id_ctx_init(ad_options, be_ctx);
+    if (ad_id_ctx == NULL) {
+        talloc_free(ad_options);
+        return ENOMEM;
+    }
+    ad_id_ctx->sdap_id_ctx->opts = ad_options->id;
+    ad_options->id_ctx = ad_id_ctx;
+
+    ret = sdap_domain_subdom_add(ad_id_ctx->sdap_id_ctx,
+                                 ad_id_ctx->sdap_id_ctx->opts->sdom,
+                                 subdom->parent);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot initialize sdap domain\n"));
+        talloc_free(ad_options);
+        return ret;
+    }
+
+    /* Set up the ID mapping object */
+    ad_id_ctx->sdap_id_ctx->opts->idmap_ctx =
+        id_ctx->sdap_id_ctx->opts->idmap_ctx;
+
+    *_ad_id_ctx = ad_id_ctx;
+    return EOK;
+}
+
+static errno_t
+ipa_server_trust_add(struct be_ctx *be_ctx,
+                     struct ipa_id_ctx *id_ctx,
+                     struct sss_domain_info *subdom)
+{
+    struct ipa_ad_server_ctx *trust_ctx;
+    struct ad_id_ctx *ad_id_ctx;
+    errno_t ret;
+
+    ret = ipa_ad_ctx_new(be_ctx, id_ctx, subdom, &ad_id_ctx);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("Cannot create ad_id_ctx for subdomain %s\n", subdom->name));
+        return ret;
+    }
+
+    trust_ctx = talloc(id_ctx->server_mode, struct ipa_ad_server_ctx);
+    if (trust_ctx == NULL) {
+        return ENOMEM;
+    }
+    trust_ctx->dom = subdom;
+    trust_ctx->ad_id_ctx = ad_id_ctx;
+
+    DLIST_ADD(id_ctx->server_mode->trusts, trust_ctx);
+    return EOK;
+}
+
+static errno_t
+ipa_ad_subdom_refresh(struct be_ctx *be_ctx,
+                      struct ipa_id_ctx *id_ctx,
+                      struct sss_domain_info *parent)
+{
+    struct sss_domain_info *dom;
+    struct ipa_ad_server_ctx *trust_iter;
+    errno_t ret;
+
+    if (dp_opt_get_bool(id_ctx->ipa_options->basic,
+                        IPA_SERVER_MODE) == false) {
+        return EOK;
+    }
+
+    for (dom = get_next_domain(parent, true);
+         dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
+         dom = get_next_domain(dom, false)) {
+
+        /* Check if we already have an ID context for this subdomain */
+        DLIST_FOR_EACH(trust_iter, id_ctx->server_mode->trusts) {
+            if (trust_iter->dom == dom) {
+                break;
+            }
+        }
+
+        /* Newly detected trust */
+        if (trust_iter == NULL) {
+            ret = ipa_server_trust_add(be_ctx, id_ctx, dom);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      ("Cannot create ad_id_ctx for subdomain %s\n",
+                       dom->name));
+                continue;
+            }
+        }
+    }
+
+    return EOK;
+}
+
+static void
+ipa_ad_subdom_remove(struct ipa_subdomains_ctx *ctx,
+                     struct sss_domain_info *subdom)
+{
+    struct ipa_ad_server_ctx *iter;
+
+    if (dp_opt_get_bool(ctx->id_ctx->ipa_options->basic,
+                        IPA_SERVER_MODE) == false) {
+        return;
+    }
+
+    DLIST_FOR_EACH(iter, ctx->id_ctx->server_mode->trusts) {
+        if (iter->dom == subdom) break;
+    }
+
+    if (iter == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("No IPA-AD context for subdomain %s\n",
+              subdom->name));
+        return;
+    }
+
+    sdap_domain_remove(iter->ad_id_ctx->sdap_id_ctx->opts, subdom);
+    DLIST_REMOVE(ctx->id_ctx->server_mode->trusts, iter);
+}
+
 const char *get_flat_name_from_subdomain_name(struct be_ctx *be_ctx,
                                               const char *name)
 {
@@ -326,6 +496,9 @@ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
             if (ret != EOK) {
                 goto done;
             }
+
+            /* Remove the AD ID ctx from the list of LDAP domains */
+            ipa_ad_subdom_remove(ctx, dom);
         } else {
             /* ok let's try to update it */
             ret = ipa_subdom_store(domain, ctx->sdap_id_ctx->opts->idmap_ctx,
@@ -600,6 +773,13 @@ static void ipa_subdomains_handler_done(struct tevent_req *req)
             goto done;
         }
 
+        ret = ipa_ad_subdom_refresh(ctx->sd_ctx->be_ctx, ctx->sd_ctx->id_ctx,
+                                    domain);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, ("ipa_ad_subdom_refresh failed.\n"));
+            goto done;
+        }
+
         ret = sss_write_domain_mappings(domain);
         if (ret != EOK) {
             DEBUG(SSSDBG_MINOR_FAILURE,
@@ -904,6 +1084,7 @@ int ipa_subdom_init(struct be_ctx *be_ctx,
     }
 
     ctx->be_ctx = be_ctx;
+    ctx->id_ctx = id_ctx;
     ctx->sdap_id_ctx = id_ctx->sdap_id_ctx;
     ctx->search_bases = id_ctx->ipa_options->subdomains_search_bases;
     ctx->master_search_bases = id_ctx->ipa_options->master_domain_search_bases;
@@ -955,6 +1136,7 @@ int ipa_ad_subdom_init(struct be_ctx *be_ctx,
     }
     id_ctx->server_mode->realm = realm;
     id_ctx->server_mode->hostname = hostname;
+    id_ctx->server_mode->trusts = NULL;
 
     return EOK;
 }
-- 
1.8.3.1

-------------- next part --------------
>From 51770bda0b38ddc52bd9353519012f5fbdebf3d2 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 19 Jun 2013 10:51:19 +0200
Subject: [PATCH 8/8] IPA: Look up AD users directly if IPA server mode is on

https://fedorahosted.org/sssd/ticket/1962

If the ipa_server_mode is selected IPA subdomain user and group lookups
are not done with the help of the extdom plugin but directly against AD
using the AD ID code.
---
 src/providers/ad/ad_id.c              |   4 +-
 src/providers/ad/ad_id.h              |  11 +++
 src/providers/ipa/ipa_common.h        |   1 +
 src/providers/ipa/ipa_id.c            |  23 +++++--
 src/providers/ipa/ipa_id.h            |   9 +++
 src/providers/ipa/ipa_subdomains_id.c | 126 ++++++++++++++++++++++++++++++++++
 6 files changed, 168 insertions(+), 6 deletions(-)

diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
index 9c4abc8c9be5f19ff36d30321dccd66a2d10519d..48ad842590d0a8904744cd5518ac511205416f28 100644
--- a/src/providers/ad/ad_id.c
+++ b/src/providers/ad/ad_id.c
@@ -38,7 +38,7 @@ struct ad_handle_acct_info_state {
 static errno_t ad_handle_acct_info_step(struct tevent_req *req);
 static void ad_handle_acct_info_done(struct tevent_req *subreq);
 
-static struct tevent_req *
+struct tevent_req *
 ad_handle_acct_info_send(TALLOC_CTX *mem_ctx,
                          struct be_req *breq,
                          struct be_acct_req *ar,
@@ -152,7 +152,7 @@ ad_handle_acct_info_done(struct tevent_req *subreq)
     /* Another lookup in progress */
 }
 
-static errno_t
+errno_t
 ad_handle_acct_info_recv(struct tevent_req *req,
                          int *_dp_error, const char **_err)
 {
diff --git a/src/providers/ad/ad_id.h b/src/providers/ad/ad_id.h
index 47fc3b33b21d1a89c96c8497b22b9a42f047471b..1fd6b599a8c42ccf9b68cec6b450a01c5ad80796 100644
--- a/src/providers/ad/ad_id.h
+++ b/src/providers/ad/ad_id.h
@@ -26,6 +26,17 @@
 void
 ad_account_info_handler(struct be_req *breq);
 
+struct tevent_req *
+ad_handle_acct_info_send(TALLOC_CTX *mem_ctx,
+                         struct be_req *breq,
+                         struct be_acct_req *ar,
+                         struct sdap_id_ctx *ctx,
+                         struct sdap_domain *sdom,
+                         struct sdap_id_conn_ctx **conn);
+errno_t
+ad_handle_acct_info_recv(struct tevent_req *req,
+                         int *_dp_error, const char **_err);
+
 void
 ad_check_online(struct be_req *be_req);
 #endif /* AD_ID_H_ */
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index 2af20e1dec3c2d64df563d800b27f95695242759..1afe20dbb1ecb52de8bd6948fe780300d43e4dd3 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -26,6 +26,7 @@
 #include "confdb/confdb.h"
 #include "providers/ldap/ldap_common.h"
 #include "providers/krb5/krb5_common.h"
+#include "providers/ad/ad_common.h"
 
 struct ipa_service {
     struct sdap_service *sdap;
diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
index b11abaa7dbdfdae119d9ec18e1d53538b5382259..6e0964400bf32a138b1ede5edd610f022db41311 100644
--- a/src/providers/ipa/ipa_id.c
+++ b/src/providers/ipa/ipa_id.c
@@ -83,9 +83,15 @@ void ipa_account_info_handler(struct be_req *breq)
     ar = talloc_get_type(be_req_get_data(breq), struct be_acct_req);
 
     if (strcasecmp(ar->domain, be_ctx->domain->name) != 0) {
-        /* if domain names do not match, this is a subdomain case */
-        req = ipa_get_subdom_acct_send(breq, be_ctx->ev, ctx, ar);
-
+        /* if domain names do not match, this is a subdomain case
+         * subdomain lookups are handled differently on the server
+         * and the client
+         */
+        if (dp_opt_get_bool(ipa_ctx->ipa_options->basic, IPA_SERVER_MODE)) {
+            req = ipa_get_ad_acct_send(breq, be_ctx->ev, ipa_ctx, breq, ar);
+        } else {
+            req = ipa_get_subdom_acct_send(breq, be_ctx->ev, ctx, ar);
+        }
     } else if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_NETGROUP) {
         /* netgroups are handled by a separate request function */
         if (ar->filter_type != BE_FILTER_NAME) {
@@ -110,15 +116,24 @@ void ipa_account_info_handler(struct be_req *breq)
 static void ipa_account_info_done(struct tevent_req *req)
 {
     struct be_req *breq = tevent_req_callback_data(req, struct be_req);
+    struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
+    struct ipa_id_ctx *ipa_ctx;
     struct be_acct_req *ar = talloc_get_type(be_req_get_data(breq),
                                              struct be_acct_req);
     const char *error_text;
     int ret, dp_error;
 
+    ipa_ctx = talloc_get_type(be_ctx->bet_info[BET_ID].pvt_bet_data,
+                              struct ipa_id_ctx);
+
     if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_NETGROUP) {
         ret = ipa_id_get_netgroup_recv(req, &dp_error);
     } else {
-        ret = ipa_get_subdom_acct_recv(req, &dp_error);
+        if (dp_opt_get_bool(ipa_ctx->ipa_options->basic, IPA_SERVER_MODE)) {
+            ret = ipa_get_ad_acct_recv(req, &dp_error);
+        } else {
+            ret = ipa_get_subdom_acct_recv(req, &dp_error);
+        }
     }
     talloc_zfree(req);
 
diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
index 7fa25e9270737cc27a961b73828bbc13c75d0cca..6c72f6d0481872bdfecfd07bd06995bd040ee4a7 100644
--- a/src/providers/ipa/ipa_id.h
+++ b/src/providers/ipa/ipa_id.h
@@ -64,4 +64,13 @@ struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx,
                                             struct sdap_id_ctx *ctx,
                                             struct be_acct_req *ar);
 int ipa_get_subdom_acct_recv(struct tevent_req *req, int *dp_error_out);
+
+struct tevent_req *ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
+                                        struct tevent_context *ev,
+                                        struct ipa_id_ctx *ipa_ctx,
+                                        struct be_req *be_req,
+                                        struct be_acct_req *ar);
+
+errno_t ipa_get_ad_acct_recv(struct tevent_req *req, int *dp_error_out);
+
 #endif
diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
index dc822888f2cbb243547341fb537d672d59af7077..6bf97bec0df465ba206181ec59789c0567443432 100644
--- a/src/providers/ipa/ipa_subdomains_id.c
+++ b/src/providers/ipa/ipa_subdomains_id.c
@@ -30,6 +30,7 @@
 #include "providers/ldap/ldap_common.h"
 #include "providers/ldap/sdap_async.h"
 #include "providers/ipa/ipa_id.h"
+#include "providers/ad/ad_id.h"
 #include "providers/ipa/ipa_subdomains.h"
 
 struct ipa_get_subdom_acct {
@@ -246,3 +247,128 @@ int ipa_get_subdom_acct_recv(struct tevent_req *req, int *dp_error_out)
     return EOK;
 }
 
+/* IPA lookup for server mode. Directly to AD. */
+struct ipa_get_ad_acct_state {
+    int dp_error;
+};
+
+static void ipa_get_ad_acct_done(struct tevent_req *subreq);
+static struct ad_id_ctx *ipa_get_ad_id_ctx(struct ipa_id_ctx *ipa_ctx,
+                                           struct sss_domain_info *dom);
+
+struct tevent_req *
+ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
+                     struct tevent_context *ev,
+                     struct ipa_id_ctx *ipa_ctx,
+                     struct be_req *be_req,
+                     struct be_acct_req *ar)
+{
+    errno_t ret;
+    struct tevent_req *req;
+    struct tevent_req *subreq;
+    struct ipa_get_ad_acct_state *state;
+    struct sss_domain_info *dom;
+    struct sdap_domain *sdom;
+    struct sdap_id_conn_ctx **clist;
+    struct sdap_id_ctx *sdap_id_ctx;;
+    struct ad_id_ctx *ad_id_ctx;
+
+    req = tevent_req_create(mem_ctx, &state, struct ipa_get_ad_acct_state);
+    if (req == NULL) return NULL;
+
+    /* This can only be a subdomain request, verify subdomain */
+    dom = find_subdomain_by_name(ipa_ctx->sdap_id_ctx->be->domain,
+                                 ar->domain, true);
+    if (dom == NULL) {
+        ret = EINVAL;
+        goto fail;
+    }
+
+    /* Let's see if this subdomain has a ad_id_ctx */
+    ad_id_ctx = ipa_get_ad_id_ctx(ipa_ctx, dom);
+    if (ad_id_ctx == NULL) {
+        ret = EINVAL;
+        goto fail;
+    }
+    sdap_id_ctx = ad_id_ctx->sdap_id_ctx;
+
+    /* Currently only LDAP port for AD is used because POSIX
+     * attributes are not replicated to GC by default
+     */
+    clist = talloc_zero_array(req, struct sdap_id_conn_ctx *, 2);
+    if (clist == NULL) {
+        ret = ENOMEM;
+        goto fail;
+    }
+    clist[0] = ad_id_ctx->ldap_ctx;
+    clist[1] = NULL;
+
+    /* Now we already need ad_id_ctx in particular sdap_id_conn_ctx */
+    sdom = sdap_domain_get(sdap_id_ctx->opts, dom);
+    if (sdom == NULL) {
+        ret = EIO;
+        goto fail;
+    }
+
+    subreq = ad_handle_acct_info_send(req, be_req, ar, sdap_id_ctx,
+                                      sdom, clist);
+    if (subreq == NULL) {
+        ret = ENOMEM;
+        goto fail;
+    }
+    tevent_req_set_callback(subreq, ipa_get_ad_acct_done, req);
+    return req;
+
+fail:
+    tevent_req_error(req, ret);
+    tevent_req_post(req, ev);
+    return req;
+}
+
+static struct ad_id_ctx *
+ipa_get_ad_id_ctx(struct ipa_id_ctx *ipa_ctx,
+                  struct sss_domain_info *dom)
+{
+    struct ipa_ad_server_ctx *iter;
+
+    DLIST_FOR_EACH(iter, ipa_ctx->server_mode->trusts) {
+        if (iter->dom == dom) break;
+    }
+
+    return iter->ad_id_ctx;
+}
+
+static void
+ipa_get_ad_acct_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                struct tevent_req);
+    struct ipa_get_ad_acct_state *state = tevent_req_data(req,
+                                                struct ipa_get_ad_acct_state);
+    errno_t ret;
+
+    ret = ad_handle_acct_info_recv(subreq, &state->dp_error, NULL);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("AD lookup failed: %d\n", ret));
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    tevent_req_done(req);
+}
+
+errno_t
+ipa_get_ad_acct_recv(struct tevent_req *req, int *dp_error_out)
+{
+    struct ipa_get_ad_acct_state *state = tevent_req_data(req,
+                                                struct ipa_get_ad_acct_state);
+
+    if (dp_error_out) {
+        *dp_error_out = state->dp_error;
+    }
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return EOK;
+}
-- 
1.8.3.1



More information about the sssd-devel mailing list