/* 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 NSS_FN_NAME "_nss_%s_%s" #define ERROR_INITGR "The '%s' library does not provides the " \ "_nss_XXX_initgroups_dyn function!\n" \ "initgroups will be slow as it will require " \ "full groups enumeration!\n" #define ERROR_NETGR "The '%s' library does not support netgroups.\n" #define ERROR_SERV "The '%s' library does not support services.\n" static void *proxy_dlsym(void *handle, const char *name, const char *libname) { char *funcname; void *funcptr; funcname = talloc_asprintf(NULL, NSS_FN_NAME, libname, name); if (funcname == NULL) { return NULL; } funcptr = dlsym(handle, funcname); talloc_free(funcname); return funcptr; } static errno_t proxy_id_conf(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx, char **_libname, char **_libpath, bool *_fast_alias) { TALLOC_CTX *tmp_ctx; char *libname; char *libpath; 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; } libpath = talloc_asprintf(tmp_ctx, "libnss_%s.so.2", libname); if (libpath == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n"); ret = ENOMEM; goto done; } *_libname = talloc_steal(mem_ctx, libname); *_libpath = talloc_steal(mem_ctx, libpath); *_fast_alias = fast_alias; ret = EOK; done: talloc_free(tmp_ctx); return ret; } static errno_t proxy_id_load_symbols(struct proxy_nss_ops *ops, const char *libname, void *handle) { int i; struct {void **dest; const char *name; const char *custom_error; bool is_fatal; } symbols[] = { {(void**)&ops->getpwnam_r, "getpwnam_r", NULL, true}, {(void**)&ops->getpwuid_r, "getpwuid_r", NULL, true}, {(void**)&ops->setpwent, "setpwent", NULL, true}, {(void**)&ops->getpwent_r, "getpwent_r", NULL, true}, {(void**)&ops->endpwent, "endpwent", NULL, true}, {(void**)&ops->getgrnam_r, "getgrnam_r", NULL, true}, {(void**)&ops->getgrgid_r, "getgrgid_r", NULL, true}, {(void**)&ops->setgrent, "setgrent", NULL, true}, {(void**)&ops->getgrent_r, "getgrent_r", NULL, true}, {(void**)&ops->endgrent, "endgrent", NULL, true}, {(void**)&ops->initgroups_dyn, "initgroups_dyn", ERROR_INITGR, false}, {(void**)&ops->setnetgrent, "setnetgrent", ERROR_NETGR, false}, {(void**)&ops->getnetgrent_r, "getnetgrent_r", ERROR_NETGR, false}, {(void**)&ops->endnetgrent, "endnetgrent", ERROR_NETGR, false}, {(void**)&ops->getservbyname_r, "getservbyname_r", ERROR_SERV, false}, {(void**)&ops->getservbyport_r, "getservbyport_r", ERROR_SERV, false}, {(void**)&ops->setservent, "setservent", ERROR_SERV, false}, {(void**)&ops->getservent_r, "getservent_r", ERROR_SERV, false}, {(void**)&ops->endservent, "endservent", ERROR_SERV, false}, {NULL, NULL, NULL, false} }; for (i = 0; symbols[i].dest != NULL; i++) { *symbols[i].dest = proxy_dlsym(handle, symbols[i].name, libname); if (*symbols[i].dest == NULL) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to load _nss_%s_%s, " "error: %s.\n", libname, symbols[i].name, dlerror()); if (symbols[i].custom_error != NULL) { DEBUG(SSSDBG_CRIT_FAILURE, symbols[i].custom_error, libname); } if (symbols[i].is_fatal) { return ELIBBAD; } } } return EOK; } static errno_t proxy_setup_sbus(TALLOC_CTX *mem_ctx, struct proxy_auth_ctx *ctx, struct be_ctx *be_ctx) { char *sbus_address; errno_t ret; sbus_address = talloc_asprintf(mem_ctx, "unix:path=%s/%s_%s", PIPE_PATH, PROXY_CHILD_PIPE, be_ctx->domain->name); if (sbus_address == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed.\n"); return ENOMEM; } ret = sbus_new_server(mem_ctx, be_ctx->ev, sbus_address, 0, be_ctx->gid, false, &ctx->sbus_srv, proxy_client_init, ctx); talloc_free(sbus_address); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "Could not set up sbus server.\n"); return ret; } return EOK; } 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) { DEBUG(SSSDBG_CRIT_FAILURE, "Missing option %s.\n", CONFDB_PROXY_PAM_TARGET); return EINVAL; } *_pam_target = pam_target; return EOK; } static errno_t proxy_init_auth_ctx(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx, struct proxy_auth_ctx **_auth_ctx) { struct proxy_auth_ctx *auth_ctx; errno_t ret; int hret; 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_setup_sbus(auth_ctx, auth_ctx, be_ctx); if (ret != EOK) { goto done; } /* Set up request hash table */ /* FIXME: get max_children from configuration file */ auth_ctx->max_children = 10; 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_auth_ctx *auth_ctx; errno_t ret; if (!dp_target_enabled(provider, module_name, DPT_ACCESS, DPT_AUTH, DPT_CHPASS)) { return EOK; } /* Initialize auth_ctx since one of the access, auth or chpass is set. */ ret = proxy_init_auth_ctx(mem_ctx, be_ctx, &auth_ctx); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create auth context [%d]: %s\n", ret, sss_strerror(ret)); return ret; } *_module_data = auth_ctx; 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_id_ctx *ctx; char *libname; char *libpath; errno_t ret; ctx = talloc_zero(mem_ctx, struct proxy_id_ctx); if (ctx == NULL) { return ENOMEM; } ctx->be = be_ctx; ret = proxy_id_conf(ctx, be_ctx, &libname, &libpath, &ctx->fast_alias); if (ret != EOK) { goto done; } ctx->handle = dlopen(libpath, RTLD_NOW); if (ctx->handle == NULL) { DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load %s module, " "error: %s\n", libpath, dlerror()); ret = ELIBACC; goto done; } ret = proxy_id_load_symbols(&ctx->ops, libname, ctx->handle); 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_ACCOUNT_HANDLER, proxy_account_info_handler_send, proxy_account_info_handler_recv, ctx, struct proxy_id_ctx, struct be_acct_req, struct dp_reply_std); ret = EOK; done: if (ret != EOK) { talloc_free(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_auth_ctx *auth_ctx; auth_ctx = talloc_get_type(module_data, struct proxy_auth_ctx); dp_set_method(dp_methods, DPM_AUTH_HANDLER, proxy_pam_handler_send, proxy_pam_handler_recv, 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_auth_ctx *auth_ctx; auth_ctx = talloc_get_type(module_data, struct proxy_auth_ctx); dp_set_method(dp_methods, DPM_ACCESS_HANDLER, proxy_pam_handler_send, proxy_pam_handler_recv, auth_ctx, struct proxy_auth_ctx, struct pam_data, struct pam_data *); return EOK; }