summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2013-05-15 17:36:44 +0200
committerJakub Hrozek <jhrozek@redhat.com>2013-06-07 00:14:13 +0200
commit55d80b1301fe969fb4ba2b9481027887b9462dbb (patch)
tree7f4f7fdc4a1f913c08506452450ac2972b01acdb
parentd27d7f2c270b69d0805633c4bedcf6d806acd5cd (diff)
downloadsssd-55d80b1301fe969fb4ba2b9481027887b9462dbb.tar.gz
sssd-55d80b1301fe969fb4ba2b9481027887b9462dbb.tar.xz
sssd-55d80b1301fe969fb4ba2b9481027887b9462dbb.zip
AD: Add additional service to support Global Catalog lookups
When fixed host names of AD servers are configured in the config file, we can't know (unlike when service discovery is at play) if the servers are Global Catalogs or not. This patch adds a private data to servers read from the config file that denote whether the server can be tried for contacting the Global Catalog port or just LDAP. The GC or LDAP URIs are generated based on contents of this private data structure. Because SSSD sticks to a working server, we don't have to disable or remove the faulty GC servers from the list.
-rw-r--r--src/providers/ad/ad_common.c190
-rw-r--r--src/providers/ad/ad_common.h5
-rw-r--r--src/providers/ad/ad_init.c16
3 files changed, 178 insertions, 33 deletions
diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index 713f31947..ea124d96d 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -25,6 +25,10 @@
#include "providers/ad/ad_opts.h"
#include "providers/dp_dyndns.h"
+struct ad_server_data {
+ bool gc;
+};
+
errno_t
ad_get_common_options(TALLOC_CTX *mem_ctx,
struct confdb_ctx *cdb,
@@ -142,6 +146,7 @@ ad_resolve_callback(void *private_data, struct fo_server *server);
static errno_t
_ad_servers_init(TALLOC_CTX *mem_ctx,
+ struct ad_service *service,
struct be_ctx *bectx,
const char *servers,
struct ad_options *options,
@@ -151,6 +156,7 @@ _ad_servers_init(TALLOC_CTX *mem_ctx,
errno_t ret = 0;
char **list;
char *ad_domain;
+ struct ad_server_data *sdata;
TALLOC_CTX *tmp_ctx;
tmp_ctx = talloc_new(NULL);
@@ -176,9 +182,33 @@ _ad_servers_init(TALLOC_CTX *mem_ctx,
continue;
}
+ sdata = talloc(service, struct ad_server_data);
+ if (sdata == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ sdata->gc = true;
+
+ ret = be_fo_add_srv_server(bectx, AD_SERVICE_NAME, "gc",
+ ad_domain, BE_FO_PROTO_TCP,
+ false, sdata);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ ("Failed to add service discovery to failover: [%s]",
+ strerror(ret)));
+ goto done;
+ }
+
+ sdata = talloc(service, struct ad_server_data);
+ if (sdata == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ sdata->gc = false;
+
ret = be_fo_add_srv_server(bectx, AD_SERVICE_NAME, "ldap",
ad_domain, BE_FO_PROTO_TCP,
- false, NULL);
+ false, sdata);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,
("Failed to add service discovery to failover: [%s]",
@@ -197,7 +227,27 @@ _ad_servers_init(TALLOC_CTX *mem_ctx,
goto done;
}
- ret = be_fo_add_server(bectx, AD_SERVICE_NAME, list[i], 0, NULL, primary);
+ sdata = talloc(service, struct ad_server_data);
+ if (sdata == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ sdata->gc = true;
+
+ ret = be_fo_add_server(bectx, AD_SERVICE_NAME, list[i], 0, sdata, primary);
+ if (ret && ret != EEXIST) {
+ DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to add server\n"));
+ goto done;
+ }
+
+ sdata = talloc(service, struct ad_server_data);
+ if (sdata == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ sdata->gc = false;
+
+ ret = be_fo_add_server(bectx, AD_SERVICE_NAME, list[i], 0, sdata, primary);
if (ret && ret != EEXIST) {
DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to add server\n"));
goto done;
@@ -211,22 +261,53 @@ done:
}
static inline errno_t
-ad_primary_servers_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
- const char *servers, struct ad_options *options)
+ad_primary_servers_init(TALLOC_CTX *mem_ctx, struct ad_service *service,
+ struct be_ctx *bectx, const char *servers,
+ struct ad_options *options)
{
- return _ad_servers_init(mem_ctx, bectx, servers, options, true);
+ return _ad_servers_init(mem_ctx, service, bectx, servers, options, true);
}
static inline errno_t
-ad_backup_servers_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
- const char *servers, struct ad_options *options)
+ad_backup_servers_init(TALLOC_CTX *mem_ctx, struct ad_service *service,
+ struct be_ctx *bectx, const char *servers,
+ struct ad_options *options)
{
- return _ad_servers_init(mem_ctx, bectx, servers, options, false);
+ return _ad_servers_init(mem_ctx, service, bectx, servers, options, false);
}
static int ad_user_data_cmp(void *ud1, void *ud2)
{
- return strcasecmp((char*) ud1, (char*) ud2);
+ struct ad_server_data *sd1, *sd2;
+
+ sd1 = talloc_get_type(ud1, struct ad_server_data);
+ sd2 = talloc_get_type(ud2, struct ad_server_data);
+ if (sd1 == NULL || sd2 == NULL) {
+ DEBUG(SSSDBG_TRACE_FUNC, ("No user data\n"));
+ return sd1 == sd2 ? 0 : 1;
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS, ("Comparing %s with %s\n",
+ sd1->gc ? "GC" : "LDAP",
+ sd2->gc ? "GC" : "LDAP"));
+
+ if (sd1->gc == sd2->gc) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static void ad_online_cb(void *pvt)
+{
+ struct ad_service *service = talloc_get_type(pvt, struct ad_service);
+
+ if (service == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid private pointer\n"));
+ return;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, ("The AD provider is online\n"));
}
errno_t
@@ -251,7 +332,15 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
}
service->sdap = talloc_zero(service, struct sdap_service);
- if (!service->sdap) {
+ service->gc = talloc_zero(service, struct sdap_service);
+ if (!service->sdap || !service->gc) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ service->sdap->name = talloc_strdup(service->sdap, AD_SERVICE_NAME);
+ service->gc->name = talloc_strdup(service->gc, AD_SERVICE_NAME);
+ if (!service->sdap->name || !service->gc->name) {
ret = ENOMEM;
goto done;
}
@@ -268,18 +357,14 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
goto done;
}
- service->sdap->name = talloc_strdup(service, AD_SERVICE_NAME);
- if (!service->sdap->name) {
- ret = ENOMEM;
- goto done;
- }
-
- service->krb5_service->name = talloc_strdup(service, AD_SERVICE_NAME);
+ service->krb5_service->name = talloc_strdup(service->krb5_service,
+ AD_SERVICE_NAME);
if (!service->krb5_service->name) {
ret = ENOMEM;
goto done;
}
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) {
@@ -300,18 +385,26 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
primary_servers = BE_SRV_IDENTIFIER;
}
- ret = ad_primary_servers_init(mem_ctx, bectx, primary_servers, options);
+ ret = ad_primary_servers_init(mem_ctx, service, bectx,
+ primary_servers, options);
if (ret != EOK) {
goto done;
}
if (backup_servers) {
- ret = ad_backup_servers_init(mem_ctx, bectx, backup_servers, options);
+ ret = ad_backup_servers_init(mem_ctx, service, bectx,
+ backup_servers, options);
if (ret != EOK) {
goto done;
}
}
+ ret = be_add_online_cb(bectx, bectx, ad_online_cb, service, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Could not set up AD online callback\n"));
+ return ret;
+ }
+
ret = be_fo_service_add_callback(mem_ctx, bectx, AD_SERVICE_NAME,
ad_resolve_callback, service);
if (ret != EOK) {
@@ -341,6 +434,7 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
const char *safe_address;
char *new_uri;
const char *srv_name;
+ struct ad_server_data *sdata = NULL;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
@@ -348,6 +442,12 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
return;
}
+ sdata = fo_get_server_user_data(server);
+ if (fo_is_srv_lookup(server) == false && sdata == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("No user data?\n"));
+ return;
+ }
+
service = talloc_get_type(private_data, struct ad_service);
if (!service) {
ret = EINVAL;
@@ -363,13 +463,6 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
goto done;
}
- sockaddr = resolv_get_sockaddr_address(tmp_ctx, srvaddr, LDAP_PORT);
- if (sockaddr == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, ("resolv_get_sockaddr_address failed.\n"));
- ret = EIO;
- goto done;
- }
-
address = resolv_get_string_address(tmp_ctx, srvaddr);
if (address == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, ("resolv_get_string_address failed.\n"));
@@ -384,7 +477,7 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
goto done;
}
- new_uri = talloc_asprintf(service, "ldap://%s", srv_name);
+ new_uri = talloc_asprintf(service->sdap, "ldap://%s", srv_name);
if (!new_uri) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to copy URI\n"));
ret = ENOMEM;
@@ -392,12 +485,53 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
}
DEBUG(SSSDBG_CONF_SETTINGS, ("Constructed uri '%s'\n", new_uri));
+ sockaddr = resolv_get_sockaddr_address(tmp_ctx, srvaddr, LDAP_PORT);
+ if (sockaddr == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("resolv_get_sockaddr_address failed.\n"));
+ ret = EIO;
+ goto done;
+ }
+
/* free old one and replace with new one */
talloc_zfree(service->sdap->uri);
service->sdap->uri = new_uri;
talloc_zfree(service->sdap->sockaddr);
- service->sdap->sockaddr = talloc_steal(service, sockaddr);
+ service->sdap->sockaddr = talloc_steal(service->sdap, sockaddr);
+
+ talloc_zfree(service->gc->uri);
+ talloc_zfree(service->gc->sockaddr);
+ if (sdata && sdata->gc) {
+ service->gc->uri = talloc_asprintf(service->gc, "%s:%d",
+ new_uri, AD_GC_PORT);
+
+ service->gc->sockaddr = resolv_get_sockaddr_address(service->gc,
+ srvaddr,
+ AD_GC_PORT);
+ } else {
+ /* Make sure there always is an URI even if we know that this
+ * server doesn't support GC. That way the lookup would go through
+ * just not return anything
+ */
+ service->gc->uri = talloc_strdup(service->gc, service->sdap->uri);
+ service->gc->sockaddr = talloc_memdup(service->gc, service->sdap->sockaddr,
+ sizeof(struct sockaddr_storage));
+ }
+
+ if (!service->gc->uri) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to append to URI\n"));
+ ret = ENOMEM;
+ goto done;
+ }
+ DEBUG(SSSDBG_CONF_SETTINGS, ("Constructed GC uri '%s'\n", service->gc->uri));
+
+ if (service->gc->sockaddr == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("resolv_get_sockaddr_address failed.\n"));
+ ret = EIO;
+ goto done;
+ }
+ /* Write krb5 info files */
safe_address = sss_escape_ip_address(tmp_ctx,
srvaddr->family,
address);
diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
index 792f32e08..801815528 100644
--- a/src/providers/ad/ad_common.h
+++ b/src/providers/ad/ad_common.h
@@ -27,6 +27,8 @@
#include "providers/ldap/ldap_common.h"
#define AD_SERVICE_NAME "AD"
+/* The port the Global Catalog runs on */
+#define AD_GC_PORT 3268
struct ad_options;
@@ -44,11 +46,14 @@ enum ad_basic_opt {
struct ad_id_ctx {
struct sdap_id_ctx *sdap_id_ctx;
+ struct sdap_id_conn_ctx *ldap_ctx;
+ struct sdap_id_conn_ctx *gc_ctx;
struct ad_options *ad_options;
};
struct ad_service {
struct sdap_service *sdap;
+ struct sdap_service *gc;
struct krb5_service *krb5_service;
};
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index aada14ec7..cb73aca3a 100644
--- a/src/providers/ad/ad_init.c
+++ b/src/providers/ad/ad_init.c
@@ -140,6 +140,12 @@ sssm_ad_id_init(struct be_ctx *bectx,
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 (sdap_ctx == NULL) {
+ return ENOMEM;
+ }
ret = ad_dyndns_init(sdap_ctx->be, ad_options);
if (ret != EOK) {
@@ -148,11 +154,6 @@ sssm_ad_id_init(struct be_ctx *bectx,
/* Continue without DNS updates */
}
- ret = sdap_id_setup_tasks(sdap_ctx);
- if (ret != EOK) {
- goto done;
- }
-
ret = sdap_setup_child();
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,
@@ -169,6 +170,11 @@ sssm_ad_id_init(struct be_ctx *bectx,
goto done;
}
+ ret = sdap_id_setup_tasks(sdap_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);
if (ret != EOK) goto done;