pamsrv_cmd.c revision a97f6203967b801d666ac686cdb7c76a7dfe55a9
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek/*
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek SSSD
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek PAM Responder
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek Copyright (C) Simo Sorce <ssorce@redhat.com> 2009
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek Copyright (C) Sumit Bose <sbose@redhat.com> 2009
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek This program is free software; you can redistribute it and/or modify
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek it under the terms of the GNU General Public License as published by
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek the Free Software Foundation; either version 3 of the License, or
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek (at your option) any later version.
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek This program is distributed in the hope that it will be useful,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek but WITHOUT ANY WARRANTY; without even the implied warranty of
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek GNU General Public License for more details.
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek You should have received a copy of the GNU General Public License
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek along with this program. If not, see <http://www.gnu.org/licenses/>.
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek*/
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include <time.h>
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include "util/util.h"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include "util/sss_selinux.h"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include "db/sysdb.h"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include "confdb/confdb.h"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include "responder/common/responder_packet.h"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include "responder/common/responder.h"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include "responder/common/negcache.h"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include "providers/data_provider.h"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include "responder/pam/pamsrv.h"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include "responder/pam/pam_helpers.h"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include "db/sysdb.h"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include "db/sysdb_selinux.h"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#ifdef HAVE_SELINUX_LOGIN_DIR
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#include <selinux/selinux.h>
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#endif
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekenum pam_verbosity {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek PAM_VERBOSITY_NO_MESSAGES = 0,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek PAM_VERBOSITY_IMPORTANT,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek PAM_VERBOSITY_INFO,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek PAM_VERBOSITY_DEBUG
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek};
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#define DEFAULT_PAM_VERBOSITY PAM_VERBOSITY_IMPORTANT
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic void pam_reply(struct pam_auth_req *preq);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek size_t data_size, uint8_t *body, size_t blen,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek size_t *c) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (data_size < sizeof(uint32_t) || *c+data_size > blen ||
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek SIZE_T_OVERFLOW(*c, data_size)) return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek *size = data_size - sizeof(uint32_t);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek SAFEALIGN_COPY_UINT32_CHECK(type, &body[*c], blen, c);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek *tok = body+(*c);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek *c += (*size);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EOK;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek}
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic int extract_string(char **var, size_t size, uint8_t *body, size_t blen,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek size_t *c) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek uint8_t *str;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (*c+size > blen || SIZE_T_OVERFLOW(*c, size)) return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek str = body+(*c);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (str[size-1]!='\0') return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* If the string isn't valid UTF-8, fail */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (!sss_utf8_check(str, size-1)) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek *c += size;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek *var = (char *) str;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EOK;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek}
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic int extract_uint32_t(uint32_t *var, size_t size, uint8_t *body,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek size_t blen, size_t *c) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (size != sizeof(uint32_t) || *c+size > blen || SIZE_T_OVERFLOW(*c, size))
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek SAFEALIGN_COPY_UINT32_CHECK(var, &body[*c], blen, c);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EOK;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek}
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic int pd_set_primary_name(const struct ldb_message *msg,struct pam_data *pd)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek{
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek const char *name;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (!name) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, ("A user with no name?\n"));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EIO;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (strcmp(pd->user, name)) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_TRACE_FUNC, ("User's primary name is %s\n", name));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek talloc_free(pd->user);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pd->user = talloc_strdup(pd, name);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (!pd->user) return ENOMEM;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EOK;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek}
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic int pam_parse_in_data_v2(struct sss_domain_info *domains,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek const char *default_domain,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek struct pam_data *pd,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek uint8_t *body, size_t blen)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek{
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek size_t c;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek uint32_t type;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek uint32_t size;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek char *pam_user;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek int ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek uint32_t terminator = SSS_END_OF_PAM_REQUEST;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (blen < 4*sizeof(uint32_t)+2 ||
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ((uint32_t *)body)[0] != SSS_START_OF_PAM_REQUEST ||
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek memcmp(&body[blen - sizeof(uint32_t)], &terminator, sizeof(uint32_t)) != 0) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(1, ("Received data is invalid.\n"));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek c = sizeof(uint32_t);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek do {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek SAFEALIGN_COPY_UINT32_CHECK(&type, &body[c], blen, &c);
7c5cd2e7711621af9163a41393e88896a91ac33bJakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (type == SSS_END_OF_PAM_REQUEST) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (c != blen) return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek } else {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek SAFEALIGN_COPY_UINT32_CHECK(&size, &body[c], blen, &c);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* the uint32_t end maker SSS_END_OF_PAM_REQUEST does not count to
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * the remaining buffer */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (size > (blen - c - sizeof(uint32_t))) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(1, ("Invalid data size.\n"));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek switch(type) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek case SSS_PAM_ITEM_USER:
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = extract_string(&pam_user, size, body, blen, &c);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = sss_parse_name_for_domains(pd, domains,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek default_domain, pam_user,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek &pd->domain, &pd->user);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek case SSS_PAM_ITEM_SERVICE:
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = extract_string(&pd->service, size, body, blen, &c);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek case SSS_PAM_ITEM_TTY:
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = extract_string(&pd->tty, size, body, blen, &c);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek case SSS_PAM_ITEM_RUSER:
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = extract_string(&pd->ruser, size, body, blen, &c);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek case SSS_PAM_ITEM_RHOST:
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = extract_string(&pd->rhost, size, body, blen, &c);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek case SSS_PAM_ITEM_CLI_PID:
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = extract_uint32_t(&pd->cli_pid, size,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek body, blen, &c);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek case SSS_PAM_ITEM_AUTHTOK:
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = extract_authtok(&pd->authtok_type, &pd->authtok_size,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek &pd->authtok, size, body, blen, &c);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek case SSS_PAM_ITEM_NEWAUTHTOK:
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = extract_authtok(&pd->newauthtok_type,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek &pd->newauthtok_size,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek &pd->newauthtok, size, body, blen, &c);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek default:
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(1,("Ignoring unknown data type [%d].\n", type));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek c += size;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek } while(c < blen);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (pd->user == NULL || *pd->user == '\0') return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG_PAM_DATA(4, pd);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EOK;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek}
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic int pam_parse_in_data_v3(struct sss_domain_info *domains,
7c5cd2e7711621af9163a41393e88896a91ac33bJakub Hrozek const char *default_domain,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek struct pam_data *pd,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek uint8_t *body, size_t blen)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek{
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek int ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = pam_parse_in_data_v2(domains, default_domain, pd, body, blen);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(1, ("pam_parse_in_data_v2 failed.\n"));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (pd->cli_pid == 0) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(1, ("Missing client PID.\n"));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EOK;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek}
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic int pam_parse_in_data(struct sss_domain_info *domains,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek const char *default_domain,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek struct pam_data *pd,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek uint8_t *body, size_t blen)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek{
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek int start;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek int end;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek int last;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek int ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek last = blen - 1;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek end = 0;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* user name */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek for (start = end; end < last; end++) if (body[end] == '\0') break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (body[end++] != '\0') return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = sss_parse_name_for_domains(pd, domains, default_domain,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek (char *)&body[start], &pd->domain, &pd->user);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek for (start = end; end < last; end++) if (body[end] == '\0') break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (body[end++] != '\0') return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pd->service = (char *) &body[start];
7c5cd2e7711621af9163a41393e88896a91ac33bJakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek for (start = end; end < last; end++) if (body[end] == '\0') break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (body[end++] != '\0') return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pd->tty = (char *) &body[start];
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek for (start = end; end < last; end++) if (body[end] == '\0') break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (body[end++] != '\0') return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pd->ruser = (char *) &body[start];
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek for (start = end; end < last; end++) if (body[end] == '\0') break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (body[end++] != '\0') return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pd->rhost = (char *) &body[start];
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek start = end;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pd->authtok_type = (int) body[start];
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek start += sizeof(uint32_t);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pd->authtok_size = (int) body[start];
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (pd->authtok_size >= blen) return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek start += sizeof(uint32_t);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek end = start + pd->authtok_size;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (pd->authtok_size == 0) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pd->authtok = NULL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek } else {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (end <= blen) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pd->authtok = (uint8_t *) &body[start];
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek } else {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(1, ("Invalid authtok size: %d\n", pd->authtok_size));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek start = end;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pd->newauthtok_type = (int) body[start];
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek start += sizeof(uint32_t);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pd->newauthtok_size = (int) body[start];
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (pd->newauthtok_size >= blen) return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek start += sizeof(uint32_t);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek end = start + pd->newauthtok_size;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (pd->newauthtok_size == 0) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pd->newauthtok = NULL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek } else {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (end <= blen) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pd->newauthtok = (uint8_t *) &body[start];
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek } else {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(1, ("Invalid newauthtok size: %d\n", pd->newauthtok_size));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG_PAM_DATA(4, pd);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EOK;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek}
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek/*=Save-Last-Login-State===================================================*/
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic errno_t set_last_login(struct pam_auth_req *preq)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek{
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek struct sysdb_ctx *dbctx;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek struct sysdb_attrs *attrs;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek errno_t ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek attrs = sysdb_new_attrs(preq);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (!attrs) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = ENOMEM;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto fail;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_ONLINE_AUTH, time(NULL));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto fail;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_LOGIN, time(NULL));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto fail;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek dbctx = preq->domain->sysdb;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (dbctx == NULL) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(0, ("Fatal: Sysdb context not found for this domain!\n"));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto fail;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = sysdb_set_user_attr(dbctx, preq->pd->user, attrs, SYSDB_MOD_REP);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(2, ("set_last_login failed.\n"));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek preq->pd->pam_status = PAM_SYSTEM_ERR;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto fail;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek } else {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek preq->pd->last_auth_saved = true;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek preq->callback(preq);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EOK;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekfail:
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek}
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#ifdef HAVE_SELINUX_LOGIN_DIR
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#define ALL_SERVICES "*"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#define selogin_path(mem_ctx, username) \
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek talloc_asprintf(mem_ctx, "%s/logins/%s", selinux_policy_root(), username)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic errno_t write_selinux_login_file(const char *username, char *string)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek{
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek char *path = NULL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek char *tmp_path = NULL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ssize_t written;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek int len;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek int fd = -1;
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek mode_t oldmask;
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek TALLOC_CTX *tmp_ctx;
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek char *full_string = NULL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek errno_t ret = EOK;
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek len = strlen(string);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (len == 0) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek tmp_ctx = talloc_new(NULL);
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek if (tmp_ctx == NULL) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return ENOMEM;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek path = selogin_path(tmp_ctx, username);
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek if (path == NULL) {
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek ret = ENOMEM;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek tmp_path = talloc_asprintf(tmp_ctx, "%sXXXXXX", path);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (tmp_path == NULL) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = ENOMEM;
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek oldmask = umask(022);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek fd = mkstemp(tmp_path);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek umask(oldmask);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (fd < 0) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE, ("creating the temp file for SELinux "
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "data failed. %s", tmp_path));
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek ret = EIO;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek }
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek full_string = talloc_asprintf(tmp_ctx, "%s:%s", ALL_SERVICES, string);
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek if (full_string == NULL) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = ENOMEM;
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek len = strlen(full_string);
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek errno = 0;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek written = sss_atomic_write_s(fd, full_string, len);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (written == -1) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = errno;
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE, ("writing to SELinux data file %s"
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "failed [%d]: %s", tmp_path, ret,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek strerror(ret)));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (written != len) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE, ("Expected to write %d bytes, wrote %d",
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek written, len));
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek ret = EIO;
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek goto done;
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek }
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek errno = 0;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (rename(tmp_path, path) < 0) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = errno;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek } else {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = EOK;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek close(fd);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek fd = -1;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekdone:
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (fd != -1) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek close(fd);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (unlink(tmp_path) < 0) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_MINOR_FAILURE, ("Could not remove file [%s]",
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek tmp_path));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek talloc_free(tmp_ctx);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek}
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic errno_t remove_selinux_login_file(const char *username)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek{
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek char *path;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek errno_t ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek path = selogin_path(NULL, username);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (!path) return ENOMEM;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek errno = 0;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = unlink(path);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret < 0) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = errno;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret == ENOENT) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* Just return success if the file was not there */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = EOK;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek } else {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ("Could not remove login file %s [%d]: %s\n",
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek path, ret, strerror(ret)));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek talloc_free(path);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek}
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic errno_t process_selinux_mappings(struct pam_auth_req *preq)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek{
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek struct sysdb_ctx *sysdb;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek TALLOC_CTX *tmp_ctx;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek struct pam_data *pd = preq->pd;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek char *file_content = NULL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek struct ldb_message **usermaps;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek struct ldb_message *config;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek const char *default_user = NULL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek const char *tmp_str;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek char *order = NULL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek char **order_array;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek errno_t ret, err;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek int i, j;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek size_t order_count;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek size_t len = 0;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek tmp_ctx = talloc_new(NULL);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (tmp_ctx == NULL) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = ENOMEM;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek sysdb = preq->domain->sysdb;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (sysdb == NULL) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_FATAL_FAILURE, ("Fatal: Sysdb CTX not found for "
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "domain [%s]!\n", preq->domain->name));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = sysdb_search_selinux_config(tmp_ctx, sysdb, NULL, &config);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret == ENOENT) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_TRACE_INTERNAL, ("No SELinux support found for the domain\n"));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = EOK;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek } else if (ret != EOK) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek default_user = ldb_msg_find_attr_as_string(config,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek SYSDB_SELINUX_DEFAULT_USER,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek NULL);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (!default_user || default_user[0] == '\0') {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* Skip creating the maps altogether if there is no default
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * or empty default
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = EOK;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek tmp_str = ldb_msg_find_attr_as_string(config,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek SYSDB_SELINUX_DEFAULT_ORDER,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek NULL);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (tmp_str == NULL) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE, ("No map order given!\n"));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek order = talloc_strdup(tmp_ctx, tmp_str);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (order == NULL) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = ENOMEM;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek len = strlen(order);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* The "order" string contains one or more SELinux user records
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * separated by $. Now we need to create an array of string from
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * this one string. First find out how many elements in the array
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * will be. This way only one alloc will be necessary for the array
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek order_count = 1;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek for (i = 0; i < len; i++) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (order[i] == '$') order_count++;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek order_array = talloc_array(tmp_ctx, char *, order_count);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (order_array == NULL) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = ENOMEM;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* Now fill the array with pointers to the original string. Also
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * use binary zeros to make multiple string out of the one.
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek order_array[0] = order;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek order_count = 1;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek for (i = 0; i < len; i++) {
466f5a539be1e4c6e7cfb396a2f406e1eb8c428dLukas Slebodnik if (order[i] == '$') {
466f5a539be1e4c6e7cfb396a2f406e1eb8c428dLukas Slebodnik order[i] = '\0';
466f5a539be1e4c6e7cfb396a2f406e1eb8c428dLukas Slebodnik order_array[order_count] = &order[i+1];
466f5a539be1e4c6e7cfb396a2f406e1eb8c428dLukas Slebodnik order_count++;
466f5a539be1e4c6e7cfb396a2f406e1eb8c428dLukas Slebodnik }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* Fetch all maps applicable to the user who is currently logging in */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = sysdb_search_selinux_usermap_by_username(tmp_ctx, sysdb, pd->user,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek &usermaps);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK && ret != ENOENT) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* If no maps match, we'll use the default SELinux user from the
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * config */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek file_content = talloc_strdup(tmp_ctx, default_user);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (file_content == NULL) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = ENOMEM;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* Iterate through the order array and try to find SELinux users
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * in fetched maps. The order array contains all SELinux users
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * allowed in the domain in the same order they should appear
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * in the SELinux config file. If any user from the order array
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * is not in fetched user maps, it means it should not be allowed
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * for the user who is just logging in.
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek *
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * Right now we have empty content of the SELinux config file,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * we shall add only those SELinux users that are present both in
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * the order array and user maps applicable to the user who is
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * logging in.
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek for (i = 0; i < order_count; i++) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek for (j = 0; usermaps[j] != NULL; j++) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek tmp_str = sss_selinux_map_get_seuser(usermaps[j]);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (tmp_str && !strcasecmp(tmp_str, order_array[i])) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* If file_content contained something, overwrite it.
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * This record has higher priority.
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek talloc_zfree(file_content);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek file_content = talloc_strdup(tmp_ctx, tmp_str);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (file_content == NULL) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = ENOMEM;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek goto done;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek break;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = write_selinux_login_file(pd->user, file_content);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekdone:
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (!file_content) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek err = remove_selinux_login_file(pd->user);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* Don't overwrite original error condition if there was one */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret == EOK) ret = err;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek talloc_free(tmp_ctx);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek}
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#endif
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic errno_t filter_responses(struct confdb_ctx *cdb,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek struct response_data *resp_list)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek{
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek int ret;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek struct response_data *resp;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek uint32_t user_info_type;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek int64_t expire_date;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek int pam_verbosity;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek CONFDB_PAM_VERBOSITY, DEFAULT_PAM_VERBOSITY,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek &pam_verbosity);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (ret != EOK) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(1, ("Failed to read PAM verbosity, not fatal.\n"));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek pam_verbosity = DEFAULT_PAM_VERBOSITY;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek resp = resp_list;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek while(resp != NULL) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (resp->type == SSS_PAM_USER_INFO) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (resp->len < sizeof(uint32_t)) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(1, ("User info entry is too short.\n"));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek return EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (pam_verbosity == PAM_VERBOSITY_NO_MESSAGES) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek resp->do_not_send_to_client = true;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek resp = resp->next;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek continue;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek memcpy(&user_info_type, resp->data, sizeof(uint32_t));
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek
resp->do_not_send_to_client = false;
switch (user_info_type) {
case SSS_PAM_USER_INFO_OFFLINE_AUTH:
if (resp->len != sizeof(uint32_t) + sizeof(int64_t)) {
DEBUG(1, ("User info offline auth entry is "
"too short.\n"));
return EINVAL;
}
memcpy(&expire_date, resp->data + sizeof(uint32_t),
sizeof(int64_t));
if ((expire_date == 0 &&
pam_verbosity < PAM_VERBOSITY_INFO) ||
(expire_date > 0 &&
pam_verbosity < PAM_VERBOSITY_IMPORTANT)) {
resp->do_not_send_to_client = true;
}
break;
default:
DEBUG(7, ("User info type [%d] not filtered.\n"));
}
} else if (resp->type & SSS_SERVER_INFO) {
resp->do_not_send_to_client = true;
}
resp = resp->next;
}
return EOK;
}
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 int pam_forwarder(struct cli_ctx *cctx, int pam_cmd);
static void pam_cache_auth_done(struct pam_auth_req *preq, int ret,
time_t expire_date, time_t delayed_until);
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 sysdb_ctx *sysdb;
struct pam_ctx *pctx;
uint32_t user_info_type;
time_t exp_date = -1;
time_t delay_until = -1;
pd = preq->pd;
cctx = preq->cctx;
pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
DEBUG(SSSDBG_FUNC_DATA,
("pam_reply called with result [%d].\n", pd->pam_status));
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;
sysdb = preq->domain->sysdb;
if (sysdb == NULL) {
DEBUG(0, ("Fatal: Sysdb CTX not found for "
"domain [%s]!\n", preq->domain->name));
goto done;
}
ret = sysdb_cache_auth(sysdb, pd->user,
pd->authtok, pd->authtok_size,
pctx->rctx->cdb, false,
&exp_date, &delay_until);
pam_cache_auth_done(preq, ret, exp_date, delay_until);
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;
ret = pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t),
(const uint8_t *) &user_info_type);
if (ret != EOK) {
DEBUG(1, ("pam_add_response failed.\n"));
goto done;
}
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;
}
#ifdef HAVE_SELINUX_LOGIN_DIR
if (pd->cmd == SSS_PAM_ACCT_MGMT &&
pd->pam_status == PAM_SUCCESS) {
/* Try to fetch data from sysdb
* (auth already passed -> we should have them) */
ret = process_selinux_mappings(preq);
if (ret != EOK) {
pd->pam_status = PAM_SYSTEM_ERR;
}
}
#endif
ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
goto done;
}
ret = filter_responses(pctx->rctx->cdb, pd->resp_list);
if (ret != EOK) {
DEBUG(1, ("filter_responses failed, not fatal.\n"));
}
if (pd->domain != NULL) {
ret = pam_add_response(pd, SSS_PAM_DOMAIN_NAME, strlen(pd->domain)+1,
(uint8_t *) pd->domain);
if (ret != EOK) {
DEBUG(1, ("pam_add_response failed.\n"));
goto done;
}
}
resp_c = 0;
resp_size = 0;
resp = pd->resp_list;
while(resp != NULL) {
if (!resp->do_not_send_to_client) {
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) {
if (!resp->do_not_send_to_client) {
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 pam_auth_req *preq, int ret,
time_t expire_date, time_t delayed_until)
{
uint32_t resp_type;
size_t resp_len;
uint8_t *resp;
int64_t dummy;
switch (ret) {
case EOK:
preq->pd->pam_status = PAM_SUCCESS;
resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH;
resp_len = sizeof(uint32_t) + sizeof(int64_t);
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 = (int64_t) expire_date;
memcpy(resp+sizeof(uint32_t), &dummy, sizeof(int64_t));
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(int64_t);
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 = (int64_t) delayed_until;
memcpy(resp+sizeof(uint32_t), &dummy, sizeof(int64_t));
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_forwarder_cb(struct tevent_req *req);
static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
const char *err_msg, void *ptr);
static int pam_check_user_search(struct pam_auth_req *preq);
static int pam_check_user_done(struct pam_auth_req *preq, int ret);
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. */
errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *pd)
{
uint8_t *body;
size_t blen;
errno_t ret;
uint32_t terminator = SSS_END_OF_PAM_REQUEST;
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;
}
switch (cctx->cli_protocol_version->version) {
case 1:
ret = pam_parse_in_data(cctx->rctx->domains,
cctx->rctx->default_domain, pd,
body, blen);
break;
case 2:
ret = pam_parse_in_data_v2(cctx->rctx->domains,
cctx->rctx->default_domain, pd,
body, blen);
break;
case 3:
ret = pam_parse_in_data_v3(cctx->rctx->domains,
cctx->rctx->default_domain, pd,
body, blen);
break;
default:
DEBUG(1, ("Illegal protocol version [%d].\n",
cctx->cli_protocol_version->version));
ret = EINVAL;
}
done:
return ret;
}
static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
{
struct sss_domain_info *dom;
struct pam_auth_req *preq;
struct pam_data *pd;
int ret;
errno_t ncret;
struct pam_ctx *pctx =
talloc_get_type(cctx->rctx->pvt_ctx, struct pam_ctx);
struct tevent_req *req;
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;
pd->cmd = pam_cmd;
pd->priv = cctx->priv;
ret = pam_forwarder_parse_data(cctx, pd);
if (ret == EAGAIN) {
req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, true, pd->domain);
if (req == NULL) {
ret = ENOMEM;
} else {
tevent_req_set_callback(req, pam_forwarder_cb, preq);
ret = EAGAIN;
}
goto done;
} else if (ret != EOK) {
ret = EINVAL;
goto done;
}
/* now check user is valid */
if (pd->domain) {
preq->domain = responder_get_domain(preq, cctx->rctx, pd->domain);
if (!preq->domain) {
ret = ENOENT;
goto done;
}
} else {
for (dom = preq->cctx->rctx->domains; dom; dom = dom->next) {
if (dom->fqnames) continue;
ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
dom, pd->user);
if (ncret == ENOENT) {
/* User not found in the negative cache
* Proceed with PAM actions
*/
break;
}
/* Try the next domain */
DEBUG(4, ("User [%s@%s] filtered out (negative cache). "
"Trying next domain.\n",
pd->user, dom->name));
}
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;
}
preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider);
ret = pam_check_user_search(preq);
if (ret == EOK) {
pam_dom_forwarder(preq);
}
done:
return pam_check_user_done(preq, ret);
}
static void pam_forwarder_cb(struct tevent_req *req)
{
struct pam_auth_req *preq = tevent_req_callback_data(req,
struct pam_auth_req);
struct cli_ctx *cctx = preq->cctx;
struct pam_data *pd;
errno_t ret = EOK;
ret = sss_dp_get_domains_recv(req);
talloc_free(req);
if (ret != EOK) {
goto done;
}
pd = preq->pd;
ret = pam_forwarder_parse_data(cctx, pd);
if (ret != EOK) {
ret = EINVAL;
goto done;
}
if (preq->pd->domain) {
preq->domain = responder_get_domain(preq, cctx->rctx, preq->pd->domain);
if (preq->domain == NULL) {
ret = ENOENT;
goto done;
}
}
ret = pam_check_user_search(preq);
if (ret == EOK) {
pam_dom_forwarder(preq);
}
done:
pam_check_user_done(preq, ret);
}
static void pam_dp_send_acct_req_done(struct tevent_req *req);
static int pam_check_user_search(struct pam_auth_req *preq)
{
struct sss_domain_info *dom = preq->domain;
char *name = NULL;
struct sysdb_ctx *sysdb;
time_t cacheExpire;
int ret;
struct tevent_req *dpreq;
struct dp_callback_ctx *cb_ctx;
struct pam_ctx *pctx =
talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
while (dom) {
/* if it is a domainless search, skip domains that require fully
* qualified names instead */
while (dom && !preq->pd->domain && dom->fqnames) {
dom = dom->next;
}
if (!dom) break;
if (dom != preq->domain) {
/* make sure we reset the check_provider flag when we check
* a new domain */
preq->check_provider = NEED_CHECK_PROVIDER(dom->provider);
}
/* make sure to update the preq if we changed domain */
preq->domain = dom;
talloc_free(name);
name = sss_get_cased_name(preq, preq->pd->user,
dom->case_sensitive);
if (!name) {
return ENOMEM;
}
/* Refresh the user's cache entry on any PAM query
* We put a timeout in the client context so that we limit
* the number of updates within a reasonable timeout
*/
if (preq->check_provider) {
ret = pam_initgr_check_timeout(pctx->id_table, name);
if (ret != EOK
&& ret != ENOENT) {
DEBUG(SSSDBG_OP_FAILURE,
("Could not look up initgroup timout\n"));
return EIO;
} else if (ret == ENOENT) {
/* Call provider first */
break;
}
/* Entry is still valid, get it from the sysdb */
}
DEBUG(4, ("Requesting info for [%s@%s]\n", name, dom->name));
sysdb = dom->sysdb;
if (sysdb == NULL) {
DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n"));
preq->pd->pam_status = PAM_SYSTEM_ERR;
return EFAULT;
}
ret = sysdb_getpwnam(preq, sysdb, name, &preq->res);
if (ret != EOK) {
DEBUG(1, ("Failed to make request to our cache!\n"));
return EIO;
}
if (preq->res->count > 1) {
DEBUG(0, ("getpwnam call returned more than one result !?!\n"));
return ENOENT;
}
if (preq->res->count == 0) {
/* if a multidomain search, try with next */
if (!preq->pd->domain) {
dom = dom->next;
continue;
}
DEBUG(2, ("No results for getpwnam call\n"));
/* TODO: store negative cache ? */
return ENOENT;
}
/* One result found */
/* if we need to check the remote account go on */
if (preq->check_provider) {
cacheExpire = ldb_msg_find_attr_as_uint64(preq->res->msgs[0],
SYSDB_CACHE_EXPIRE, 0);
if (cacheExpire < time(NULL)) {
break;
}
}
DEBUG(6, ("Returning info for user [%s@%s]\n", name, dom->name));
/* We might have searched by alias. Pass on the primary name */
ret = pd_set_primary_name(preq->res->msgs[0], preq->pd);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Could not canonicalize username\n"));
return ret;
}
return EOK;
}
if (!dom) {
/* Ensure that we don't try to check a provider without a domain,
* since this will cause a NULL-dereference below.
*/
preq->check_provider = false;
}
if (preq->check_provider) {
/* dont loop forever :-) */
preq->check_provider = false;
dpreq = sss_dp_get_account_send(preq, preq->cctx->rctx,
dom, false, SSS_DP_INITGROUPS,
name, 0, NULL);
if (!dpreq) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Out of memory sending data provider request\n"));
return ENOMEM;
}
cb_ctx = talloc_zero(preq, struct dp_callback_ctx);
if(!cb_ctx) {
talloc_zfree(dpreq);
return ENOMEM;
}
cb_ctx->callback = pam_check_user_dp_callback;
cb_ctx->ptr = preq;
cb_ctx->cctx = preq->cctx;
cb_ctx->mem_ctx = preq;
tevent_req_set_callback(dpreq, pam_dp_send_acct_req_done, cb_ctx);
/* tell caller we are in an async call */
return EAGAIN;
}
DEBUG(SSSDBG_MINOR_FAILURE,
("No matching domain found for [%s], fail!\n", preq->pd->user));
return ENOENT;
}
static void pam_dp_send_acct_req_done(struct tevent_req *req)
{
struct dp_callback_ctx *cb_ctx =
tevent_req_callback_data(req, struct dp_callback_ctx);
errno_t ret;
dbus_uint16_t err_maj;
dbus_uint32_t err_min;
char *err_msg;
ret = sss_dp_get_account_recv(cb_ctx->mem_ctx, req,
&err_maj, &err_min,
&err_msg);
talloc_zfree(req);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Fatal error, killing connection!\n"));
talloc_free(cb_ctx->cctx);
return;
}
cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
}
static int pam_check_user_done(struct pam_auth_req *preq, int ret)
{
switch (ret) {
case EOK:
break;
case EAGAIN:
/* performing async request, just return */
break;
case ENOENT:
preq->pd->pam_status = PAM_USER_UNKNOWN;
pam_reply(preq);
break;
default:
preq->pd->pam_status = PAM_SYSTEM_ERR;
pam_reply(preq);
break;
}
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);
int ret;
struct pam_ctx *pctx =
talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
char *name;
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));
}
ret = pam_check_user_search(preq);
if (ret == EOK) {
/* Make sure we don't go to the ID provider too often */
name = preq->domain->case_sensitive ?
talloc_strdup(preq, preq->pd->user) :
sss_tc_utf8_str_tolower(preq, preq->pd->user);
if (!name) {
ret = ENOMEM;
goto done;
}
ret = pam_initgr_cache_set(pctx->rctx->ev, pctx->id_table,
name, pctx->id_timeout);
talloc_free(name);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
("Could not save initgr timestamp. "
"Proceeding with PAM actions\n"));
/* This is non-fatal, we'll just end up going to the
* data provider again next time.
*/
}
pam_dom_forwarder(preq);
}
ret = pam_check_user_done(preq, ret);
done:
if (ret) {
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 <type><size><data>"},
{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;
}