/* SSSD proxy_init.c Authors: Stephen Gallagher 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 . */ #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; }