diff options
Diffstat (limited to 'src/providers')
-rw-r--r-- | src/providers/ad/ad_common.c | 600 | ||||
-rw-r--r-- | src/providers/ad/ad_common.h | 85 | ||||
-rw-r--r-- | src/providers/ad/ad_id.c | 37 | ||||
-rw-r--r-- | src/providers/ad/ad_id.h | 29 | ||||
-rw-r--r-- | src/providers/ad/ad_init.c | 184 | ||||
-rw-r--r-- | src/providers/ad/ad_opts.h | 230 |
6 files changed, 1165 insertions, 0 deletions
diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c new file mode 100644 index 00000000..92cd40ec --- /dev/null +++ b/src/providers/ad/ad_common.c @@ -0,0 +1,600 @@ +/* + SSSD + + Authors: + Stephen Gallagher <sgallagh@redhat.com> + + Copyright (C) 2012 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#include <ctype.h> + +#include "providers/ad/ad_common.h" +#include "providers/ad/ad_opts.h" + +errno_t +ad_get_common_options(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *conf_path, + struct sss_domain_info *dom, + struct ad_options **_opts) +{ + errno_t ret; + int gret; + size_t i; + struct ad_options *opts = NULL; + char *domain; + char *server; + char *realm; + char *ad_hostname; + char hostname[HOST_NAME_MAX + 1]; + + opts = talloc_zero(mem_ctx, struct ad_options); + if (!opts) return ENOMEM; + + ret = dp_get_options(opts, cdb, conf_path, + ad_basic_opts, + AD_OPTS_BASIC, + &opts->basic); + if (ret != EOK) { + goto done; + } + + /* If the AD domain name wasn't explicitly set, assume that it + * 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 = talloc_strdup(opts, domain); + if (!realm) { + ret = ENOMEM; + goto done; + } + + for (i = 0; realm[i]; i++) { + realm[i] = toupper(realm[i]); + } + + ret = dp_opt_set_string(opts->basic, AD_KRB5_REALM, realm); + if (ret != EOK) { + goto done; + } + + 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); + +errno_t +ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx, + const char *servers, + struct ad_options *options, + struct ad_service **_service) +{ + errno_t ret; + TALLOC_CTX *tmp_ctx; + struct ad_service *service; + char *ad_domain; + char *realm; + char **list; + size_t i; + + 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); + if (!service->sdap) { + 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); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to create failover service!\n")); + 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); + if (!service->krb5_service->name) { + ret = ENOMEM; + goto done; + } + service->sdap->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 (!servers) { + servers = BE_SRV_IDENTIFIER; + } + + /* Split the server list */ + ret = split_on_separator(tmp_ctx, servers, ',', 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])) { + ret = be_fo_add_srv_server(bectx, AD_SERVICE_NAME, "ldap", + ad_domain, BE_FO_PROTO_TCP, + false, NULL); + 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; + } + + ret = be_fo_add_server(bectx, AD_SERVICE_NAME, list[i], 0, NULL); + 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])); + } + + 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; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\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; + } + + 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")); + 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, "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)); + + /* 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); + + 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 *sasl_primary; + char *desired_primary; + char *sasl_realm; + char *desired_realm; + char *keytab_path; + bool primary_requested = true; + bool realm_requested = true; + + 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 = 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)); + + /* Configuration of SASL auth ID and realm */ + desired_primary = dp_opt_get_string(id_opts->basic, SDAP_SASL_AUTHID); + if (!desired_primary) { + primary_requested = false; + desired_primary = dp_opt_get_string(ad_opts->basic, AD_HOSTNAME); + } + + desired_realm = dp_opt_get_string(id_opts->basic, SDAP_SASL_REALM); + if (!desired_realm) { + realm_requested = false; + desired_realm = dp_opt_get_string(ad_opts->basic, AD_KRB5_REALM); + } + + keytab_path = dp_opt_get_string(id_opts->basic, SDAP_KRB5_KEYTAB); + /* It's okay if this is NULL here */ + + ret = select_principal_from_keytab(tmp_ctx, + desired_primary, desired_realm, + keytab_path, NULL, + &sasl_primary, &sasl_realm); + if (ret != EOK) goto done; + + if ((primary_requested && strcmp(desired_primary, sasl_primary) != 0) || + (realm_requested && strcmp(desired_realm, sasl_realm) != 0)) { + DEBUG(SSSDBG_FATAL_FAILURE, + ("Configured SASL auth ID/realm not found in keytab.\n")); + ret = ENOENT; + goto done; + } + + ret = dp_opt_set_string(id_opts->basic, SDAP_SASL_AUTHID, sasl_primary); + if (ret != EOK) goto done; + DEBUG(SSSDBG_CONF_SETTINGS, + ("Option %s set to %s\n", + id_opts->basic[SDAP_SASL_AUTHID].opt_name, + sasl_primary)); + + ret = dp_opt_set_string(id_opts->basic, SDAP_SASL_REALM, sasl_realm); + if (ret != EOK) goto done; + DEBUG(SSSDBG_CONF_SETTINGS, + ("Option %s set to %s\n", + id_opts->basic[SDAP_SASL_REALM].opt_name, + sasl_realm)); + + /* 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->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->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->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->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->service_search_bases); + if (ret != EOK && ret != ENOENT) goto done; + + ret = EOK; +done: + return ret; +} diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h new file mode 100644 index 00000000..fefb67b6 --- /dev/null +++ b/src/providers/ad/ad_common.h @@ -0,0 +1,85 @@ +/* + SSSD + + Authors: + Stephen Gallagher <sgallagh@redhat.com> + + Copyright (C) 2012 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef AD_COMMON_H_ +#define AD_COMMON_H_ + +#include "util/util.h" +#include "providers/ldap/ldap_common.h" + +#define AD_SERVICE_NAME "AD" + +struct ad_options; + +enum ad_basic_opt { + AD_DOMAIN = 0, + AD_SERVER, + AD_HOSTNAME, + AD_KRB5_REALM, + + AD_OPTS_BASIC /* opts counter */ +}; + +struct ad_id_ctx { + struct sdap_id_ctx *sdap_id_ctx; + struct ad_options *ad_options; +}; + +struct ad_service { + struct sdap_service *sdap; + struct krb5_service *krb5_service; +}; + +struct ad_options { + /* Common options */ + struct dp_option *basic; + struct ad_service *service; + + /* ID Provider */ + struct sdap_options *id; + struct ad_id_ctx *id_ctx; + + /* Auth and chpass Provider */ + struct dp_option *auth; + struct ad_auth_ctx *auth_ctx; +}; + +errno_t +ad_get_common_options(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *conf_path, + struct sss_domain_info *dom, + struct ad_options **_opts); + +errno_t +ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *ctx, + const char *servers, + struct ad_options *options, + struct ad_service **_service); + +errno_t +ad_get_id_options(struct ad_options *ad_opts, + struct confdb_ctx *cdb, + const char *conf_path, + struct sdap_options **_opts); + +#endif /* AD_COMMON_H_ */ diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c new file mode 100644 index 00000000..41510b24 --- /dev/null +++ b/src/providers/ad/ad_id.c @@ -0,0 +1,37 @@ +/* + SSSD + + Authors: + Stephen Gallagher <sgallagh@redhat.com> + + Copyright (C) 2012 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "util/util.h" +#include "providers/ad/ad_common.h" +#include "providers/ad/ad_id.h" + +void +ad_account_info_handler(struct be_req *breq) +{ + struct ad_id_ctx *ad_ctx; + struct sdap_id_ctx *sdap_id_ctx; + + ad_ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data, + struct ad_id_ctx); + sdap_id_ctx = ad_ctx->sdap_id_ctx; + + return sdap_handle_account_info(breq, sdap_id_ctx); +} diff --git a/src/providers/ad/ad_id.h b/src/providers/ad/ad_id.h new file mode 100644 index 00000000..7f480aab --- /dev/null +++ b/src/providers/ad/ad_id.h @@ -0,0 +1,29 @@ +/* + SSSD + + Authors: + Stephen Gallagher <sgallagh@redhat.com> + + Copyright (C) 2012 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef AD_ID_H_ +#define AD_ID_H_ + +void +ad_account_info_handler(struct be_req *breq); + +#endif /* AD_ID_H_ */ diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c new file mode 100644 index 00000000..da659da2 --- /dev/null +++ b/src/providers/ad/ad_init.c @@ -0,0 +1,184 @@ +/* + SSSD + + Authors: + Stephen Gallagher <sgallagh@redhat.com> + + Copyright (C) 2012 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + + +#include <sys/types.h> +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "util/util.h" +#include "providers/ad/ad_common.h" +#include "providers/ldap/ldap_common.h" +#include "providers/ldap/sdap_idmap.h" +#include "providers/krb5/krb5_auth.h" +#include "providers/ad/ad_id.h" + +struct ad_options *ad_options = NULL; + +static void +ad_shutdown(struct be_req *req); + +struct bet_ops ad_id_ops = { + .handler = ad_account_info_handler, + .finalize = ad_shutdown, + .check_online = sdap_check_online +}; + +struct bet_ops ad_auth_ops = { + .handler = krb5_pam_handler, + .finalize = NULL +}; + +struct bet_ops ad_chpass_ops = { + .handler = krb5_pam_handler, + .finalize = NULL +}; + +static errno_t +common_ad_init(struct be_ctx *bectx) +{ + errno_t ret; + char *ad_servers = NULL; + + /* Get AD-specific options */ + ret = ad_get_common_options(bectx, bectx->cdb, + bectx->conf_path, + bectx->domain, + &ad_options); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + ("Could not parse common options: [%s]\n", + strerror(ret))); + goto done; + } + + ad_servers = dp_opt_get_string(ad_options->basic, AD_SERVER); + + /* Set up the failover service */ + ret = ad_failover_init(ad_options, bectx, ad_servers, ad_options, + &ad_options->service); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + ("Failed to init AD failover service: [%s]\n", + strerror(ret))); + goto done; + } + + ret = EOK; +done: + return ret; +} + +int +sssm_ad_id_init(struct be_ctx *bectx, + struct bet_ops **ops, + void **pvt_data) +{ + errno_t ret; + struct ad_id_ctx *ad_ctx; + struct sdap_id_ctx *sdap_ctx; + + if (!ad_options) { + ret = common_ad_init(bectx); + if (ret != EOK) { + return ret; + } + } + + if (ad_options->id_ctx) { + /* already initialized */ + *ops = &ad_id_ops; + *pvt_data = ad_options->id_ctx; + return EOK; + } + + ad_ctx = talloc_zero(ad_options, struct ad_id_ctx); + if (!ad_options) { + return ENOMEM; + } + ad_ctx->ad_options = ad_options; + ad_options->id_ctx = ad_ctx; + + sdap_ctx = talloc_zero(ad_options, struct sdap_id_ctx); + if (!sdap_ctx) { + return ENOMEM; + } + sdap_ctx->be = bectx; + sdap_ctx->service = ad_options->service->sdap; + ad_ctx->sdap_id_ctx = sdap_ctx; + + ret = ad_get_id_options(ad_options, bectx->cdb, + bectx->conf_path, + &sdap_ctx->opts); + if (ret != EOK) { + goto done; + } + + ret = setup_tls_config(sdap_ctx->opts->basic); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("setup_tls_config failed [%s]\n", strerror(ret))); + goto done; + } + + ret = sdap_id_conn_cache_create(sdap_ctx, sdap_ctx, &sdap_ctx->conn_cache); + if (ret != EOK) { + goto done; + } + + if (dp_opt_get_bool(sdap_ctx->opts->basic, SDAP_ID_MAPPING)) { + /* Set up the ID mapping object */ + ret = sdap_idmap_init(sdap_ctx, sdap_ctx, &sdap_ctx->opts->idmap_ctx); + if (ret != EOK) goto done; + } + + ret = sdap_id_setup_tasks(sdap_ctx); + if (ret != EOK) { + goto done; + } + + ret = setup_child(sdap_ctx); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + ("setup_child failed [%d][%s].\n", + ret, strerror(ret))); + goto done; + } + + *ops = &ad_id_ops; + *pvt_data = ad_ctx; + + ret = EOK; +done: + if (ret != EOK) { + talloc_zfree(ad_options->id_ctx); + } + return ret; +} + +static void +ad_shutdown(struct be_req *req) +{ + /* TODO: Clean up any internal data */ + sdap_handler_done(req, DP_ERR_OK, EOK, NULL); +} diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h new file mode 100644 index 00000000..178d097f --- /dev/null +++ b/src/providers/ad/ad_opts.h @@ -0,0 +1,230 @@ +/* + SSSD + + Authors: + Stephen Gallagher <sgallagh@redhat.com> + + Copyright (C) 2012 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef AD_OPTS_H_ +#define AD_OPTS_H_ + +#include "src/providers/data_provider.h" +#include "db/sysdb_services.h" +#include "db/sysdb_autofs.h" + +struct dp_option ad_basic_opts[] = { + { "ad_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ad_server", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ad_hostname", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING}, + DP_OPTION_TERMINATOR +}; + +struct dp_option ad_def_ldap_opts[] = { + { "ldap_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_default_bind_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_default_authtok_type", DP_OPT_STRING, { "password" }, NULL_STRING}, + { "ldap_default_authtok", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB }, + { "ldap_search_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER }, + { "ldap_network_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER }, + { "ldap_opt_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER }, + { "ldap_tls_reqcert", DP_OPT_STRING, { "hard" }, NULL_STRING }, + { "ldap_user_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_user_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, + { "ldap_user_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_group_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, + { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_service_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_sudo_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_sudo_full_refresh_interval", DP_OPT_NUMBER, { .number = 21600 }, NULL_NUMBER }, /* 360 mins */ + { "ldap_sudo_smart_refresh_interval", DP_OPT_NUMBER, { .number = 900 }, NULL_NUMBER }, /* 15 mins */ + { "ldap_sudo_use_host_filter", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, + { "ldap_sudo_hostnames", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_sudo_ip", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_sudo_include_netgroups", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, + { "ldap_sudo_include_regexp", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, + { "ldap_autofs_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_schema", DP_OPT_STRING, { "ad" }, NULL_STRING }, + { "ldap_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER }, + { "ldap_force_upper_case_realm", DP_OPT_BOOL, BOOL_TRUE, BOOL_FALSE }, + { "ldap_enumeration_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER }, + { "ldap_purge_cache_timeout", DP_OPT_NUMBER, { .number = 10800 }, NULL_NUMBER }, + { "ldap_tls_cacert", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_tls_cacertdir", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_tls_cert", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_tls_key", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_tls_cipher_suite", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_id_use_start_tls", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "ldap_id_mapping", DP_OPT_BOOL, BOOL_TRUE, BOOL_FALSE }, + { "ldap_sasl_mech", DP_OPT_STRING, { "gssapi" }, NULL_STRING }, + { "ldap_sasl_authid", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_sasl_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_sasl_minssf", DP_OPT_NUMBER, { .number = -1 }, NULL_NUMBER }, + { "ldap_krb5_keytab", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_krb5_init_creds", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, + /* use the same parm name as the krb5 module so we set it only once */ + { "krb5_server", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_canonicalize", DP_OPT_BOOL, BOOL_FALSE, BOOL_TRUE }, + { "ldap_pwd_policy", DP_OPT_STRING, { "none" }, NULL_STRING }, + { "ldap_referrals", DP_OPT_BOOL, BOOL_FALSE, BOOL_TRUE }, + { "account_cache_expiration", DP_OPT_NUMBER, { .number = 0 }, NULL_NUMBER }, + { "ldap_dns_service_name", DP_OPT_STRING, { SSS_LDAP_SRV_NAME }, NULL_STRING }, + { "ldap_krb5_ticket_lifetime", DP_OPT_NUMBER, { .number = (24 * 60 * 60) }, NULL_NUMBER }, + { "ldap_access_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_netgroup_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_group_nesting_level", DP_OPT_NUMBER, { .number = 2 }, NULL_NUMBER }, + { "ldap_deref", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_account_expire_policy", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_access_order", DP_OPT_STRING, { "filter" }, NULL_STRING }, + { "ldap_chpass_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_chpass_dns_service_name", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_chpass_update_last_change", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "ldap_enumeration_search_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER }, + /* Do not include ldap_auth_disable_tls_never_use_in_production in the + * manpages or SSSDConfig API + */ + { "ldap_auth_disable_tls_never_use_in_production", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "ldap_page_size", DP_OPT_NUMBER, { .number = 1000 }, NULL_NUMBER }, + { "ldap_deref_threshold", DP_OPT_NUMBER, { .number = 10 }, NULL_NUMBER }, + { "ldap_sasl_canonicalize", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "ldap_connection_expire_timeout", DP_OPT_NUMBER, { .number = 900 }, NULL_NUMBER }, + { "ldap_disable_paging", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "ldap_idmap_range_min", DP_OPT_NUMBER, { .number = 100001 }, NULL_NUMBER }, + { "ldap_idmap_range_max", DP_OPT_NUMBER, { .number = 2000100000LL }, NULL_NUMBER }, + { "ldap_idmap_range_size", DP_OPT_NUMBER, { .number = 200000 }, NULL_NUMBER }, + { "ldap_idmap_autorid_compat", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "ldap_idmap_default_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_idmap_default_domain_sid", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_groups_use_matching_rule_in_chain", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "ldap_initgroups_use_matching_rule_in_chain", DP_OPT_BOOL, BOOL_TRUE, BOOL_FALSE }, + DP_OPTION_TERMINATOR +}; + +struct dp_option ad_def_krb5_opts[] = { + { "krb5_server", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_ccachedir", DP_OPT_STRING, { DEFAULT_CCACHE_DIR }, NULL_STRING }, + { "krb5_ccname_template", DP_OPT_STRING, { DEFAULT_CCNAME_TEMPLATE }, NULL_STRING}, + { "krb5_auth_timeout", DP_OPT_NUMBER, { .number = 15 }, NULL_NUMBER }, + { "krb5_keytab", DP_OPT_STRING, { "/etc/krb5.keytab" }, NULL_STRING }, + { "krb5_validate", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, + { "krb5_kpasswd", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_store_password_if_offline", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "krb5_renewable_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_renew_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER }, + { "krb5_use_fast", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_fast_principal", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_canonicalize", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE } +}; + +struct sdap_attr_map ad_2008r2_attr_map[] = { + { "ldap_entry_usn", SDAP_AD_USN, SYSDB_USN, NULL }, + { "ldap_rootdse_last_usn", SDAP_AD_LAST_USN, SYSDB_HIGH_USN, NULL }, + SDAP_ATTR_MAP_TERMINATOR +}; + +struct sdap_attr_map ad_2008r2_user_map[] = { + { "ldap_user_object_class", "user", SYSDB_USER_CLASS, NULL }, + { "ldap_user_name", "sAMAccountName", SYSDB_NAME, NULL }, + { "ldap_user_pwd", "unixUserPassword", SYSDB_PWD, NULL }, + { "ldap_user_uid_number", "uidNumber", SYSDB_UIDNUM, NULL }, + { "ldap_user_gid_number", "gidNumber", SYSDB_GIDNUM, NULL }, + { "ldap_user_gecos", "gecos", SYSDB_GECOS, NULL }, + { "ldap_user_home_directory", "unixHomeDirectory", SYSDB_HOMEDIR, NULL }, + { "ldap_user_shell", "loginShell", SYSDB_SHELL, NULL }, + { "ldap_user_principal", "userPrincipalName", SYSDB_UPN, NULL }, + { "ldap_user_fullname", "name", SYSDB_FULLNAME, NULL }, + { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL }, + { "ldap_user_uuid", "objectGUID", SYSDB_UUID, NULL }, + { "ldap_user_objectsid", "objectSID", SYSDB_SID, NULL }, + { "ldap_user_primary_group", "primaryGroupID", SYSDB_PRIMARY_GROUP, NULL }, + { "ldap_user_modify_timestamp", "whenChanged", SYSDB_ORIG_MODSTAMP, NULL }, + { "ldap_user_entry_usn", SDAP_AD_USN, SYSDB_USN, NULL }, + { "ldap_user_shadow_last_change", NULL, SYSDB_SHADOWPW_LASTCHANGE, NULL }, + { "ldap_user_shadow_min", NULL, SYSDB_SHADOWPW_MIN, NULL }, + { "ldap_user_shadow_max", NULL, SYSDB_SHADOWPW_MAX, NULL }, + { "ldap_user_shadow_warning", NULL, SYSDB_SHADOWPW_WARNING, NULL }, + { "ldap_user_shadow_inactive", NULL, SYSDB_SHADOWPW_INACTIVE, NULL }, + { "ldap_user_shadow_expire", NULL, SYSDB_SHADOWPW_EXPIRE, NULL }, + { "ldap_user_shadow_flag", NULL, SYSDB_SHADOWPW_FLAG, NULL }, + { "ldap_user_krb_last_pwd_change", NULL, SYSDB_KRBPW_LASTCHANGE, NULL }, + { "ldap_user_krb_password_expiration", NULL, SYSDB_KRBPW_EXPIRATION, NULL }, + { "ldap_pwd_attribute", NULL, SYSDB_PWD_ATTRIBUTE, NULL }, + { "ldap_user_authorized_service", NULL, SYSDB_AUTHORIZED_SERVICE, NULL }, + { "ldap_user_ad_account_expires", "accountExpires", SYSDB_AD_ACCOUNT_EXPIRES, NULL}, + { "ldap_user_ad_user_account_control", "userAccountControl", SYSDB_AD_USER_ACCOUNT_CONTROL, NULL}, + { "ldap_ns_account_lock", NULL, SYSDB_NS_ACCOUNT_LOCK, NULL}, + { "ldap_user_authorized_host", NULL, SYSDB_AUTHORIZED_HOST, NULL }, + { "ldap_user_nds_login_disabled", NULL, SYSDB_NDS_LOGIN_DISABLED, NULL }, + { "ldap_user_nds_login_expiration_time", NULL, SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL }, + { "ldap_user_nds_login_allowed_time_map", NULL, SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL }, + { "ldap_user_ssh_public_key", NULL, SYSDB_SSH_PUBKEY, NULL }, + SDAP_ATTR_MAP_TERMINATOR +}; + +struct sdap_attr_map ad_2008r2_group_map[] = { + { "ldap_group_object_class", "group", SYSDB_GROUP_CLASS, NULL }, + { "ldap_group_name", "name", SYSDB_NAME, NULL }, + { "ldap_group_pwd", NULL, SYSDB_PWD, NULL }, + { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL }, + { "ldap_group_member", "member", SYSDB_MEMBER, NULL }, + { "ldap_group_uuid", "objectGUID", SYSDB_UUID, NULL }, + { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL }, + { "ldap_group_modify_timestamp", "whenChanged", SYSDB_ORIG_MODSTAMP, NULL }, + { "ldap_group_entry_usn", SDAP_AD_USN, SYSDB_USN, NULL }, + SDAP_ATTR_MAP_TERMINATOR +}; + +struct sdap_attr_map ad_netgroup_map[] = { + { "ldap_netgroup_object_class", "nisNetgroup", SYSDB_NETGROUP_CLASS, NULL }, + { "ldap_netgroup_name", "cn", SYSDB_NAME, NULL }, + { "ldap_netgroup_member", "memberNisNetgroup", SYSDB_ORIG_NETGROUP_MEMBER, NULL }, + { "ldap_netgroup_triple", "nisNetgroupTriple", SYSDB_NETGROUP_TRIPLE, NULL }, + /* FIXME: this is 389ds specific */ + { "ldap_netgroup_uuid", "nsUniqueId", SYSDB_UUID, NULL }, + { "ldap_netgroup_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }, + SDAP_ATTR_MAP_TERMINATOR +}; + +struct sdap_attr_map ad_service_map[] = { + { "ldap_service_object_class", "ipService", SYSDB_SVC_CLASS, NULL }, + { "ldap_service_name", "cn", SYSDB_NAME, NULL }, + { "ldap_service_port", "ipServicePort", SYSDB_SVC_PORT, NULL }, + { "ldap_service_proto", "ipServiceProtocol", SYSDB_SVC_PROTO, NULL }, + { "ldap_service_entry_usn", NULL, SYSDB_USN, NULL }, + SDAP_ATTR_MAP_TERMINATOR +}; + +struct sdap_attr_map ad_autofs_mobject_map[] = { + { "ldap_autofs_map_object_class", "nisMap", SYSDB_AUTOFS_MAP_OC, NULL }, + { "ldap_autofs_map_name", "nisMapName", SYSDB_AUTOFS_MAP_NAME, NULL }, + SDAP_ATTR_MAP_TERMINATOR +}; + +struct sdap_attr_map ad_autofs_entry_map[] = { + { "ldap_autofs_entry_object_class", "nisObject", SYSDB_AUTOFS_ENTRY_OC, NULL }, + { "ldap_autofs_entry_key", "cn", SYSDB_AUTOFS_ENTRY_KEY, NULL }, + { "ldap_autofs_entry_value", "nisMapEntry", SYSDB_AUTOFS_ENTRY_VALUE, NULL }, + SDAP_ATTR_MAP_TERMINATOR +}; + +#endif /* AD_OPTS_H_ */ |