From 1c48b5a62f73234ed26bb20f0ab345ab61cda0ab Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Thu, 18 Feb 2010 07:49:04 -0500 Subject: Rename server/ directory to src/ Also update BUILD.txt --- server/responder/pam/pam_LOCAL_domain.c | 476 ------------- server/responder/pam/pamsrv.c | 224 ------ server/responder/pam/pamsrv.h | 57 -- server/responder/pam/pamsrv_cmd.c | 1181 ------------------------------- server/responder/pam/pamsrv_dp.c | 142 ---- 5 files changed, 2080 deletions(-) delete mode 100644 server/responder/pam/pam_LOCAL_domain.c delete mode 100644 server/responder/pam/pamsrv.c delete mode 100644 server/responder/pam/pamsrv.h delete mode 100644 server/responder/pam/pamsrv_cmd.c delete mode 100644 server/responder/pam/pamsrv_dp.c (limited to 'server/responder/pam') diff --git a/server/responder/pam/pam_LOCAL_domain.c b/server/responder/pam/pam_LOCAL_domain.c deleted file mode 100644 index 34f0c8dd..00000000 --- a/server/responder/pam/pam_LOCAL_domain.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - SSSD - - PAM e credentials - - Copyright (C) Sumit Bose 2009 - - 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 -#include - -#include "util/util.h" -#include "db/sysdb.h" -#include "util/sha512crypt.h" -#include "providers/data_provider.h" -#include "responder/pam/pamsrv.h" - - -#define NULL_CHECK_OR_JUMP(var, msg, ret, err, label) do { \ - if (var == NULL) { \ - DEBUG(1, (msg)); \ - ret = (err); \ - goto label; \ - } \ -} while(0) - -#define NEQ_CHECK_OR_JUMP(var, val, msg, ret, err, label) do { \ - if (var != (val)) { \ - DEBUG(1, (msg)); \ - ret = (err); \ - goto label; \ - } \ -} while(0) - - -struct LOCAL_request { - struct tevent_context *ev; - struct sysdb_ctx *dbctx; - struct sysdb_attrs *mod_attrs; - struct sysdb_handle *handle; - - struct ldb_result *res; - int error; - - struct pam_auth_req *preq; -}; - -static void prepare_reply(struct LOCAL_request *lreq) -{ - struct pam_data *pd; - - pd = lreq->preq->pd; - - if (lreq->error != EOK && pd->pam_status == PAM_SUCCESS) - pd->pam_status = PAM_SYSTEM_ERR; - - lreq->preq->callback(lreq->preq); -} - -static void set_user_attr_done(struct tevent_req *req) -{ - struct LOCAL_request *lreq; - int ret; - - lreq = tevent_req_callback_data(req, struct LOCAL_request); - - ret = sysdb_transaction_commit_recv(req); - if (ret) { - DEBUG(2, ("set_user_attr failed.\n")); - lreq->error =ret; - } - - prepare_reply(lreq); -} - -static void set_user_attr_req_done(struct tevent_req *subreq); -static void set_user_attr_req(struct tevent_req *req) -{ - struct LOCAL_request *lreq = tevent_req_callback_data(req, - struct LOCAL_request); - struct tevent_req *subreq; - int ret; - - DEBUG(4, ("entering set_user_attr_req\n")); - - ret = sysdb_transaction_recv(req, lreq, &lreq->handle); - if (ret) { - lreq->error = ret; - return prepare_reply(lreq); - } - - subreq = sysdb_set_user_attr_send(lreq, lreq->ev, lreq->handle, - lreq->preq->domain, - lreq->preq->pd->user, - lreq->mod_attrs, SYSDB_MOD_REP); - if (!subreq) { - /* cancel transaction */ - talloc_zfree(lreq->handle); - lreq->error = ret; - return prepare_reply(lreq); - } - tevent_req_set_callback(subreq, set_user_attr_req_done, lreq); -} - -static void set_user_attr_req_done(struct tevent_req *subreq) -{ - struct LOCAL_request *lreq = tevent_req_callback_data(subreq, - struct LOCAL_request); - struct tevent_req *req; - int ret; - - ret = sysdb_set_user_attr_recv(subreq); - talloc_zfree(subreq); - - DEBUG(4, ("set_user_attr_callback, status [%d][%s]\n", ret, strerror(ret))); - - if (ret) { - lreq->error = ret; - goto fail; - } - - req = sysdb_transaction_commit_send(lreq, lreq->ev, lreq->handle); - if (!req) { - lreq->error = ENOMEM; - goto fail; - } - tevent_req_set_callback(req, set_user_attr_done, lreq); - - return; - -fail: - DEBUG(2, ("set_user_attr failed.\n")); - - /* cancel transaction */ - talloc_zfree(lreq->handle); - - prepare_reply(lreq); -} - -static void do_successful_login(struct LOCAL_request *lreq) -{ - struct tevent_req *req; - int ret; - - lreq->mod_attrs = sysdb_new_attrs(lreq); - NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"), - lreq->error, ENOMEM, done); - - ret = sysdb_attrs_add_long(lreq->mod_attrs, - SYSDB_LAST_LOGIN, (long)time(NULL)); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"), - lreq->error, ret, done); - - ret = sysdb_attrs_add_long(lreq->mod_attrs, SYSDB_FAILED_LOGIN_ATTEMPTS, 0L); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"), - lreq->error, ret, done); - - req = sysdb_transaction_send(lreq, lreq->ev, lreq->dbctx); - if (!req) { - lreq->error = ENOMEM; - goto done; - } - tevent_req_set_callback(req, set_user_attr_req, lreq); - - return; - -done: - - prepare_reply(lreq); -} - -static void do_failed_login(struct LOCAL_request *lreq) -{ - struct tevent_req *req; - int ret; - int failedLoginAttempts; - struct pam_data *pd; - - pd = lreq->preq->pd; - pd->pam_status = PAM_AUTH_ERR; -/* TODO: maybe add more inteligent delay calculation */ - pd->response_delay = 3; - - lreq->mod_attrs = sysdb_new_attrs(lreq); - NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"), - lreq->error, ENOMEM, done); - - ret = sysdb_attrs_add_long(lreq->mod_attrs, - SYSDB_LAST_FAILED_LOGIN, (long)time(NULL)); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"), - lreq->error, ret, done); - - failedLoginAttempts = ldb_msg_find_attr_as_int(lreq->res->msgs[0], - SYSDB_FAILED_LOGIN_ATTEMPTS, - 0); - failedLoginAttempts++; - - ret = sysdb_attrs_add_long(lreq->mod_attrs, - SYSDB_FAILED_LOGIN_ATTEMPTS, - (long)failedLoginAttempts); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"), - lreq->error, ret, done); - - req = sysdb_transaction_send(lreq, lreq->ev, lreq->dbctx); - if (!req) { - lreq->error = ENOMEM; - goto done; - } - tevent_req_set_callback(req, set_user_attr_req, lreq); - - return; - -done: - - prepare_reply(lreq); -} - -static void do_pam_acct_mgmt(struct LOCAL_request *lreq) -{ - const char *disabled; - struct pam_data *pd; - - pd = lreq->preq->pd; - - disabled = ldb_msg_find_attr_as_string(lreq->res->msgs[0], - SYSDB_DISABLED, NULL); - if ((disabled != NULL) && - (strncasecmp(disabled, "false",5) != 0) && - (strncasecmp(disabled, "no",2) != 0) ) { - pd->pam_status = PAM_PERM_DENIED; - } - - prepare_reply(lreq); -} - -static void do_pam_chauthtok(struct LOCAL_request *lreq) -{ - struct tevent_req *req; - int ret; - char *newauthtok; - char *salt; - char *new_hash; - struct pam_data *pd; - - pd = lreq->preq->pd; - - newauthtok = talloc_strndup(lreq, (char *) pd->newauthtok, - pd->newauthtok_size); - NULL_CHECK_OR_JUMP(newauthtok, ("talloc_strndup failed.\n"), lreq->error, - ENOMEM, done); - memset(pd->newauthtok, 0, pd->newauthtok_size); - - if (strlen(newauthtok) == 0) { - /* TODO: should we allow null passwords via a config option ? */ - DEBUG(1, ("Empty passwords are not allowed!")); - ret = EINVAL; - goto done; - } - - ret = s3crypt_gen_salt(lreq, &salt); - NEQ_CHECK_OR_JUMP(ret, EOK, ("Salt generation failed.\n"), - lreq->error, ret, done); - DEBUG(4, ("Using salt [%s]\n", salt)); - - ret = s3crypt_sha512(lreq, newauthtok, salt, &new_hash); - NEQ_CHECK_OR_JUMP(ret, EOK, ("Hash generation failed.\n"), - lreq->error, ret, done); - DEBUG(4, ("New hash [%s]\n", new_hash)); - memset(newauthtok, 0, pd->newauthtok_size); - - lreq->mod_attrs = sysdb_new_attrs(lreq); - NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"), - lreq->error, ENOMEM, done); - - ret = sysdb_attrs_add_string(lreq->mod_attrs, SYSDB_PWD, new_hash); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_string failed.\n"), - lreq->error, ret, done); - - ret = sysdb_attrs_add_long(lreq->mod_attrs, - "lastPasswordChange", (long)time(NULL)); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"), - lreq->error, ret, done); - - req = sysdb_transaction_send(lreq, lreq->ev, lreq->dbctx); - if (!req) { - lreq->error = ENOMEM; - goto done; - } - tevent_req_set_callback(req, set_user_attr_req, lreq); - - return; -done: - - prepare_reply(lreq); -} - -static void local_handler_callback(void *pvt, int ldb_status, - struct ldb_result *res) -{ - struct LOCAL_request *lreq; - const char *username = NULL; - const char *password = NULL; - char *newauthtok = NULL; - char *new_hash = NULL; - char *authtok = NULL; - struct pam_data *pd; - int ret; - - lreq = talloc_get_type(pvt, struct LOCAL_request); - pd = lreq->preq->pd; - - DEBUG(4, ("pam_handler_callback called with ldb_status [%d].\n", - ldb_status)); - - NEQ_CHECK_OR_JUMP(ldb_status, LDB_SUCCESS, ("ldb search failed.\n"), - lreq->error, sysdb_error_to_errno(ldb_status), done); - - - if (res->count < 1) { - DEBUG(4, ("No user found with filter ["SYSDB_PWNAM_FILTER"]\n", - pd->user)); - pd->pam_status = PAM_USER_UNKNOWN; - goto done; - } else if (res->count > 1) { - DEBUG(4, ("More than one object found with filter ["SYSDB_PWNAM_FILTER"]\n")); - lreq->error = EFAULT; - goto done; - } - - username = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL); - if (strcmp(username, pd->user) != 0) { - DEBUG(1, ("Expected username [%s] get [%s].\n", pd->user, username)); - lreq->error = EINVAL; - goto done; - } - - lreq->res = res; - - switch (pd->cmd) { - case SSS_PAM_AUTHENTICATE: - case SSS_PAM_CHAUTHTOK: - case SSS_PAM_CHAUTHTOK_PRELIM: - if ((pd->cmd == SSS_PAM_CHAUTHTOK || - pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) && - lreq->preq->cctx->priv == 1) { -/* TODO: maybe this is a candiate for an explicit audit message. */ - DEBUG(4, ("allowing root to reset a password.\n")); - break; - } - authtok = talloc_strndup(lreq, (char *) pd->authtok, - pd->authtok_size); - NULL_CHECK_OR_JUMP(authtok, ("talloc_strndup failed.\n"), - lreq->error, ENOMEM, done); - memset(pd->authtok, 0, pd->authtok_size); - - password = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL); - NULL_CHECK_OR_JUMP(password, ("No password stored.\n"), - lreq->error, LDB_ERR_NO_SUCH_ATTRIBUTE, done); - DEBUG(4, ("user: [%s], password hash: [%s]\n", username, password)); - - ret = s3crypt_sha512(lreq, authtok, password, &new_hash); - memset(authtok, 0, pd->authtok_size); - NEQ_CHECK_OR_JUMP(ret, EOK, ("nss_sha512_crypt failed.\n"), - lreq->error, ret, done); - - DEBUG(4, ("user: [%s], new hash: [%s]\n", username, new_hash)); - - if (strcmp(new_hash, password) != 0) { - DEBUG(1, ("Passwords do not match.\n")); - do_failed_login(lreq); - return; - } - - break; - } - - switch (pd->cmd) { - case SSS_PAM_AUTHENTICATE: - do_successful_login(lreq); - return; - break; - case SSS_PAM_CHAUTHTOK: - do_pam_chauthtok(lreq); - return; - break; - case SSS_PAM_ACCT_MGMT: - do_pam_acct_mgmt(lreq); - return; - break; - case SSS_PAM_SETCRED: - break; - case SSS_PAM_OPEN_SESSION: - break; - case SSS_PAM_CLOSE_SESSION: - break; - case SSS_PAM_CHAUTHTOK_PRELIM: - break; - default: - lreq->error = EINVAL; - DEBUG(1, ("Unknown PAM task [%d].\n")); - } - -done: - if (pd->authtok != NULL) - memset(pd->authtok, 0, pd->authtok_size); - if (authtok != NULL) - memset(authtok, 0, pd->authtok_size); - if (pd->newauthtok != NULL) - memset(pd->newauthtok, 0, pd->newauthtok_size); - if (newauthtok != NULL) - memset(newauthtok, 0, pd->newauthtok_size); - - prepare_reply(lreq); -} - -int LOCAL_pam_handler(struct pam_auth_req *preq) -{ - int ret; - struct LOCAL_request *lreq; - - static const char *attrs[] = {SYSDB_NAME, - SYSDB_PWD, - SYSDB_DISABLED, - SYSDB_LAST_LOGIN, - "lastPasswordChange", - "accountExpires", - SYSDB_FAILED_LOGIN_ATTEMPTS, - "passwordHint", - "passwordHistory", - SYSDB_LAST_FAILED_LOGIN, - NULL}; - - DEBUG(4, ("LOCAL pam handler.\n")); - - lreq = talloc_zero(preq, struct LOCAL_request); - if (!lreq) { - return ENOMEM; - } - - ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list, - preq->domain, &lreq->dbctx); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - talloc_free(lreq); - return ret; - } - lreq->ev = preq->cctx->ev; - lreq->preq = preq; - - preq->pd->pam_status = PAM_SUCCESS; - - ret = sysdb_get_user_attr(lreq, lreq->dbctx, - preq->domain, preq->pd->user, attrs, - local_handler_callback, lreq); - - if (ret != EOK) { - DEBUG(1, ("sysdb_get_user_attr failed.\n")); - talloc_free(lreq); - return ret; - } - - return EOK; -} diff --git a/server/responder/pam/pamsrv.c b/server/responder/pam/pamsrv.c deleted file mode 100644 index 84b13dc4..00000000 --- a/server/responder/pam/pamsrv.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - SSSD - - PAM Responder - - Copyright (C) Simo Sorce 2009 - Copyright (C) Sumit Bose 2009 - - 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "popt.h" -#include "util/util.h" -#include "db/sysdb.h" -#include "confdb/confdb.h" -#include "dbus/dbus.h" -#include "sbus/sssd_dbus.h" -#include "responder/common/responder_packet.h" -#include "providers/data_provider.h" -#include "monitor/monitor_interfaces.h" -#include "sbus/sbus_client.h" -#include "responder/pam/pamsrv.h" - -#define SSS_PAM_SBUS_SERVICE_VERSION 0x0001 -#define SSS_PAM_SBUS_SERVICE_NAME "pam" - -static int service_reload(DBusMessage *message, struct sbus_connection *conn); - -struct sbus_method monitor_pam_methods[] = { - { MON_CLI_METHOD_PING, monitor_common_pong }, - { MON_CLI_METHOD_RELOAD, service_reload }, - { MON_CLI_METHOD_RES_INIT, monitor_common_res_init }, - { NULL, NULL } -}; - -struct sbus_interface monitor_pam_interface = { - MONITOR_INTERFACE, - MONITOR_PATH, - SBUS_DEFAULT_VTABLE, - monitor_pam_methods, - NULL -}; - -static int service_reload(DBusMessage *message, struct sbus_connection *conn) { - /* Monitor calls this function when we need to reload - * our configuration information. Perform whatever steps - * are needed to update the configuration objects. - */ - - /* Send an empty reply to acknowledge receipt */ - return monitor_common_pong(message, conn); -} - -static struct sbus_method pam_dp_methods[] = { - { NULL, NULL } -}; - -struct sbus_interface pam_dp_interface = { - DP_INTERFACE, - DP_PATH, - SBUS_DEFAULT_VTABLE, - pam_dp_methods, - NULL -}; - - -static void pam_dp_reconnect_init(struct sbus_connection *conn, int status, void *pvt) -{ - struct be_conn *be_conn = talloc_get_type(pvt, struct be_conn); - int ret; - - /* Did we reconnect successfully? */ - if (status == SBUS_RECONNECT_SUCCESS) { - DEBUG(1, ("Reconnected to the Data Provider.\n")); - - /* Identify ourselves to the data provider */ - ret = dp_common_send_id(be_conn->conn, - DATA_PROVIDER_VERSION, - "PAM", be_conn->domain->name); - /* all fine */ - if (ret == EOK) return; - } - - /* Handle failure */ - DEBUG(0, ("Could not reconnect to %s provider.\n", - be_conn->domain->name)); - - /* FIXME: kill the frontend and let the monitor restart it ? */ - /* pam_shutdown(rctx); */ -} - -static errno_t pam_get_config(struct pam_ctx *pctx, - struct resp_ctx *rctx, - struct confdb_ctx *cdb) -{ - int ret = EOK; - ret = confdb_get_int(cdb, pctx, CONFDB_PAM_CONF_ENTRY, - CONFDB_PAM_CRED_TIMEOUT, 0, - &pctx->cred_expiration); - return ret; -} - -static int pam_process_init(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct confdb_ctx *cdb) -{ - struct sss_cmd_table *pam_cmds; - struct be_conn *iter; - struct pam_ctx *pctx; - int ret, max_retries; - - pctx = talloc_zero(mem_ctx, struct pam_ctx); - if (!pctx) { - return ENOMEM; - } - - pam_cmds = get_pam_cmds(); - ret = sss_process_init(pctx, ev, cdb, - pam_cmds, - SSS_PAM_SOCKET_NAME, - SSS_PAM_PRIV_SOCKET_NAME, - CONFDB_PAM_CONF_ENTRY, - SSS_PAM_SBUS_SERVICE_NAME, - SSS_PAM_SBUS_SERVICE_VERSION, - &monitor_pam_interface, - "PAM", &pam_dp_interface, - &pctx->rctx); - if (ret != EOK) { - return ret; - } - - pctx->rctx->pvt_ctx = pctx; - ret = pam_get_config(pctx, pctx->rctx, pctx->rctx->cdb); - - /* Enable automatic reconnection to the Data Provider */ - - /* FIXME: "retries" is too generic, either get it from a global config - * or specify these retries are about the sbus connections to DP */ - ret = confdb_get_int(pctx->rctx->cdb, pctx->rctx, CONFDB_PAM_CONF_ENTRY, - CONFDB_SERVICE_RECON_RETRIES, 3, &max_retries); - if (ret != EOK) { - DEBUG(0, ("Failed to set up automatic reconnection\n")); - return ret; - } - - for (iter = pctx->rctx->be_conns; iter; iter = iter->next) { - sbus_reconnect_init(iter->conn, max_retries, - pam_dp_reconnect_init, iter); - } - - return EOK; -} - -int main(int argc, const char *argv[]) -{ - int opt; - poptContext pc; - struct main_context *main_ctx; - int ret; - - struct poptOption long_options[] = { - POPT_AUTOHELP - SSSD_MAIN_OPTS - { NULL } - }; - - pc = poptGetContext(argv[0], argc, argv, long_options, 0); - while((opt = poptGetNextOpt(pc)) != -1) { - switch(opt) { - default: - fprintf(stderr, "\nInvalid option %s: %s\n\n", - poptBadOption(pc, 0), poptStrerror(opt)); - poptPrintUsage(pc, stderr, 0); - return 1; - } - } - - poptFreeContext(pc); - - /* set up things like debug, signals, daemonization, etc... */ - debug_log_file = "sssd_pam"; - - ret = server_setup("sssd[pam]", 0, CONFDB_PAM_CONF_ENTRY, &main_ctx); - if (ret != EOK) return 2; - - ret = die_if_parent_died(); - if (ret != EOK) { - /* This is not fatal, don't return */ - DEBUG(2, ("Could not set up to exit when parent process does\n")); - } - - ret = pam_process_init(main_ctx, - main_ctx->event_ctx, - main_ctx->confdb_ctx); - if (ret != EOK) return 3; - - /* loop on main */ - server_loop(main_ctx); - - return 0; -} - diff --git a/server/responder/pam/pamsrv.h b/server/responder/pam/pamsrv.h deleted file mode 100644 index 60f9c66a..00000000 --- a/server/responder/pam/pamsrv.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - Authors: - Simo Sorce - Sumit Bose - - Copyright (C) 2009 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 . -*/ - -#ifndef __PAMSRV_H__ -#define __PAMSRV_H__ - -#include -#include "util/util.h" -#include "sbus/sssd_dbus.h" -#include "responder/common/responder.h" - -struct pam_auth_req; - -typedef void (pam_dp_callback_t)(struct pam_auth_req *preq); - -struct pam_ctx { - int cred_expiration; - struct resp_ctx *rctx; -}; - -struct pam_auth_req { - struct cli_ctx *cctx; - struct sss_domain_info *domain; - - struct pam_data *pd; - - pam_dp_callback_t *callback; - - bool check_provider; - void *data; -}; - -struct sss_cmd_table *get_pam_cmds(void); - -int pam_dp_send_req(struct pam_auth_req *preq, int timeout); - -int LOCAL_pam_handler(struct pam_auth_req *preq); - -#endif /* __PAMSRV_H__ */ diff --git a/server/responder/pam/pamsrv_cmd.c b/server/responder/pam/pamsrv_cmd.c deleted file mode 100644 index 37aad829..00000000 --- a/server/responder/pam/pamsrv_cmd.c +++ /dev/null @@ -1,1181 +0,0 @@ -/* - SSSD - - PAM Responder - - Copyright (C) Simo Sorce 2009 - Copyright (C) Sumit Bose 2009 - - 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 -#include "util/util.h" -#include "db/sysdb.h" -#include "confdb/confdb.h" -#include "responder/common/responder_packet.h" -#include "responder/common/responder.h" -#include "providers/data_provider.h" -#include "responder/pam/pamsrv.h" -#include "db/sysdb.h" - -static void pam_reply(struct pam_auth_req *preq); - -static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok, uint8_t *body, size_t blen, size_t *c) { - uint32_t data_size; - - if (blen-(*c) < 2*sizeof(uint32_t)) return EINVAL; - - memcpy(&data_size, &body[*c], sizeof(uint32_t)); - *c += sizeof(uint32_t); - if (data_size < sizeof(uint32_t) || (*c)+(data_size) > blen) return EINVAL; - *size = data_size - sizeof(uint32_t); - - memcpy(type, &body[*c], sizeof(uint32_t)); - *c += sizeof(uint32_t); - - *tok = body+(*c); - - *c += (*size); - - return EOK; -} - -static int extract_string(char **var, uint8_t *body, size_t blen, size_t *c) { - uint32_t size; - uint8_t *str; - - if (blen-(*c) < sizeof(uint32_t)+1) return EINVAL; - - memcpy(&size, &body[*c], sizeof(uint32_t)); - *c += sizeof(uint32_t); - if (*c+size > blen) return EINVAL; - - str = body+(*c); - - if (str[size-1]!='\0') return EINVAL; - - *c += size; - - *var = (char *) str; - - return EOK; -} - -static int extract_uint32_t(uint32_t *var, uint8_t *body, size_t blen, size_t *c) { - uint32_t size; - - if (blen-(*c) < 2*sizeof(uint32_t)) return EINVAL; - - memcpy(&size, &body[*c], sizeof(uint32_t)); - *c += sizeof(uint32_t); - - memcpy(var, &body[*c], sizeof(uint32_t)); - *c += sizeof(uint32_t); - - return EOK; -} - -static int pam_parse_in_data_v2(struct sss_names_ctx *snctx, - struct pam_data *pd, - uint8_t *body, size_t blen) -{ - size_t c; - uint32_t type; - uint32_t size; - char *pam_user; - int ret; - uint32_t terminator = SSS_END_OF_PAM_REQUEST; - - if (blen < 4*sizeof(uint32_t)+2 || - ((uint32_t *)body)[0] != SSS_START_OF_PAM_REQUEST || - memcmp(&body[blen - sizeof(uint32_t)], &terminator, sizeof(uint32_t)) != 0) { - DEBUG(1, ("Received data is invalid.\n")); - return EINVAL; - } - - c = sizeof(uint32_t); - do { - memcpy(&type, &body[c], sizeof(uint32_t)); - c += sizeof(uint32_t); - if (c > blen) return EINVAL; - - switch(type) { - case SSS_PAM_ITEM_USER: - ret = extract_string(&pam_user, body, blen, &c); - if (ret != EOK) return ret; - - ret = sss_parse_name(pd, snctx, pam_user, - &pd->domain, &pd->user); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_SERVICE: - ret = extract_string(&pd->service, body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_TTY: - ret = extract_string(&pd->tty, body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_RUSER: - ret = extract_string(&pd->ruser, body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_RHOST: - ret = extract_string(&pd->rhost, body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_CLI_PID: - ret = extract_uint32_t(&pd->cli_pid, - body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_AUTHTOK: - ret = extract_authtok(&pd->authtok_type, &pd->authtok_size, - &pd->authtok, body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_PAM_ITEM_NEWAUTHTOK: - ret = extract_authtok(&pd->newauthtok_type, - &pd->newauthtok_size, - &pd->newauthtok, body, blen, &c); - if (ret != EOK) return ret; - break; - case SSS_END_OF_PAM_REQUEST: - if (c != blen) return EINVAL; - break; - default: - DEBUG(1,("Ignoring unknown data type [%d].\n", type)); - size = ((uint32_t *)&body[c])[0]; - c += size+sizeof(uint32_t); - } - } while(c < blen); - - if (pd->user == NULL || *pd->user == '\0') return EINVAL; - - DEBUG_PAM_DATA(4, pd); - - return EOK; - -} - -static int pam_parse_in_data_v3(struct sss_names_ctx *snctx, - struct pam_data *pd, - uint8_t *body, size_t blen) -{ - int ret; - - ret = pam_parse_in_data_v2(snctx, pd, body, blen); - if (ret != EOK) { - DEBUG(1, ("pam_parse_in_data_v2 failed.\n")); - return ret; - } - - if (pd->cli_pid == 0) { - DEBUG(1, ("Missing client PID.\n")); - return EINVAL; - } - - return EOK; -} - -static int pam_parse_in_data(struct sss_names_ctx *snctx, - struct pam_data *pd, - uint8_t *body, size_t blen) -{ - int start; - int end; - int last; - int ret; - - last = blen - 1; - end = 0; - - /* user name */ - for (start = end; end < last; end++) if (body[end] == '\0') break; - if (body[end++] != '\0') return EINVAL; - - ret = sss_parse_name(pd, snctx, (char *)&body[start], &pd->domain, &pd->user); - if (ret != EOK) return ret; - - for (start = end; end < last; end++) if (body[end] == '\0') break; - if (body[end++] != '\0') return EINVAL; - pd->service = (char *) &body[start]; - - for (start = end; end < last; end++) if (body[end] == '\0') break; - if (body[end++] != '\0') return EINVAL; - pd->tty = (char *) &body[start]; - - for (start = end; end < last; end++) if (body[end] == '\0') break; - if (body[end++] != '\0') return EINVAL; - pd->ruser = (char *) &body[start]; - - for (start = end; end < last; end++) if (body[end] == '\0') break; - if (body[end++] != '\0') return EINVAL; - pd->rhost = (char *) &body[start]; - - start = end; - pd->authtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->authtok_size = (int) body[start]; - - start += sizeof(uint32_t); - end = start + pd->authtok_size; - if (pd->authtok_size == 0) { - pd->authtok = NULL; - } else { - if (end <= blen) { - pd->authtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid authtok size: %d\n", pd->authtok_size)); - return EINVAL; - } - } - - start = end; - pd->newauthtok_type = (int) body[start]; - - start += sizeof(uint32_t); - pd->newauthtok_size = (int) body[start]; - - start += sizeof(uint32_t); - end = start + pd->newauthtok_size; - - if (pd->newauthtok_size == 0) { - pd->newauthtok = NULL; - } else { - if (end <= blen) { - pd->newauthtok = (uint8_t *) &body[start]; - } else { - DEBUG(1, ("Invalid newauthtok size: %d\n", pd->newauthtok_size)); - return EINVAL; - } - } - - DEBUG_PAM_DATA(4, pd); - - return EOK; -} - -/*=Save-Last-Login-State===================================================*/ - -struct set_last_login_state { - struct tevent_context *ev; - struct sysdb_ctx *dbctx; - - struct sss_domain_info *dom; - const char *username; - struct sysdb_attrs *attrs; - - struct sysdb_handle *handle; - - struct ldb_result *res; -}; - -static void set_last_login_trans_done(struct tevent_req *subreq); -static void set_last_login_attrs_done(struct tevent_req *subreq); -static void set_last_login_done(struct tevent_req *subreq); - -static struct tevent_req *set_last_login_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sysdb_ctx *dbctx, - struct sss_domain_info *dom, - const char *username, - struct sysdb_attrs *attrs) -{ - struct tevent_req *req, *subreq; - struct set_last_login_state *state; - - req = tevent_req_create(memctx, &state, struct set_last_login_state); - if (!req) { - return NULL; - } - - state->ev = ev; - state->dbctx = dbctx; - state->dom = dom; - state->username = username; - state->attrs = attrs; - state->handle = NULL; - - subreq = sysdb_transaction_send(state, state->ev, state->dbctx); - if (!subreq) { - talloc_free(req); - return NULL; - } - tevent_req_set_callback(subreq, set_last_login_trans_done, req); - - return req; -} - -static void set_last_login_trans_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct set_last_login_state *state = tevent_req_data(req, - struct set_last_login_state); - int ret; - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - talloc_zfree(subreq); - if (ret != EOK) { - DEBUG(1, ("Unable to acquire sysdb transaction lock\n")); - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_set_user_attr_send(state, state->ev, state->handle, - state->dom, state->username, - state->attrs, SYSDB_MOD_REP); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, set_last_login_attrs_done, req); -} - -static void set_last_login_attrs_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct set_last_login_state *state = tevent_req_data(req, - struct set_last_login_state); - int ret; - - ret = sysdb_set_user_attr_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - DEBUG(4, ("set_user_attr_callback, status [%d][%s]\n", - ret, strerror(ret))); - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, set_last_login_done, req); -} - -static void set_last_login_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - int ret; - - ret = sysdb_transaction_commit_recv(subreq); - if (ret != EOK) { - DEBUG(2, ("set_last_login failed.\n")); - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -static int set_last_login_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - -/*=========================================================================*/ - - -static void set_last_login_reply(struct tevent_req *req); - -static errno_t set_last_login(struct pam_auth_req *preq) -{ - struct tevent_req *req; - struct sysdb_ctx *dbctx; - struct sysdb_attrs *attrs; - errno_t ret; - - attrs = sysdb_new_attrs(preq); - if (!attrs) { - ret = ENOMEM; - goto fail; - } - - ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_ONLINE_AUTH, time(NULL)); - if (ret != EOK) { - goto fail; - } - - ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list, preq->domain, - &dbctx); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb context not found for this domain!\n")); - goto fail; - } - - req = set_last_login_send(preq, preq->cctx->ev, dbctx, - preq->domain, preq->pd->user, attrs); - if (!req) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(req, set_last_login_reply, preq); - - return EOK; - -fail: - return ret; -} - -static void set_last_login_reply(struct tevent_req *req) -{ - struct pam_auth_req *preq = tevent_req_callback_data(req, - struct pam_auth_req); - int ret; - - ret = set_last_login_recv(req); - if (ret != EOK) { - preq->pd->pam_status = PAM_SYSTEM_ERR; - } else { - preq->pd->last_auth_saved = true; - } - - preq->callback(preq); -} - -static void pam_reply_delay(struct tevent_context *ev, struct tevent_timer *te, - struct timeval tv, void *pvt) -{ - struct pam_auth_req *preq; - - DEBUG(4, ("pam_reply_delay get called.\n")); - - preq = talloc_get_type(pvt, struct pam_auth_req); - - pam_reply(preq); -} - -static void pam_cache_auth_done(struct tevent_req *req); - -static void pam_reply(struct pam_auth_req *preq) -{ - struct cli_ctx *cctx; - uint8_t *body; - size_t blen; - int ret; - int32_t resp_c; - int32_t resp_size; - struct response_data *resp; - int p; - struct timeval tv; - struct tevent_timer *te; - struct pam_data *pd; - struct tevent_req *req; - struct sysdb_ctx *sysdb; - struct pam_ctx *pctx; - uint32_t user_info_type; - - pd = preq->pd; - cctx = preq->cctx; - - DEBUG(4, ("pam_reply get called.\n")); - - if (pd->pam_status == PAM_AUTHINFO_UNAVAIL) { - switch(pd->cmd) { - case SSS_PAM_AUTHENTICATE: - if ((preq->domain != NULL) && - (preq->domain->cache_credentials == true) && - (pd->offline_auth == false)) { - - /* do auth with offline credentials */ - pd->offline_auth = true; - - ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list, - preq->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for " - "domain [%s]!\n", preq->domain->name)); - goto done; - } - - pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, - struct pam_ctx); - - req = sysdb_cache_auth_send(preq, preq->cctx->ev, sysdb, - preq->domain, pd->user, - pd->authtok, pd->authtok_size, - pctx->rctx->cdb); - if (req == NULL) { - DEBUG(1, ("Failed to setup offline auth.\n")); - /* this error is not fatal, continue */ - } else { - tevent_req_set_callback(req, pam_cache_auth_done, preq); - return; - } - } - break; - case SSS_PAM_CHAUTHTOK_PRELIM: - case SSS_PAM_CHAUTHTOK: - DEBUG(5, ("Password change not possible while offline.\n")); - pd->pam_status = PAM_AUTHTOK_ERR; - user_info_type = SSS_PAM_USER_INFO_OFFLINE_CHPASS; - pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t), - (const uint8_t *) &user_info_type); - break; -/* TODO: we need the pam session cookie here to make sure that cached - * authentication was successful */ - case SSS_PAM_SETCRED: - case SSS_PAM_ACCT_MGMT: - case SSS_PAM_OPEN_SESSION: - case SSS_PAM_CLOSE_SESSION: - DEBUG(2, ("Assuming offline authentication setting status for " - "pam call %d to PAM_SUCCESS.\n", pd->cmd)); - pd->pam_status = PAM_SUCCESS; - break; - default: - DEBUG(1, ("Unknown PAM call [%d].\n", pd->cmd)); - pd->pam_status = PAM_MODULE_UNKNOWN; - } - } - - if (pd->response_delay > 0) { - ret = gettimeofday(&tv, NULL); - if (ret != EOK) { - DEBUG(1, ("gettimeofday failed [%d][%s].\n", - errno, strerror(errno))); - goto done; - } - tv.tv_sec += pd->response_delay; - tv.tv_usec = 0; - pd->response_delay = 0; - - te = tevent_add_timer(cctx->ev, cctx, tv, pam_reply_delay, preq); - if (te == NULL) { - DEBUG(1, ("Failed to add event pam_reply_delay.\n")); - goto done; - } - - return; - } - - /* If this was a successful login, save the lastLogin time */ - if (pd->cmd == SSS_PAM_AUTHENTICATE && - pd->pam_status == PAM_SUCCESS && - preq->domain->cache_credentials && - !pd->offline_auth && - !pd->last_auth_saved && - NEED_CHECK_PROVIDER(preq->domain->provider)) { - ret = set_last_login(preq); - if (ret != EOK) { - goto done; - } - - return; - } - - ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - goto done; - } - - if (pd->domain != NULL) { - pam_add_response(pd, SSS_PAM_DOMAIN_NAME, strlen(pd->domain)+1, - (uint8_t *) pd->domain); - } - - resp_c = 0; - resp_size = 0; - resp = pd->resp_list; - while(resp != NULL) { - resp_c++; - resp_size += resp->len; - resp = resp->next; - } - - ret = sss_packet_grow(cctx->creq->out, sizeof(int32_t) + - sizeof(int32_t) + - resp_c * 2* sizeof(int32_t) + - resp_size); - if (ret != EOK) { - goto done; - } - - sss_packet_get_body(cctx->creq->out, &body, &blen); - DEBUG(4, ("blen: %d\n", blen)); - p = 0; - - memcpy(&body[p], &pd->pam_status, sizeof(int32_t)); - p += sizeof(int32_t); - - memcpy(&body[p], &resp_c, sizeof(int32_t)); - p += sizeof(int32_t); - - resp = pd->resp_list; - while(resp != NULL) { - memcpy(&body[p], &resp->type, sizeof(int32_t)); - p += sizeof(int32_t); - memcpy(&body[p], &resp->len, sizeof(int32_t)); - p += sizeof(int32_t); - memcpy(&body[p], resp->data, resp->len); - p += resp->len; - - resp = resp->next; - } - -done: - sss_cmd_done(cctx, preq); -} - -static void pam_cache_auth_done(struct tevent_req *req) -{ - int ret; - struct pam_auth_req *preq = tevent_req_callback_data(req, - struct pam_auth_req); - uint32_t resp_type; - size_t resp_len; - uint8_t *resp; - time_t expire_date = 0; - time_t delayed_until = -1; - long long dummy; - - ret = sysdb_cache_auth_recv(req, &expire_date, &delayed_until); - talloc_zfree(req); - - switch (ret) { - case EOK: - preq->pd->pam_status = PAM_SUCCESS; - - resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH; - resp_len = sizeof(uint32_t) + sizeof(long long); - resp = talloc_size(preq->pd, resp_len); - if (resp == NULL) { - DEBUG(1, ("talloc_size failed, cannot prepare user info.\n")); - } else { - memcpy(resp, &resp_type, sizeof(uint32_t)); - dummy = (long long) expire_date; - memcpy(resp+sizeof(uint32_t), &dummy, sizeof(long long)); - ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len, - (const uint8_t *) resp); - if (ret != EOK) { - DEBUG(1, ("pam_add_response failed.\n")); - } - } - break; - case ENOENT: - preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; - break; - case EINVAL: - preq->pd->pam_status = PAM_AUTH_ERR; - break; - case EACCES: - preq->pd->pam_status = PAM_PERM_DENIED; - if (delayed_until >= 0) { - resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH_DELAYED; - resp_len = sizeof(uint32_t) + sizeof(long long); - resp = talloc_size(preq->pd, resp_len); - if (resp == NULL) { - DEBUG(1, ("talloc_size failed, cannot prepare user info.\n")); - } else { - memcpy(resp, &resp_type, sizeof(uint32_t)); - dummy = (long long) delayed_until; - memcpy(resp+sizeof(uint32_t), &dummy, sizeof(long long)); - ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len, - (const uint8_t *) resp); - if (ret != EOK) { - DEBUG(1, ("pam_add_response failed.\n")); - } - } - } - break; - default: - preq->pd->pam_status = PAM_SYSTEM_ERR; - } - - pam_reply(preq); - return; -} - -static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); -static void pam_check_user_callback(void *ptr, int status, - struct ldb_result *res); -static void pam_dom_forwarder(struct pam_auth_req *preq); - -/* TODO: we should probably return some sort of cookie that is set in the - * PAM_ENVIRONMENT, so that we can save performing some calls and cache - * data. */ - -static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) -{ - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct pam_auth_req *preq; - struct pam_data *pd; - uint8_t *body; - size_t blen; - int timeout; - int ret; - uint32_t terminator = SSS_END_OF_PAM_REQUEST; - preq = talloc_zero(cctx, struct pam_auth_req); - if (!preq) { - return ENOMEM; - } - preq->cctx = cctx; - - preq->pd = talloc_zero(preq, struct pam_data); - if (!preq->pd) { - talloc_free(preq); - return ENOMEM; - } - pd = preq->pd; - - sss_packet_get_body(cctx->creq->in, &body, &blen); - if (blen >= sizeof(uint32_t) && - memcmp(&body[blen - sizeof(uint32_t)], &terminator, sizeof(uint32_t)) != 0) { - DEBUG(1, ("Received data not terminated.\n")); - ret = EINVAL; - goto done; - } - - pd->cmd = pam_cmd; - pd->priv = cctx->priv; - - switch (cctx->cli_protocol_version->version) { - case 1: - ret = pam_parse_in_data(cctx->rctx->names, pd, body, blen); - break; - case 2: - ret = pam_parse_in_data_v2(cctx->rctx->names, pd, body, blen); - break; - case 3: - ret = pam_parse_in_data_v3(cctx->rctx->names, pd, body, blen); - break; - default: - DEBUG(1, ("Illegal protocol version [%d].\n", - cctx->cli_protocol_version->version)); - ret = EINVAL; - } - if (ret != EOK) { - ret = EINVAL; - goto done; - } - - /* now check user is valid */ - if (pd->domain) { - for (dom = cctx->rctx->domains; dom; dom = dom->next) { - if (strcasecmp(dom->name, pd->domain) == 0) break; - } - if (!dom) { - ret = ENOENT; - goto done; - } - preq->domain = dom; - } - else { - for (dom = preq->cctx->rctx->domains; dom; dom = dom->next) { - if (dom->fqnames) continue; - -/* FIXME: need to support negative cache */ -#if HAVE_NEG_CACHE - ncret = sss_ncache_check_user(nctx->ncache, nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; -#endif - break; - } - if (!dom) { - ret = ENOENT; - goto done; - } - preq->domain = dom; - } - - if (preq->domain->provider == NULL) { - DEBUG(1, ("Domain [%s] has no auth provider.\n", preq->domain->name)); - ret = EINVAL; - goto done; - } - - /* When auth is requested always search the provider first, - * do not rely on cached data unless the provider is completely - * offline */ - if (NEED_CHECK_PROVIDER(preq->domain->provider) && - (pam_cmd == SSS_PAM_AUTHENTICATE || pam_cmd == SSS_PAM_SETCRED)) { - - /* no need to re-check later on */ - preq->check_provider = false; - timeout = SSS_CLI_SOCKET_TIMEOUT/2; - - ret = sss_dp_send_acct_req(preq->cctx->rctx, preq, - pam_check_user_dp_callback, preq, - timeout, preq->domain->name, - false, SSS_DP_INITGROUPS, - preq->pd->user, 0); - } - else { - preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider); - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - preq->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - goto done; - } - ret = sysdb_getpwnam(preq, sysdb, - preq->domain, preq->pd->user, - pam_check_user_callback, preq); - } - -done: - if (ret != EOK) { - switch (ret) { - case ENOENT: - pd->pam_status = PAM_USER_UNKNOWN; - default: - pd->pam_status = PAM_SYSTEM_ERR; - } - pam_reply(preq); - } - return EOK; -} - -static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) -{ - struct pam_auth_req *preq = talloc_get_type(ptr, struct pam_auth_req); - struct sysdb_ctx *sysdb; - int ret; - - if (err_maj) { - DEBUG(2, ("Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg)); - } - - /* always try to see if we have the user in cache even if the provider - * returned an error */ - ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list, - preq->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - goto done; - } - ret = sysdb_getpwnam(preq, sysdb, - preq->domain, preq->pd->user, - pam_check_user_callback, preq); - -done: - if (ret != EOK) { - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - } -} - -static void pam_check_user_callback(void *ptr, int status, - struct ldb_result *res) -{ - struct pam_auth_req *preq = talloc_get_type(ptr, struct pam_auth_req); - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - uint64_t cacheExpire; - bool call_provider = false; - time_t timeout; - int ret; - - if (status != LDB_SUCCESS) { - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - return; - } - - timeout = SSS_CLI_SOCKET_TIMEOUT/2; - - if (preq->check_provider) { - switch (res->count) { - case 0: - call_provider = true; - break; - - case 1: - cacheExpire = ldb_msg_find_attr_as_uint64(res->msgs[0], - SYSDB_CACHE_EXPIRE, 0); - if (cacheExpire < time(NULL)) { - call_provider = true; - } - break; - - default: - DEBUG(1, ("check user call returned more than one result !?!\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - return; - } - } - - if (call_provider) { - - /* dont loop forever :-) */ - preq->check_provider = false; - - /* keep around current data in case backend is offline */ - if (res->count) { - preq->data = talloc_steal(preq, res); - } - - ret = sss_dp_send_acct_req(preq->cctx->rctx, preq, - pam_check_user_dp_callback, preq, - timeout, preq->domain->name, - false, SSS_DP_USER, - preq->pd->user, 0); - if (ret != EOK) { - DEBUG(3, ("Failed to dispatch request: %d(%s)\n", - ret, strerror(ret))); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - } - return; - } - - switch (res->count) { - case 0: - if (!preq->pd->domain) { - /* search next as the domain was unknown */ - - ret = EOK; - - /* skip domains that require FQnames or have negative caches */ - for (dom = preq->domain->next; dom; dom = dom->next) { - - if (dom->fqnames) continue; - -#if HAVE_NEG_CACHE - ncret = nss_ncache_check_user(nctx->ncache, - nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; - - neghit = true; -#endif - break; - } -#if HAVE_NEG_CACHE - /* reset neghit if we still have a domain to check */ - if (dom) neghit = false; - - if (neghit) { - DEBUG(2, ("User [%s] does not exist! (negative cache)\n", - cmdctx->name)); - ret = ENOENT; - } -#endif - if (dom == NULL) { - DEBUG(2, ("No matching domain found for [%s], fail!\n", - preq->pd->user)); - ret = ENOENT; - } - - if (ret == EOK) { - preq->domain = dom; - preq->data = NULL; - - DEBUG(4, ("Requesting info for [%s@%s]\n", - preq->pd->user, preq->domain->name)); - - /* When auth is requested always search the provider first, - * do not rely on cached data unless the provider is - * completely offline */ - if (NEED_CHECK_PROVIDER(preq->domain->provider) && - (preq->pd->cmd == SSS_PAM_AUTHENTICATE || - preq->pd->cmd == SSS_PAM_SETCRED)) { - - /* no need to re-check later on */ - preq->check_provider = false; - - ret = sss_dp_send_acct_req(preq->cctx->rctx, preq, - pam_check_user_dp_callback, - preq, timeout, - preq->domain->name, - false, SSS_DP_USER, - preq->pd->user, 0); - } - else { - preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider); - - ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list, - preq->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - return; - } - ret = sysdb_getpwnam(preq, sysdb, - preq->domain, preq->pd->user, - pam_check_user_callback, preq); - } - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } - } - - /* we made another call, end here */ - if (ret == EOK) return; - } - else { - ret = ENOENT; - } - - DEBUG(2, ("No results for check user call\n")); - -#if HAVE_NEG_CACHE - /* set negative cache only if not result of cache check */ - if (!neghit) { - ret = nss_ncache_set_user(nctx->ncache, false, - dctx->domain->name, cmdctx->name); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - } -#endif - - if (ret != EOK) { - if (ret == ENOENT) { - preq->pd->pam_status = PAM_USER_UNKNOWN; - } else { - preq->pd->pam_status = PAM_SYSTEM_ERR; - } - pam_reply(preq); - return; - } - break; - - case 1: - - /* BINGO */ - preq->pd->pw_uid = - ldb_msg_find_attr_as_int(res->msgs[0], SYSDB_UIDNUM, -1); - if (preq->pd->pw_uid == -1) { - DEBUG(1, ("Failed to find uid for user [%s] in domain [%s].\n", - preq->pd->user, preq->pd->domain)); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - } - - preq->pd->gr_gid = - ldb_msg_find_attr_as_int(res->msgs[0], SYSDB_GIDNUM, -1); - if (preq->pd->gr_gid == -1) { - DEBUG(1, ("Failed to find gid for user [%s] in domain [%s].\n", - preq->pd->user, preq->pd->domain)); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - } - - pam_dom_forwarder(preq); - return; - - default: - DEBUG(1, ("check user call returned more than one result !?!\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - } -} - -static void pam_dom_forwarder(struct pam_auth_req *preq) -{ - int ret; - - if (!preq->pd->domain) { - preq->pd->domain = preq->domain->name; - } - - if (!NEED_CHECK_PROVIDER(preq->domain->provider)) { - preq->callback = pam_reply; - ret = LOCAL_pam_handler(preq); - } - else { - preq->callback = pam_reply; - ret = pam_dp_send_req(preq, SSS_CLI_SOCKET_TIMEOUT/2); - DEBUG(4, ("pam_dp_send_req returned %d\n", ret)); - } - - if (ret != EOK) { - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - } -} - -static int pam_cmd_authenticate(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_authenticate\n")); - return pam_forwarder(cctx, SSS_PAM_AUTHENTICATE); -} - -static int pam_cmd_setcred(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_setcred\n")); - return pam_forwarder(cctx, SSS_PAM_SETCRED); -} - -static int pam_cmd_acct_mgmt(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_acct_mgmt\n")); - return pam_forwarder(cctx, SSS_PAM_ACCT_MGMT); -} - -static int pam_cmd_open_session(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_open_session\n")); - return pam_forwarder(cctx, SSS_PAM_OPEN_SESSION); -} - -static int pam_cmd_close_session(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_close_session\n")); - return pam_forwarder(cctx, SSS_PAM_CLOSE_SESSION); -} - -static int pam_cmd_chauthtok(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_chauthtok\n")); - return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK); -} - -static int pam_cmd_chauthtok_prelim(struct cli_ctx *cctx) { - DEBUG(4, ("entering pam_cmd_chauthtok_prelim\n")); - return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK_PRELIM); -} - -struct cli_protocol_version *register_cli_protocol_version(void) -{ - static struct cli_protocol_version pam_cli_protocol_version[] = { - {3, "2009-09-14", "make cli_pid mandatory"}, - {2, "2009-05-12", "new format "}, - {1, "2008-09-05", "initial version, \\0 terminated strings"}, - {0, NULL, NULL} - }; - - return pam_cli_protocol_version; -} - -struct sss_cmd_table *get_pam_cmds(void) -{ - static struct sss_cmd_table sss_cmds[] = { - {SSS_GET_VERSION, sss_cmd_get_version}, - {SSS_PAM_AUTHENTICATE, pam_cmd_authenticate}, - {SSS_PAM_SETCRED, pam_cmd_setcred}, - {SSS_PAM_ACCT_MGMT, pam_cmd_acct_mgmt}, - {SSS_PAM_OPEN_SESSION, pam_cmd_open_session}, - {SSS_PAM_CLOSE_SESSION, pam_cmd_close_session}, - {SSS_PAM_CHAUTHTOK, pam_cmd_chauthtok}, - {SSS_PAM_CHAUTHTOK_PRELIM, pam_cmd_chauthtok_prelim}, - {SSS_CLI_NULL, NULL} - }; - - return sss_cmds; -} diff --git a/server/responder/pam/pamsrv_dp.c b/server/responder/pam/pamsrv_dp.c deleted file mode 100644 index 071d09b8..00000000 --- a/server/responder/pam/pamsrv_dp.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - SSSD - - NSS Responder - Data Provider Interfaces - - Copyright (C) Simo Sorce 2008 - - 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 -#include - -#include -#include - -#include "util/util.h" -#include "responder/common/responder_packet.h" -#include "providers/data_provider.h" -#include "sbus/sbus_client.h" -#include "responder/pam/pamsrv.h" - -static void pam_dp_process_reply(DBusPendingCall *pending, void *ptr) -{ - DBusError dbus_error; - DBusMessage* msg; - int ret; - int type; - struct pam_auth_req *preq; - - preq = talloc_get_type(ptr, struct pam_auth_req); - - dbus_error_init(&dbus_error); - - dbus_pending_call_block(pending); - msg = dbus_pending_call_steal_reply(pending); - if (msg == NULL) { - DEBUG(0, ("Severe error. A reply callback was called but no reply was received and no timeout occurred\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - - - type = dbus_message_get_type(msg); - switch (type) { - case DBUS_MESSAGE_TYPE_METHOD_RETURN: - ret = dp_unpack_pam_response(msg, preq->pd, &dbus_error); - if (!ret) { - DEBUG(0, ("Failed to parse reply.\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - DEBUG(4, ("received: [%d][%s]\n", preq->pd->pam_status, preq->pd->domain)); - break; - case DBUS_MESSAGE_TYPE_ERROR: - DEBUG(0, ("Reply error.\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - break; - default: - DEBUG(0, ("Default... what now?.\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - } - - -done: - dbus_pending_call_unref(pending); - dbus_message_unref(msg); - preq->callback(preq); -} - -int pam_dp_send_req(struct pam_auth_req *preq, int timeout) -{ - struct pam_data *pd = preq->pd; - struct be_conn *be_conn; - DBusMessage *msg; - DBusPendingCall *pending_reply; - DBusConnection *dbus_conn; - dbus_bool_t ret; - int res; - - /* double check dp_ctx has actually been initialized. - * in some pathological cases it may happen that nss starts up before - * dp connection code is actually able to establish a connection. - */ - res = sss_dp_get_domain_conn(preq->cctx->rctx, - preq->domain->name, &be_conn); - if (res != EOK) { - DEBUG(1, ("The Data Provider connection for %s is not available!" - " This maybe a bug, it shouldn't happen!\n", preq->domain)); - return EIO; - } - dbus_conn = sbus_get_connection(be_conn->conn); - - msg = dbus_message_new_method_call(NULL, - DP_PATH, - DP_INTERFACE, - DP_METHOD_PAMHANDLER); - if (msg == NULL) { - DEBUG(0,("Out of memory?!\n")); - return ENOMEM; - } - - - DEBUG(4, ("Sending request with the following data:\n")); - DEBUG_PAM_DATA(4, pd); - - ret = dp_pack_pam_request(msg, pd); - if (!ret) { - DEBUG(1,("Failed to build message\n")); - return EIO; - } - - ret = dbus_connection_send_with_reply(dbus_conn, msg, &pending_reply, timeout); - if (!ret || pending_reply == NULL) { - /* - * Critical Failure - * We can't communicate on this connection - * We'll drop it using the default destructor. - */ - DEBUG(0, ("D-BUS send failed.\n")); - dbus_message_unref(msg); - return EIO; - } - - dbus_pending_call_set_notify(pending_reply, - pam_dp_process_reply, preq, NULL); - dbus_message_unref(msg); - - return EOK; -} - -- cgit