ad_common.c revision bb4172259e04925ffc3a92e4450029634d295134
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco/*
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco SSSD
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco Authors:
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco Stephen Gallagher <sgallagh@redhat.com>
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco Copyright (C) 2012 Red Hat
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco This program is free software; you can redistribute it and/or modify
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco it under the terms of the GNU General Public License as published by
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco the Free Software Foundation; either version 3 of the License, or
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco (at your option) any later version.
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco This program is distributed in the hope that it will be useful,
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco but WITHOUT ANY WARRANTY; without even the implied warranty of
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco GNU General Public License for more details.
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco You should have received a copy of the GNU General Public License
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco along with this program. If not, see <http://www.gnu.org/licenses/>.
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco*/
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco#include <ctype.h>
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco#include "providers/ad/ad_common.h"
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco#include "providers/ad/ad_opts.h"
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco#include "providers/dp_dyndns.h"
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Koscostruct ad_server_data {
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco bool gc;
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco};
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Koscoerrno_t
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Koscoad_get_common_options(TALLOC_CTX *mem_ctx,
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco struct confdb_ctx *cdb,
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco const char *conf_path,
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco struct sss_domain_info *dom,
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco struct ad_options **_opts)
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco{
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco errno_t ret;
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco int gret;
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco struct ad_options *opts = NULL;
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco char *domain;
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco char *server;
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco char *realm;
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco char *ad_hostname;
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco char hostname[HOST_NAME_MAX + 1];
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco opts = talloc_zero(mem_ctx, struct ad_options);
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco if (!opts) return ENOMEM;
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco ret = dp_get_options(opts, cdb, conf_path,
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco ad_basic_opts,
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco AD_OPTS_BASIC,
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco &opts->basic);
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco if (ret != EOK) {
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco goto done;
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco }
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco /* If the AD domain name wasn't explicitly set, assume that it
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco * matches the SSSD domain name
*/
domain = dp_opt_get_string(opts->basic, AD_DOMAIN);
if (!domain) {
ret = dp_opt_set_string(opts->basic, AD_DOMAIN, dom->name);
if (ret != EOK) {
goto done;
}
domain = dom->name;
}
/* Did we get an explicit server name, or are we discovering it? */
server = dp_opt_get_string(opts->basic, AD_SERVER);
if (!server) {
DEBUG(SSSDBG_CONF_SETTINGS,
("No AD server set, will use service discovery!\n"));
}
/* Set the machine's hostname to the local host name if it
* wasn't explicitly specified.
*/
ad_hostname = dp_opt_get_string(opts->basic, AD_HOSTNAME);
if (ad_hostname == NULL) {
gret = gethostname(hostname, HOST_NAME_MAX);
if (gret != 0) {
ret = errno;
DEBUG(SSSDBG_FATAL_FAILURE,
("gethostname failed [%s].\n",
strerror(ret)));
goto done;
}
hostname[HOST_NAME_MAX] = '\0';
DEBUG(SSSDBG_CONF_SETTINGS,
("Setting ad_hostname to [%s].\n", hostname));
ret = dp_opt_set_string(opts->basic, AD_HOSTNAME, hostname);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,
("Setting ad_hostname failed [%s].\n",
strerror(ret)));
goto done;
}
}
/* Always use the upper-case AD domain for the kerberos realm */
realm = get_uppercase_realm(opts, domain);
if (!realm) {
ret = ENOMEM;
goto done;
}
ret = dp_opt_set_string(opts->basic, AD_KRB5_REALM, realm);
if (ret != EOK) {
goto done;
}
/* Active Directory is always case-insensitive */
dom->case_sensitive = false;
/* Set this in the confdb so that the responders pick it
* up when they start up.
*/
ret = confdb_set_bool(cdb, conf_path, "case_sensitive",
dom->case_sensitive);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Could not set domain case-sensitive: [%s]\n",
strerror(ret)));
goto done;
}
DEBUG(SSSDBG_CONF_SETTINGS,
("Setting domain case-insensitive\n"));
ret = EOK;
*_opts = opts;
done:
if (ret != EOK) {
talloc_zfree(opts);
}
return ret;
}
static void
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,
bool primary)
{
size_t i;
errno_t ret = 0;
char **list;
char *ad_domain;
struct ad_server_data *sdata;
TALLOC_CTX *tmp_ctx;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return ENOMEM;
/* Split the server list */
ret = split_on_separator(tmp_ctx, servers, ',', true, true, &list, NULL);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to parse server list!\n"));
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])) {
if (!primary) {
DEBUG(SSSDBG_MINOR_FAILURE,
("Failed to add server [%s] to failover service: "
"SRV resolution only allowed for primary servers!\n",
list[i]));
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, sdata);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,
("Failed to add service discovery to failover: [%s]",
strerror(ret)));
goto done;
}
DEBUG(SSSDBG_CONF_SETTINGS, ("Added service discovery for AD\n"));
continue;
}
/* It could be ipv6 address in square brackets. Remove
* the brackets if needed. */
ret = remove_ipv6_brackets(list[i]);
if (ret != EOK) {
goto done;
}
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;
}
DEBUG(SSSDBG_CONF_SETTINGS, ("Added failover server %s\n", list[i]));
}
done:
talloc_free(tmp_ctx);
return ret;
}
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)
{
return _ad_servers_init(mem_ctx, service, bectx, servers, options, 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)
{
return _ad_servers_init(mem_ctx, service, bectx, servers, options, false);
}
static int ad_user_data_cmp(void *ud1, void *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
ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
const char *primary_servers,
const char *backup_servers,
struct ad_options *options,
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;
service = talloc_zero(tmp_ctx, struct ad_service);
if (!service) {
ret = ENOMEM;
goto done;
}
service->sdap = talloc_zero(service, struct sdap_service);
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;
}
service->krb5_service = talloc_zero(service, struct krb5_service);
if (!service->krb5_service) {
ret = ENOMEM;
goto done;
}
ret = be_fo_add_service(bectx, AD_SERVICE_NAME, ad_user_data_cmp);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to create failover service!\n"));
goto done;
}
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) {
DEBUG(SSSDBG_CRIT_FAILURE, ("No Kerberos realm set\n"));
ret = EINVAL;
goto done;
}
service->krb5_service->realm =
talloc_strdup(service->krb5_service, realm);
if (!service->krb5_service->realm) {
ret = ENOMEM;
goto done;
}
if (!primary_servers) {
DEBUG(SSSDBG_CONF_SETTINGS,
("No primary servers defined, using service discovery\n"));
primary_servers = BE_SRV_IDENTIFIER;
}
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, 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) {
DEBUG(SSSDBG_FATAL_FAILURE,
("Failed to add failover callback! [%s]\n", strerror(ret)));
goto done;
}
*_service = talloc_steal(mem_ctx, service);
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
static void
ad_resolve_callback(void *private_data, struct fo_server *server)
{
errno_t ret;
TALLOC_CTX *tmp_ctx;
struct ad_service *service;
struct resolv_hostent *srvaddr;
struct sockaddr_storage *sockaddr;
char *address;
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) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\n"));
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;
goto done;
}
srvaddr = fo_get_server_hostent(server);
if (!srvaddr) {
DEBUG(SSSDBG_CRIT_FAILURE,
("No hostent available for server (%s)\n",
fo_get_server_str_name(server)));
ret = EINVAL;
goto done;
}
address = resolv_get_string_address(tmp_ctx, srvaddr);
if (address == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, ("resolv_get_string_address failed.\n"));
ret = EIO;
goto done;
}
srv_name = fo_get_server_name(server);
if (srv_name == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Could not get server host name\n"));
ret = EINVAL;
goto done;
}
new_uri = talloc_asprintf(service->sdap, "ldap://%s", srv_name);
if (!new_uri) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to copy URI\n"));
ret = ENOMEM;
goto done;
}
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->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;
}
if (service->krb5_service->write_kdcinfo) {
/* Write krb5 info files */
safe_address = sss_escape_ip_address(tmp_ctx,
srvaddr->family,
address);
if (safe_address == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, ("sss_escape_ip_address failed.\n"));
ret = ENOMEM;
goto done;
}
ret = write_krb5info_file(service->krb5_service->realm, safe_address,
SSS_KRB5KDC_FO_SRV);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
("write_krb5info_file failed, authentication might fail.\n"));
}
}
ret = EOK;
done:
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Error: [%s]\n", strerror(ret)));
}
talloc_free(tmp_ctx);
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)
{
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.
*/
ret = dp_opt_set_string(id_opts->basic,
SDAP_PWD_POLICY,
PWD_POL_OPT_MIT);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE, ("Could not set password policy\n"));
goto done;
}
/* Set the Kerberos Realm for GSSAPI */
krb5_realm = dp_opt_get_string(ad_opts->basic, AD_KRB5_REALM);
if (!krb5_realm) {
/* Should be impossible, this is set in ad_get_common_options() */
DEBUG(SSSDBG_FATAL_FAILURE, ("No Kerberos realm\n"));
ret = EINVAL;
goto done;
}
ret = dp_opt_set_string(id_opts->basic, SDAP_KRB5_REALM, krb5_realm);
if (ret != EOK) goto done;
DEBUG(SSSDBG_CONF_SETTINGS,
("Option %s set to %s\n",
id_opts->basic[SDAP_KRB5_REALM].opt_name,
krb5_realm));
keytab_path = dp_opt_get_string(ad_opts->basic, AD_KEYTAB);
if (keytab_path) {
ret = dp_opt_set_string(id_opts->basic, SDAP_KRB5_KEYTAB,
keytab_path);
if (ret != EOK) goto done;
DEBUG(SSSDBG_CONF_SETTINGS,
("Option %s set to %s\n",
id_opts->basic[SDAP_KRB5_KEYTAB].opt_name,
keytab_path));
}
ret = sdap_set_sasl_options(id_opts,
dp_opt_get_string(ad_opts->basic,
AD_HOSTNAME),
dp_opt_get_string(ad_opts->basic,
AD_KRB5_REALM),
keytab_path);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("Cannot set the SASL-related options\n"));
goto done;
}
/* fix schema to AD */
id_opts->schema_type = SDAP_SCHEMA_AD;
/* 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;
}
ad_opts->id = talloc_steal(ad_opts, id_opts);
*_opts = id_opts;
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
errno_t
ad_set_search_bases(struct sdap_options *id_opts)
{
errno_t ret;
char *default_search_base;
size_t o;
const int search_base_options[] = { SDAP_USER_SEARCH_BASE,
SDAP_GROUP_SEARCH_BASE,
SDAP_NETGROUP_SEARCH_BASE,
SDAP_SERVICE_SEARCH_BASE,
-1 };
/* AD servers provide defaultNamingContext, so we will
* rely on that to specify the search base unless it has
* been specifically overridden.
*/
default_search_base =
dp_opt_get_string(id_opts->basic, SDAP_SEARCH_BASE);
if (default_search_base) {
/* set search bases if they are not */
for (o = 0; search_base_options[o] != -1; o++) {
if (NULL == dp_opt_get_string(id_opts->basic,
search_base_options[o])) {
ret = dp_opt_set_string(id_opts->basic,
search_base_options[o],
default_search_base);
if (ret != EOK) {
goto done;
}
DEBUG(SSSDBG_CONF_SETTINGS,
("Option %s set to %s\n",
id_opts->basic[search_base_options[o]].opt_name,
dp_opt_get_string(id_opts->basic,
search_base_options[o])));
}
}
} else {
DEBUG(SSSDBG_CONF_SETTINGS,
("Search base not set. SSSD will attempt to discover it later, "
"when connecting to the LDAP server.\n"));
}
/* Default search */
ret = sdap_parse_search_base(id_opts, id_opts->basic,
SDAP_SEARCH_BASE,
&id_opts->sdom->search_bases);
if (ret != EOK && ret != ENOENT) goto done;
/* User search */
ret = sdap_parse_search_base(id_opts, id_opts->basic,
SDAP_USER_SEARCH_BASE,
&id_opts->sdom->user_search_bases);
if (ret != EOK && ret != ENOENT) goto done;
/* Group search base */
ret = sdap_parse_search_base(id_opts, id_opts->basic,
SDAP_GROUP_SEARCH_BASE,
&id_opts->sdom->group_search_bases);
if (ret != EOK && ret != ENOENT) goto done;
/* Netgroup search */
ret = sdap_parse_search_base(id_opts, id_opts->basic,
SDAP_NETGROUP_SEARCH_BASE,
&id_opts->sdom->netgroup_search_bases);
if (ret != EOK && ret != ENOENT) goto done;
/* Service search */
ret = sdap_parse_search_base(id_opts, id_opts->basic,
SDAP_SERVICE_SEARCH_BASE,
&id_opts->sdom->service_search_bases);
if (ret != EOK && ret != ENOENT) goto done;
ret = EOK;
done:
return ret;
}
errno_t
ad_get_auth_options(TALLOC_CTX *mem_ctx,
struct ad_options *ad_opts,
struct be_ctx *bectx,
struct dp_option **_opts)
{
errno_t ret;
struct dp_option *krb5_options;
const char *ad_servers;
const char *krb5_realm;
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return ENOMEM;
/* Get krb5 options */
ret = dp_get_options(tmp_ctx, bectx->cdb, bectx->conf_path,
ad_def_krb5_opts, KRB5_OPTS,
&krb5_options);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Could not read Kerberos options from the configuration\n"));
goto done;
}
ad_servers = dp_opt_get_string(ad_opts->basic, AD_SERVER);
/* Force the krb5_servers to match the ad_servers */
ret = dp_opt_set_string(krb5_options, KRB5_KDC, ad_servers);
if (ret != EOK) goto done;
DEBUG(SSSDBG_CONF_SETTINGS,
("Option %s set to %s\n",
krb5_options[KRB5_KDC].opt_name,
ad_servers));
/* Set krb5 realm */
/* Set the Kerberos Realm for GSSAPI */
krb5_realm = dp_opt_get_string(ad_opts->basic, AD_KRB5_REALM);
if (!krb5_realm) {
/* Should be impossible, this is set in ad_get_common_options() */
DEBUG(SSSDBG_FATAL_FAILURE, ("No Kerberos realm\n"));
ret = EINVAL;
goto done;
}
/* Force the kerberos realm to match the AD_KRB5_REALM (which may have
* been upper-cased in ad_common_options()
*/
ret = dp_opt_set_string(krb5_options, KRB5_REALM, krb5_realm);
if (ret != EOK) goto done;
DEBUG(SSSDBG_CONF_SETTINGS,
("Option %s set to %s\n",
krb5_options[KRB5_REALM].opt_name,
krb5_realm));
/* Set flag that controls whether we want to write the
* kdcinfo files at all
*/
ad_opts->service->krb5_service->write_kdcinfo = \
dp_opt_get_bool(krb5_options, KRB5_USE_KDCINFO);
DEBUG(SSSDBG_CONF_SETTINGS, ("Option %s set to %s\n",
krb5_options[KRB5_USE_KDCINFO].opt_name,
ad_opts->service->krb5_service->write_kdcinfo ? "true" : "false"));
*_opts = talloc_steal(mem_ctx, krb5_options);
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
errno_t ad_get_dyndns_options(struct be_ctx *be_ctx,
struct ad_options *ad_opts)
{
errno_t ret;
ret = be_nsupdate_init(ad_opts, be_ctx, ad_dyndns_opts,
&ad_opts->dyndns_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
("Cannot initialize AD dyndns opts [%d]: %s\n",
ret, sss_strerror(ret)));
return ret;
}
return EOK;
}