diff options
Diffstat (limited to 'src/providers/proxy/proxy_init.c')
-rw-r--r-- | src/providers/proxy/proxy_init.c | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c new file mode 100644 index 0000000..b3ffad8 --- /dev/null +++ b/src/providers/proxy/proxy_init.c @@ -0,0 +1,519 @@ +/* + SSSD + + proxy_init.c + + Authors: + Stephen Gallagher <sgallagh@redhat.com> + + Copyright (C) 2010 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 "config.h" + +#include "util/sss_format.h" +#include "providers/proxy/proxy.h" + +#define OPT_MAX_CHILDREN_DEFAULT 10 + +static errno_t proxy_id_conf(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + char **_libname, + bool *_fast_alias) +{ + TALLOC_CTX *tmp_ctx; + char *libname; + bool fast_alias; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); + return ENOMEM; + } + + ret = confdb_get_string(be_ctx->cdb, tmp_ctx, be_ctx->conf_path, + CONFDB_PROXY_LIBNAME, NULL, &libname); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read confdb [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } else if (libname == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "No library name given\n"); + ret = ENOENT; + goto done; + } + + ret = confdb_get_bool(be_ctx->cdb, be_ctx->conf_path, + CONFDB_PROXY_FAST_ALIAS, false, &fast_alias); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read confdb [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + + *_libname = talloc_steal(mem_ctx, libname); + *_fast_alias = fast_alias; + + ret = EOK; + +done: + talloc_free(tmp_ctx); + + return ret; +} + +#define LOCAL_AUTH_POLICY_MATCH "match" +#define LOCAL_AUTH_POLICY_ONLY "only" +#define LOCAL_AUTH_POLICY_ENABLE "enable" + +static bool local_auth_enabled(struct be_ctx *be_ctx) +{ + int ret; + char *local_policy = NULL; + bool res; + + ret = confdb_get_string(be_ctx->cdb, NULL, be_ctx->conf_path, + CONFDB_DOMAIN_LOCAL_AUTH_POLICY, + LOCAL_AUTH_POLICY_MATCH, &local_policy); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to get the confdb local_auth_policy\n"); + return false; + } + + res = (strcasecmp(local_policy, LOCAL_AUTH_POLICY_ONLY) == 0 + || strcasestr(local_policy, LOCAL_AUTH_POLICY_ENABLE":") != NULL); + + talloc_free(local_policy); + + return res; +} + +static errno_t proxy_auth_conf(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + char **_pam_target) +{ + char *pam_target; + errno_t ret; + + ret = confdb_get_string(be_ctx->cdb, mem_ctx, be_ctx->conf_path, + CONFDB_PROXY_PAM_TARGET, NULL, &pam_target); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read confdb [%d]: %s\n", + ret, sss_strerror(ret)); + return ret; + } + + if (pam_target == NULL) { + if (local_auth_enabled(be_ctx)) { + DEBUG(SSSDBG_TRACE_FUNC, + "Option ["CONFDB_PROXY_PAM_TARGET"] is missing but local " \ + "authentication is enabled.\n"); + return EOK; + } else { + DEBUG(SSSDBG_CRIT_FAILURE, + "Missing option "CONFDB_PROXY_PAM_TARGET" and local " \ + "authentication isn't enable as well.\n"); + return EINVAL; + } + } + + *_pam_target = pam_target; + + return EOK; +} + +static errno_t proxy_resolver_conf(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + char **_libname) +{ + TALLOC_CTX *tmp_ctx; + char *libname; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); + return ENOMEM; + } + + ret = confdb_get_string(be_ctx->cdb, tmp_ctx, be_ctx->conf_path, + CONFDB_PROXY_RESOLVER_LIBNAME, NULL, &libname); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read confdb [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } else if (libname == NULL) { + DEBUG(SSSDBG_CONF_SETTINGS, "No resolver library name given\n"); + ret = ENOENT; + goto done; + } + + *_libname = talloc_steal(mem_ctx, libname); + + ret = EOK; + +done: + talloc_free(tmp_ctx); + + return ret; +} + +static errno_t proxy_init_auth_ctx(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct data_provider *provider, + struct proxy_auth_ctx **_auth_ctx) +{ + struct proxy_auth_ctx *auth_ctx; + errno_t ret; + int hret; + int max_children; + + auth_ctx = talloc_zero(mem_ctx, struct proxy_auth_ctx); + if (auth_ctx == NULL) { + return ENOMEM; + } + + auth_ctx->be = be_ctx; + auth_ctx->timeout_ms = SSS_CLI_SOCKET_TIMEOUT / 4; + auth_ctx->next_id = 1; + + ret = proxy_auth_conf(auth_ctx, be_ctx, &auth_ctx->pam_target); + if (ret != EOK) { + goto done; + } + + ret = proxy_client_init(dp_sbus_conn(be_ctx->provider), auth_ctx); + if (ret != EOK) { + goto done; + } + + /* Set up request hash table */ + ret = confdb_get_int(be_ctx->cdb, be_ctx->conf_path, + CONFDB_PROXY_MAX_CHILDREN, + OPT_MAX_CHILDREN_DEFAULT, + &max_children); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Unable to read confdb [%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + + if (max_children < 1) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Option " CONFDB_PROXY_MAX_CHILDREN " must be higher then 0\n"); + ret = EINVAL; + goto done; + } + auth_ctx->max_children = max_children; + + hret = hash_create(auth_ctx->max_children * 2, &auth_ctx->request_table, + NULL, NULL); + if (hret != HASH_SUCCESS) { + DEBUG(SSSDBG_FATAL_FAILURE, "Could not initialize request table\n"); + ret = EIO; + goto done; + } + + *_auth_ctx = auth_ctx; + + ret = EOK; + +done: + if (ret != EOK) { + talloc_free(auth_ctx); + } + + return ret; +} + +errno_t sssm_proxy_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct data_provider *provider, + const char *module_name, + void **_module_data) +{ + struct proxy_module_ctx *module_ctx; + errno_t ret; + + module_ctx = talloc_zero(mem_ctx, struct proxy_module_ctx); + if (module_ctx == NULL) { + return ENOMEM; + } + + if (dp_target_enabled(provider, module_name, + DPT_ACCESS, DPT_AUTH, DPT_CHPASS)) { + /* Initialize auth_ctx since one of the access, auth or chpass is + * set. */ + ret = proxy_init_auth_ctx(module_ctx, be_ctx, provider, + &module_ctx->auth_ctx); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create auth context [%d]: %s\n", + ret, sss_strerror(ret)); + talloc_free(module_ctx); + return ret; + } + } + + *_module_data = module_ctx; + + return EOK; +} + +static errno_t proxy_load_nss_symbols(struct sss_nss_ops *ops, + const char *libname) +{ + errno_t ret; + struct sss_nss_symbols syms[] = { + {(void*)&ops->getpwnam_r, true, "getpwnam_r" }, + {(void*)&ops->getpwuid_r, true, "getpwuid_r" }, + {(void*)&ops->setpwent, true, "setpwent" }, + {(void*)&ops->getpwent_r, true, "getpwent_r" }, + {(void*)&ops->endpwent, true, "endpwent" }, + {(void*)&ops->getgrnam_r, true, "getgrnam_r" }, + {(void*)&ops->getgrgid_r, true, "getgrgid_r" }, + {(void*)&ops->setgrent, true, "setgrent" }, + {(void*)&ops->getgrent_r, true, "getgrent_r" }, + {(void*)&ops->endgrent, true, "endgrent" }, + {(void*)&ops->initgroups_dyn, false, "initgroups_dyn" }, + {(void*)&ops->setnetgrent, false, "setnetgrent" }, + {(void*)&ops->getnetgrent_r, false, "getnetgrent_r" }, + {(void*)&ops->endnetgrent, false, "endnetgrent" }, + {(void*)&ops->getservbyname_r, false, "getservbyname_r" }, + {(void*)&ops->getservbyport_r, false, "getservbyport_r" }, + {(void*)&ops->setservent, false, "setservent" }, + {(void*)&ops->getservent_r, false, "getservent_r" }, + {(void*)&ops->endservent, false, "endservent" }, + }; + size_t nsyms = sizeof(syms) / sizeof(struct sss_nss_symbols); + + ret = sss_load_nss_symbols(ops, libname, syms, nsyms); + if (ret != EOK) { + return ret; + } + + return EOK; +} + +static errno_t proxy_load_nss_hosts_symbols(struct sss_nss_ops *ops, + const char *libname) +{ + errno_t ret; + struct sss_nss_symbols syms[] = { + {(void*)&ops->gethostbyname_r, true, "gethostbyname_r"}, + {(void*)&ops->gethostbyname2_r, true, "gethostbyname2_r"}, + {(void*)&ops->gethostbyaddr_r, true, "gethostbyaddr_r"}, + {(void*)&ops->sethostent, false, "sethostent"}, + {(void*)&ops->gethostent_r, false, "gethostent_r"}, + {(void*)&ops->endhostent, false, "endhostent"}, + }; + size_t nsyms = sizeof(syms) / sizeof(struct sss_nss_symbols); + + ret = sss_load_nss_symbols(ops, libname, syms, nsyms); + if (ret != EOK) { + return ret; + } + + return EOK; +} + +static errno_t proxy_load_nss_nets_symbols(struct sss_nss_ops *ops, + const char *libname) +{ + errno_t ret; + struct sss_nss_symbols syms[] = { + {(void*)&ops->getnetbyname_r, true, "getnetbyname_r"}, + {(void*)&ops->getnetbyaddr_r, true, "getnetbyaddr_r"}, + {(void*)&ops->setnetent, false, "setnetent"}, + {(void*)&ops->getnetent_r, false, "getnetent_r"}, + {(void*)&ops->endnetent, false, "endnetent"}, + }; + size_t nsyms = sizeof(syms) / sizeof(struct sss_nss_symbols); + + ret = sss_load_nss_symbols(ops, libname, syms, nsyms); + if (ret != EOK) { + return ret; + } + + return EOK; +} + +errno_t sssm_proxy_id_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + void *module_data, + struct dp_method *dp_methods) +{ + struct proxy_module_ctx *module_ctx; + char *libname; + errno_t ret; + + module_ctx = talloc_get_type(module_data, struct proxy_module_ctx); + module_ctx->id_ctx = talloc_zero(module_ctx, struct proxy_id_ctx); + if (module_ctx->id_ctx == NULL) { + return ENOMEM; + } + + module_ctx->id_ctx->be = be_ctx; + + ret = proxy_id_conf(module_ctx->id_ctx, be_ctx, &libname, + &module_ctx->id_ctx->fast_alias); + if (ret != EOK) { + goto done; + } + + ret = proxy_load_nss_symbols(&module_ctx->id_ctx->ops, libname); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load NSS symbols [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + + ret = confdb_certmap_to_sysdb(be_ctx->cdb, be_ctx->domain, true); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to initialize certificate mapping rules. " + "Authentication with certificates/Smartcards might not work " + "as expected.\n"); + /* not fatal, ignored */ + } else { + ret = proxy_init_certmap(module_ctx->id_ctx, module_ctx->id_ctx); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "files_init_certmap failed. " + "Authentication with certificates/Smartcards might not work " + "as expected.\n"); + /* not fatal, ignored */ + } + } + + dp_set_method(dp_methods, DPM_ACCOUNT_HANDLER, + proxy_account_info_handler_send, proxy_account_info_handler_recv, + module_ctx->id_ctx, struct proxy_id_ctx, struct dp_id_data, + struct dp_reply_std); + + dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER, + default_account_domain_send, default_account_domain_recv, NULL, + void, struct dp_get_acct_domain_data, struct dp_reply_std); + + ret = EOK; + +done: + if (ret != EOK) { + talloc_zfree(module_ctx->id_ctx); + } + + return ret; +} + +errno_t sssm_proxy_auth_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + void *module_data, + struct dp_method *dp_methods) +{ + struct proxy_module_ctx *module_ctx; + + module_ctx = talloc_get_type(module_data, struct proxy_module_ctx); + + dp_set_method(dp_methods, DPM_AUTH_HANDLER, + proxy_pam_handler_send, proxy_pam_handler_recv, + module_ctx->auth_ctx, struct proxy_auth_ctx, + struct pam_data, struct pam_data *); + + return EOK; +} + +errno_t sssm_proxy_chpass_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + void *module_data, + struct dp_method *dp_methods) +{ + return sssm_proxy_auth_init(mem_ctx, be_ctx, module_data, dp_methods); +} + +errno_t sssm_proxy_access_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + void *module_data, + struct dp_method *dp_methods) +{ + struct proxy_module_ctx *module_ctx; + + module_ctx = talloc_get_type(module_data, struct proxy_module_ctx); + + dp_set_method(dp_methods, DPM_ACCESS_HANDLER, + proxy_pam_handler_send, proxy_pam_handler_recv, + module_ctx->auth_ctx, struct proxy_auth_ctx, + struct pam_data, struct pam_data *); + + return EOK; +} + +errno_t sssm_proxy_resolver_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + void *module_data, + struct dp_method *dp_methods) +{ + struct proxy_module_ctx *module_ctx; + char *libname; + errno_t ret; + + module_ctx = talloc_get_type(module_data, struct proxy_module_ctx); + + module_ctx->resolver_ctx = talloc_zero(mem_ctx, struct proxy_resolver_ctx); + if (module_ctx->resolver_ctx == NULL) { + return ENOMEM; + } + + ret = proxy_resolver_conf(module_ctx->resolver_ctx, be_ctx, &libname); + if (ret == ENOENT) { + ret = ENOTSUP; + goto done; + } else if (ret != EOK) { + goto done; + } + + ret = proxy_load_nss_hosts_symbols(&module_ctx->resolver_ctx->ops, libname); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load NSS symbols [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + + ret = proxy_load_nss_nets_symbols(&module_ctx->resolver_ctx->ops, libname); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load NSS symbols [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + + dp_set_method(dp_methods, DPM_RESOLVER_HOSTS_HANDLER, + proxy_hosts_handler_send, proxy_hosts_handler_recv, + module_ctx->resolver_ctx, struct proxy_resolver_ctx, + struct dp_resolver_data, struct dp_reply_std); + + dp_set_method(dp_methods, DPM_RESOLVER_IP_NETWORK_HANDLER, + proxy_nets_handler_send, proxy_nets_handler_recv, + module_ctx->resolver_ctx, struct proxy_resolver_ctx, + struct dp_resolver_data, struct dp_reply_std); + + ret = EOK; + +done: + if (ret != EOK) { + talloc_zfree(module_ctx->resolver_ctx); + } + + return ret; +} |