pamsrv_cmd.c revision 95ef1bd1c06163492e285fa9d8e2fa81f99d39d2
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/*
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen SSSD
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen PAM Responder
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1171f0abf442638bac1827bb24a0b6b8eb682a82Timo Sirainen Copyright (C) Simo Sorce <ssorce@redhat.com> 2009
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Copyright (C) Sumit Bose <sbose@redhat.com> 2009
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen This program is free software; you can redistribute it and/or modify
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen it under the terms of the GNU General Public License as published by
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen the Free Software Foundation; either version 3 of the License, or
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (at your option) any later version.
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen This program is distributed in the hope that it will be useful,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen GNU General Public License for more details.
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen You should have received a copy of the GNU General Public License
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen along with this program. If not, see <http://www.gnu.org/licenses/>.
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen*/
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <time.h>
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen#include "util/util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "util/auth_utils.h"
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen#include "db/sysdb.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "confdb/confdb.h"
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen#include "responder/common/responder_packet.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "responder/common/responder.h"
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen#include "responder/common/negcache.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "providers/data_provider.h"
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen#include "responder/pam/pamsrv.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "responder/pam/pam_helpers.h"
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen#include "db/sysdb.h"
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainenenum pam_verbosity {
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen PAM_VERBOSITY_NO_MESSAGES = 0,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen PAM_VERBOSITY_IMPORTANT,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen PAM_VERBOSITY_INFO,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen PAM_VERBOSITY_DEBUG
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen};
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define DEFAULT_PAM_VERBOSITY PAM_VERBOSITY_IMPORTANT
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void pam_reply(struct pam_auth_req *preq);
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainenstatic bool is_domain_requested(struct pam_data *pd, const char *domain_name)
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* If none specific domains got requested via pam, all domains are allowed.
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen * Which mimics the default/original behaviour.
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!pd->requested_domains) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return true;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
aff3354de83df9d683587e27461697193ff36591Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen for (i = 0; pd->requested_domains[i]; i++) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (strcmp(domain_name, pd->requested_domains[i])) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen continue;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen }
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return true;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return false;
44c5e644cb413a6559bf2d4179cbe48f9a82f366Timo Sirainen}
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenstatic int extract_authtok_v2(struct sss_auth_token *tok,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen size_t data_size, uint8_t *body, size_t blen,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen size_t *c)
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen{
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen uint32_t auth_token_type;
aff3354de83df9d683587e27461697193ff36591Timo Sirainen uint32_t auth_token_length;
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen uint8_t *auth_token_data;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen int ret = EOK;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainen if (data_size < sizeof(uint32_t) || *c+data_size > blen ||
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainen SIZE_T_OVERFLOW(*c, data_size)) return EINVAL;
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainen
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainen SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c);
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainen auth_token_length = data_size - sizeof(uint32_t);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen auth_token_data = body+(*c);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen switch (auth_token_type) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen case SSS_AUTHTOK_TYPE_EMPTY:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sss_authtok_set_empty(tok);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen break;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen case SSS_AUTHTOK_TYPE_PASSWORD:
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (auth_token_length == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sss_authtok_set_empty(tok);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen ret = sss_authtok_set_password(tok, (const char *)auth_token_data,
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen auth_token_length);
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen }
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen break;
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen default:
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return EINVAL;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen }
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen *c += auth_token_length;
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return ret;
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen}
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainenstatic int extract_string(char **var, size_t size, uint8_t *body, size_t blen,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen size_t *c) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint8_t *str;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (*c+size > blen || SIZE_T_OVERFLOW(*c, size)) return EINVAL;
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen str = body+(*c);
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen if (str[size-1]!='\0') return EINVAL;
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* If the string isn't valid UTF-8, fail */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (!sss_utf8_check(str, size-1)) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return EINVAL;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen *c += size;
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen *var = (char *) str;
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen return EOK;
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen}
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenstatic int extract_uint32_t(uint32_t *var, size_t size, uint8_t *body,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen size_t blen, size_t *c) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (size != sizeof(uint32_t) || *c+size > blen || SIZE_T_OVERFLOW(*c, size))
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return EINVAL;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen SAFEALIGN_COPY_UINT32_CHECK(var, &body[*c], blen, c);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return EOK;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainenstatic int pd_set_primary_name(const struct ldb_message *msg,struct pam_data *pd)
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const char *name;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (!name) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "A user with no name?\n");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return EIO;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
02166e32bcda5d0018ae1a2a38614126ab5c6025Timo Sirainen if (strcmp(pd->user, name)) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen DEBUG(SSSDBG_TRACE_FUNC, "User's primary name is %s\n", name);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen talloc_free(pd->user);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen pd->user = talloc_strdup(pd, name);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (!pd->user) return ENOMEM;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return EOK;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenstatic int pam_parse_in_data_v2(struct pam_data *pd,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint8_t *body, size_t blen)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen size_t c;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint32_t type;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint32_t size;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen int ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint32_t start;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint32_t terminator;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen char *requested_domains;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (blen < 4*sizeof(uint32_t)+2) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return EINVAL;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen SAFEALIGN_COPY_UINT32(&start, body, NULL);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen SAFEALIGN_COPY_UINT32(&terminator, body + blen - sizeof(uint32_t), NULL);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (start != SSS_START_OF_PAM_REQUEST
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen || terminator != SSS_END_OF_PAM_REQUEST) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return EINVAL;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen c = sizeof(uint32_t);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen do {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen SAFEALIGN_COPY_UINT32_CHECK(&type, &body[c], blen, &c);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (type == SSS_END_OF_PAM_REQUEST) {
58febed28f2af78b2d8a281c851d9b67160c4bd3Timo Sirainen if (c != blen) return EINVAL;
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen } else {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen SAFEALIGN_COPY_UINT32_CHECK(&size, &body[c], blen, &c);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* the uint32_t end maker SSS_END_OF_PAM_REQUEST does not count to
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen * the remaining buffer */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (size > (blen - c - sizeof(uint32_t))) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Invalid data size.\n");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return EINVAL;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen switch(type) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen case SSS_PAM_ITEM_USER:
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ret = extract_string(&pd->logon_name, size, body, blen, &c);
5e4f94015f5bbc9eefb1f2cb7af81ed50dcd2b39Timo Sirainen if (ret != EOK) return ret;
5e4f94015f5bbc9eefb1f2cb7af81ed50dcd2b39Timo Sirainen break;
5e4f94015f5bbc9eefb1f2cb7af81ed50dcd2b39Timo Sirainen case SSS_PAM_ITEM_SERVICE:
5e4f94015f5bbc9eefb1f2cb7af81ed50dcd2b39Timo Sirainen ret = extract_string(&pd->service, size, body, blen, &c);
5e4f94015f5bbc9eefb1f2cb7af81ed50dcd2b39Timo Sirainen if (ret != EOK) return ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen break;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen case SSS_PAM_ITEM_TTY:
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ret = extract_string(&pd->tty, size, body, blen, &c);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ret != EOK) return ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen break;
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen case SSS_PAM_ITEM_RUSER:
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ret = extract_string(&pd->ruser, size, body, blen, &c);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ret != EOK) return ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen break;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen case SSS_PAM_ITEM_RHOST:
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ret = extract_string(&pd->rhost, size, body, blen, &c);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ret != EOK) return ret;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen break;
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen case SSS_PAM_ITEM_REQUESTED_DOMAINS:
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ret = extract_string(&requested_domains, size, body, blen,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen &c);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ret != EOK) return ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ret = split_on_separator(pd, requested_domains, ',', true,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen true, &pd->requested_domains,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen NULL);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ret != EOK) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Failed to parse requested_domains list!\n");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen break;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen case SSS_PAM_ITEM_CLI_PID:
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ret = extract_uint32_t(&pd->cli_pid, size,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen body, blen, &c);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ret != EOK) return ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen break;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen case SSS_PAM_ITEM_AUTHTOK:
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ret = extract_authtok_v2(pd->authtok,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen size, body, blen, &c);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ret != EOK) return ret;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen break;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen case SSS_PAM_ITEM_NEWAUTHTOK:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = extract_authtok_v2(pd->newauthtok,
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen size, body, blen, &c);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen if (ret != EOK) return ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen break;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen default:
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Ignoring unknown data type [%d].\n", type);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen c += size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } while(c < blen);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return EOK;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenstatic int pam_parse_in_data_v3(struct pam_data *pd,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint8_t *body, size_t blen)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen{
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen ret = pam_parse_in_data_v2(pd, body, blen);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (ret != EOK) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "pam_parse_in_data_v2 failed.\n");
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return ret;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen }
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (pd->cli_pid == 0) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Missing client PID.\n");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return EINVAL;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return EOK;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainenstatic int extract_authtok_v1(struct sss_auth_token *tok,
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen uint8_t *body, size_t blen, size_t *c)
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen{
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen uint32_t auth_token_type;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen uint32_t auth_token_length;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint8_t *auth_token_data;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen int ret = EOK;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, &body[*c], blen, c);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_token_data = body+(*c);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen switch (auth_token_type) {
f65602dff8a85170176ddaa790db6df56006d132Timo Sirainen case SSS_AUTHTOK_TYPE_EMPTY:
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen sss_authtok_set_empty(tok);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case SSS_AUTHTOK_TYPE_PASSWORD:
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen ret = sss_authtok_set_password(tok, (const char *)auth_token_data,
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen auth_token_length);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen break;
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen default:
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return EINVAL;
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen }
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen *c += auth_token_length;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainenstatic int pam_parse_in_data(struct pam_data *pd,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint8_t *body, size_t blen)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen{
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen size_t start;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen size_t end;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen size_t last;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen int ret;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen last = blen - 1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen end = 0;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* user name */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen for (start = end; end < last; end++) if (body[end] == '\0') break;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (body[end++] != '\0') return EINVAL;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen pd->logon_name = (char *) &body[start];
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen for (start = end; end < last; end++) if (body[end] == '\0') break;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (body[end++] != '\0') return EINVAL;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen pd->service = (char *) &body[start];
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen for (start = end; end < last; end++) if (body[end] == '\0') break;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (body[end++] != '\0') return EINVAL;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen pd->tty = (char *) &body[start];
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen for (start = end; end < last; end++) if (body[end] == '\0') break;
1171f0abf442638bac1827bb24a0b6b8eb682a82Timo Sirainen if (body[end++] != '\0') return EINVAL;
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen pd->ruser = (char *) &body[start];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen for (start = end; end < last; end++) if (body[end] == '\0') break;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (body[end++] != '\0') return EINVAL;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen pd->rhost = (char *) &body[start];
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen ret = extract_authtok_v1(pd->authtok, body, blen, &end);
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen if (ret) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Invalid auth token\n");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return ret;
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen }
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen ret = extract_authtok_v1(pd->newauthtok, body, blen, &end);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ret) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Invalid new auth token\n");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return EOK;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen/*=Save-Last-Login-State===================================================*/
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenstatic errno_t set_last_login(struct pam_auth_req *preq)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct sysdb_attrs *attrs;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen errno_t ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen attrs = sysdb_new_attrs(preq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!attrs) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen ret = ENOMEM;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen goto fail;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_ONLINE_AUTH, time(NULL));
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (ret != EOK) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen goto fail;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen }
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_LOGIN, time(NULL));
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ret != EOK) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen goto fail;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ret = sysdb_set_user_attr(preq->domain, preq->pd->user, attrs,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen SYSDB_MOD_REP);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (ret != EOK) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen DEBUG(SSSDBG_OP_FAILURE, "set_last_login failed.\n");
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen preq->pd->pam_status = PAM_SYSTEM_ERR;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen goto fail;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen } else {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen preq->pd->last_auth_saved = true;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen preq->callback(preq);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return EOK;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainenfail:
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return ret;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic errno_t filter_responses(struct confdb_ctx *cdb,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct response_data *resp_list)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen int ret;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct response_data *resp;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen uint32_t user_info_type;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen int64_t expire_date;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen int pam_verbosity;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen CONFDB_PAM_VERBOSITY, DEFAULT_PAM_VERBOSITY,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen &pam_verbosity);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (ret != EOK) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen "Failed to read PAM verbosity, not fatal.\n");
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen pam_verbosity = DEFAULT_PAM_VERBOSITY;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen resp = resp_list;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen while(resp != NULL) {
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen if (resp->type == SSS_PAM_USER_INFO) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (resp->len < sizeof(uint32_t)) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "User info entry is too short.\n");
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return EINVAL;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (pam_verbosity == PAM_VERBOSITY_NO_MESSAGES) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen resp->do_not_send_to_client = true;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen resp = resp->next;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen continue;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen memcpy(&user_info_type, resp->data, sizeof(uint32_t));
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen resp->do_not_send_to_client = false;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen switch (user_info_type) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen case SSS_PAM_USER_INFO_OFFLINE_AUTH:
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (resp->len != sizeof(uint32_t) + sizeof(int64_t)) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen "User info offline auth entry is "
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen "too short.\n");
65a5fb2343f9870713bfca0b24abb58dcade605eTimo Sirainen return EINVAL;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen memcpy(&expire_date, resp->data + sizeof(uint32_t),
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen sizeof(int64_t));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if ((expire_date == 0 &&
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen pam_verbosity < PAM_VERBOSITY_INFO) ||
2a21435425c50514fa4d0708110a4ed7f0d85661Timo Sirainen (expire_date > 0 &&
2a21435425c50514fa4d0708110a4ed7f0d85661Timo Sirainen pam_verbosity < PAM_VERBOSITY_IMPORTANT)) {
2a21435425c50514fa4d0708110a4ed7f0d85661Timo Sirainen resp->do_not_send_to_client = true;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen }
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen break;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen default:
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen DEBUG(SSSDBG_TRACE_LIBS,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen "User info type [%d] not filtered.\n",
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen user_info_type);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
65a5fb2343f9870713bfca0b24abb58dcade605eTimo Sirainen } else if (resp->type & SSS_SERVER_INFO) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen resp->do_not_send_to_client = true;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen resp = resp->next;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return EOK;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenstatic void pam_reply_delay(struct tevent_context *ev, struct tevent_timer *te,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct timeval tv, void *pvt)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct pam_auth_req *preq;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen DEBUG(SSSDBG_CONF_SETTINGS, "pam_reply_delay get called.\n");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen preq = talloc_get_type(pvt, struct pam_auth_req);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen pam_reply(preq);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
84004c37192dc91a8dcc9f213ca2cfa22b4f40e4Timo Sirainenstatic int pam_forwarder(struct cli_ctx *cctx, int pam_cmd);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void pam_handle_cached_login(struct pam_auth_req *preq, int ret,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen time_t expire_date, time_t delayed_until);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstatic void pam_reply(struct pam_auth_req *preq)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct cli_ctx *cctx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen uint8_t *body;
b1f58fea9e1813b48735a021043f1cea2b495c3bTimo Sirainen size_t blen;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen int ret;
b1f58fea9e1813b48735a021043f1cea2b495c3bTimo Sirainen int32_t resp_c;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen int32_t resp_size;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen struct response_data *resp;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen int p;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen struct timeval tv;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct tevent_timer *te;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct pam_data *pd;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen struct pam_ctx *pctx;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen uint32_t user_info_type;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen time_t exp_date = -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen time_t delay_until = -1;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen pd = preq->pd;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen cctx = preq->cctx;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen DEBUG(SSSDBG_FUNC_DATA,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen "pam_reply called with result [%d].\n", pd->pam_status);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (pd->pam_status == PAM_AUTHINFO_UNAVAIL) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen switch(pd->cmd) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen case SSS_PAM_AUTHENTICATE:
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if ((preq->domain != NULL) &&
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen (preq->domain->cache_credentials == true) &&
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen (pd->offline_auth == false)) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char *password = NULL;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen /* do auth with offline credentials */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen pd->offline_auth = true;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (preq->domain->sysdb == NULL) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen DEBUG(SSSDBG_FATAL_FAILURE,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen "Fatal: Sysdb CTX not found for domain"
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen " [%s]!\n", preq->domain->name);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen goto done;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ret = sss_authtok_get_password(pd->authtok, &password, NULL);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (ret) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get password.\n");
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen goto done;
}
ret = sysdb_cache_auth(preq->domain,
pd->user, password,
pctx->rctx->cdb, false,
&exp_date, &delay_until);
pam_handle_cached_login(preq, ret, exp_date, delay_until);
return;
}
break;
case SSS_PAM_CHAUTHTOK_PRELIM:
case SSS_PAM_CHAUTHTOK:
DEBUG(SSSDBG_FUNC_DATA,
"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(SSSDBG_CRIT_FAILURE, "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(SSSDBG_OP_FAILURE,
"Assuming offline authentication setting status for "
"pam call %d to PAM_SUCCESS.\n", pd->cmd);
pd->pam_status = PAM_SUCCESS;
break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, "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(SSSDBG_CRIT_FAILURE, "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(SSSDBG_CRIT_FAILURE,
"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;
}
ret = filter_responses(pctx->rctx->cdb, pd->resp_list);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "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(SSSDBG_CRIT_FAILURE, "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(SSSDBG_FUNC_DATA, "blen: %zu\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_handle_cached_login(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;
preq->pd->pam_status = cached_login_pam_status(ret);
switch (preq->pd->pam_status) {
case 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(SSSDBG_CRIT_FAILURE,
"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(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
}
}
break;
case 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(SSSDBG_CRIT_FAILURE,
"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(SSSDBG_CRIT_FAILURE,
"pam_add_response failed.\n");
}
}
}
break;
default:
DEBUG(SSSDBG_TRACE_LIBS,
"cached login returned: %d\n", preq->pd->pam_status);
}
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_packet_get_body(cctx->creq->in, &body, &blen);
if (blen >= sizeof(uint32_t)) {
SAFEALIGN_COPY_UINT32(&terminator,
body + blen - sizeof(uint32_t),
NULL);
if (terminator != SSS_END_OF_PAM_REQUEST) {
DEBUG(SSSDBG_CRIT_FAILURE, "Received data not terminated.\n");
ret = EINVAL;
goto done;
}
}
switch (cctx->cli_protocol_version->version) {
case 1:
ret = pam_parse_in_data(pd, body, blen);
break;
case 2:
ret = pam_parse_in_data_v2(pd, body, blen);
break;
case 3:
ret = pam_parse_in_data_v3(pd, body, blen);
break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, "Illegal protocol version [%d].\n",
cctx->cli_protocol_version->version);
ret = EINVAL;
}
if (ret != EOK) {
goto done;
}
ret = sss_parse_name_for_domains(pd, cctx->rctx->domains,
cctx->rctx->default_domain, pd->logon_name,
&pd->domain, &pd->user);
DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
done:
return ret;
}
static int pam_auth_req_destructor(struct pam_auth_req *preq)
{
if (preq && preq->dpreq_spy) {
/* If there is still a request pending, tell the spy
* the client is going away
*/
preq->dpreq_spy->preq = NULL;
}
return 0;
}
static bool is_uid_trusted(uint32_t uid,
size_t trusted_uids_count,
uid_t *trusted_uids)
{
size_t i;
/* root is always trusted */
if (uid == 0) {
return true;
}
/* All uids are allowed */
if (trusted_uids_count == 0) {
return true;
}
for(i = 0; i < trusted_uids_count; i++) {
if (trusted_uids[i] == uid) {
return true;
}
}
return false;
}
static bool is_domain_public(char *name,
char **public_dom_names,
size_t public_dom_names_count)
{
size_t i;
for(i=0; i < public_dom_names_count; i++) {
if (strcmp(name, public_dom_names[i]) == 0) {
return true;
}
}
return false;
}
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;
pctx->is_uid_trusted = is_uid_trusted(cctx->client_euid,
pctx->trusted_uids_count,
pctx->trusted_uids);
if (!pctx->is_uid_trusted) {
DEBUG(SSSDBG_MINOR_FAILURE, "uid %"PRIu32" is not trusted.\n",
cctx->client_euid);
}
preq = talloc_zero(cctx, struct pam_auth_req);
if (!preq) {
return ENOMEM;
}
talloc_set_destructor(preq, pam_auth_req_destructor);
preq->cctx = cctx;
preq->pd = create_pam_data(preq);
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(cctx->rctx, pd->domain);
if (!preq->domain) {
ret = ENOENT;
goto done;
}
/* Untrusted users can access only public domains. */
if (!pctx->is_uid_trusted &&
!is_domain_public(pd->domain, pctx->public_domains,
pctx->public_domains_count)) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Untrusted user %"PRIu32" cannot access unpublic domain %s.\n",
cctx->client_euid, pd->domain);
ret = EPERM;
goto done;
}
ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
preq->domain, pd->user);
if (ncret == EEXIST) {
/* User found in the negative cache */
ret = ENOENT;
goto done;
}
/* skip this domain if not requested */
if (!is_domain_requested(pd, pd->domain)) {
ret = ENOENT;
goto done;
}
} else {
for (dom = preq->cctx->rctx->domains;
dom;
dom = get_next_domain(dom, false)) {
if (dom->fqnames) continue;
/* Untrusted users can access only public domains. */
if (!pctx->is_uid_trusted &&
!is_domain_public(dom->name, pctx->public_domains,
pctx->public_domains_count)) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Untrusted user %"PRIu32" cannot access unpublic domain %s."
" Trying next domain.\n",
cctx->client_euid, dom->name);
continue;
}
/* skip this domain if not requested */
if (!is_domain_requested(pd, dom->name)) {
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(SSSDBG_TRACE_FUNC,
"User [%s@%s] filtered out (negative cache). "
"Trying next domain.\n", pd->user, dom->name);
}
if (!dom || !is_domain_requested(pd, dom->name)) {
ret = ENOENT;
goto done;
}
preq->domain = dom;
}
if (preq->domain->provider == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE,
"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 == EAGAIN) {
if (strchr(preq->pd->logon_name, '@') == NULL) {
goto done;
}
/* Assuming Kerberos principal */
preq->domain = preq->cctx->rctx->domains;
preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider);
preq->pd->user = talloc_strdup(preq->pd, preq->pd->logon_name);
if (preq->pd->user == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
ret = ENOMEM;
goto done;
}
preq->pd->name_is_upn = true;
preq->pd->domain = NULL;
} else if (ret != EOK) {
ret = EINVAL;
goto done;
}
if (preq->pd->domain) {
preq->domain = responder_get_domain(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;
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);
static const char *user_attrs[] = SYSDB_PW_ATTRS;
struct ldb_message *msg;
struct ldb_result *res;
while (dom) {
/* if it is a domainless search, skip domains that require fully
* qualified names instead, also untrusted users can access only
* public domains */
while (dom && !preq->pd->domain && !preq->pd->name_is_upn
&& (dom->fqnames ||
(!pctx->is_uid_trusted &&
!is_domain_public(dom->name,
pctx->public_domains,
pctx->public_domains_count)))) {
dom = get_next_domain(dom, false);
}
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;
}
name = sss_reverse_replace_space(preq, name,
pctx->rctx->override_space);
if (name == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE,
"sss_reverse_replace_space failed\n");
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(SSSDBG_CONF_SETTINGS,
"Requesting info for [%s@%s]\n", name, dom->name);
if (dom->sysdb == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Fatal: Sysdb CTX not found for this domain!\n");
preq->pd->pam_status = PAM_SYSTEM_ERR;
return EFAULT;
}
if (preq->pd->name_is_upn) {
ret = sysdb_search_user_by_upn(preq, dom, name, user_attrs, &msg);
} else {
ret = sysdb_getpwnam(preq, dom, name, &res);
if (res->count > 1) {
DEBUG(SSSDBG_FATAL_FAILURE,
"getpwnam call returned more than one result !?!\n");
return ENOENT;
} else if (res->count == 0) {
ret = ENOENT;
} else {
msg = res->msgs[0];
}
}
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to make request to our cache!\n");
return EIO;
}
if (ret == ENOENT) {
if (preq->check_provider == false) {
/* set negative cache only if not result of cache check */
ret = sss_ncache_set_user(pctx->ncache, false, dom, name);
if (ret != EOK) {
/* Should not be fatal, just slower next time */
DEBUG(SSSDBG_MINOR_FAILURE,
"Cannot set ncache for [%s@%s]\n", name,
dom->name);
}
}
/* if a multidomain search, try with next */
if (!preq->pd->domain) {
dom = get_next_domain(dom, false);
continue;
}
DEBUG(SSSDBG_OP_FAILURE, "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(msg,
SYSDB_CACHE_EXPIRE, 0);
if (cacheExpire < time(NULL)) {
break;
}
}
DEBUG(SSSDBG_TRACE_FUNC,
"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(msg, 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,
preq->pd->name_is_upn ? EXTRA_NAME_IS_UPN : 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(SSSDBG_OP_FAILURE,
"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(SSSDBG_CONF_SETTINGS, "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(SSSDBG_CONF_SETTINGS, "entering pam_cmd_authenticate\n");
return pam_forwarder(cctx, SSS_PAM_AUTHENTICATE);
}
static int pam_cmd_setcred(struct cli_ctx *cctx) {
DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_setcred\n");
return pam_forwarder(cctx, SSS_PAM_SETCRED);
}
static int pam_cmd_acct_mgmt(struct cli_ctx *cctx) {
DEBUG(SSSDBG_CONF_SETTINGS, "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(SSSDBG_CONF_SETTINGS, "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(SSSDBG_CONF_SETTINGS, "entering pam_cmd_close_session\n");
return pam_forwarder(cctx, SSS_PAM_CLOSE_SESSION);
}
static int pam_cmd_chauthtok(struct cli_ctx *cctx) {
DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_chauthtok\n");
return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK);
}
static int pam_cmd_chauthtok_prelim(struct cli_ctx *cctx) {
DEBUG(SSSDBG_CONF_SETTINGS, "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;
}