Line data Source code
1 : /*
2 : SSSD
3 :
4 : PAM Responder
5 :
6 : Copyright (C) Simo Sorce <ssorce@redhat.com> 2009
7 : Copyright (C) Sumit Bose <sbose@redhat.com> 2009
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include <time.h>
24 : #include "util/util.h"
25 : #include "util/auth_utils.h"
26 : #include "db/sysdb.h"
27 : #include "confdb/confdb.h"
28 : #include "responder/common/responder_packet.h"
29 : #include "responder/common/responder.h"
30 : #include "responder/common/negcache.h"
31 : #include "providers/data_provider.h"
32 : #include "responder/pam/pamsrv.h"
33 : #include "responder/pam/pam_helpers.h"
34 : #include "responder/common/responder_cache_req.h"
35 : #include "db/sysdb.h"
36 :
37 : enum pam_verbosity {
38 : PAM_VERBOSITY_NO_MESSAGES = 0,
39 : PAM_VERBOSITY_IMPORTANT,
40 : PAM_VERBOSITY_INFO,
41 : PAM_VERBOSITY_DEBUG
42 : };
43 :
44 : #define DEFAULT_PAM_VERBOSITY PAM_VERBOSITY_IMPORTANT
45 :
46 : static errno_t
47 : pam_null_last_online_auth_with_curr_token(struct sss_domain_info *domain,
48 : const char *username);
49 : static errno_t
50 : pam_get_last_online_auth_with_curr_token(struct sss_domain_info *domain,
51 : const char *name,
52 : uint64_t *_value);
53 :
54 : static void pam_reply(struct pam_auth_req *preq);
55 :
56 0 : static errno_t pack_user_info_msg(TALLOC_CTX *mem_ctx,
57 : const char *user_error_message,
58 : size_t *resp_len,
59 : uint8_t **_resp)
60 : {
61 0 : uint32_t resp_type = SSS_PAM_USER_INFO_ACCOUNT_EXPIRED;
62 : size_t err_len;
63 : uint8_t *resp;
64 : size_t p;
65 :
66 0 : err_len = strlen(user_error_message);
67 0 : *resp_len = 2 * sizeof(uint32_t) + err_len;
68 0 : resp = talloc_size(mem_ctx, *resp_len);
69 0 : if (resp == NULL) {
70 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
71 0 : return ENOMEM;
72 : }
73 :
74 0 : p = 0;
75 0 : SAFEALIGN_SET_UINT32(&resp[p], resp_type, &p);
76 0 : SAFEALIGN_SET_UINT32(&resp[p], err_len, &p);
77 0 : safealign_memcpy(&resp[p], user_error_message, err_len, &p);
78 0 : if (p != *resp_len) {
79 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Size mismatch\n");
80 : }
81 :
82 0 : *_resp = resp;
83 0 : return EOK;
84 : }
85 :
86 0 : static void inform_user(struct pam_data* pd, const char *pam_message)
87 : {
88 : size_t msg_len;
89 : uint8_t *msg;
90 : errno_t ret;
91 :
92 0 : ret = pack_user_info_msg(pd, pam_message, &msg_len, &msg);
93 0 : if (ret != EOK) {
94 0 : DEBUG(SSSDBG_CRIT_FAILURE,
95 : "pack_user_info_account_expired failed.\n");
96 : } else {
97 0 : ret = pam_add_response(pd, SSS_PAM_USER_INFO, msg_len, msg);
98 0 : if (ret != EOK) {
99 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
100 : }
101 : }
102 0 : }
103 :
104 38 : static bool is_domain_requested(struct pam_data *pd, const char *domain_name)
105 : {
106 : int i;
107 :
108 : /* If none specific domains got requested via pam, all domains are allowed.
109 : * Which mimics the default/original behaviour.
110 : */
111 38 : if (!pd->requested_domains) {
112 38 : return true;
113 : }
114 :
115 0 : for (i = 0; pd->requested_domains[i]; i++) {
116 0 : if (strcasecmp(domain_name, pd->requested_domains[i])) {
117 0 : continue;
118 : }
119 :
120 0 : return true;
121 : }
122 :
123 0 : return false;
124 : }
125 :
126 22 : static int extract_authtok_v2(struct sss_auth_token *tok,
127 : size_t data_size, uint8_t *body, size_t blen,
128 : size_t *c)
129 : {
130 : uint32_t auth_token_type;
131 : uint32_t auth_token_length;
132 : uint8_t *auth_token_data;
133 22 : int ret = EOK;
134 :
135 44 : if (data_size < sizeof(uint32_t) || *c+data_size > blen ||
136 22 : SIZE_T_OVERFLOW(*c, data_size)) return EINVAL;
137 :
138 22 : SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c);
139 22 : auth_token_length = data_size - sizeof(uint32_t);
140 22 : auth_token_data = body+(*c);
141 :
142 22 : switch (auth_token_type) {
143 : case SSS_AUTHTOK_TYPE_EMPTY:
144 0 : sss_authtok_set_empty(tok);
145 0 : break;
146 : case SSS_AUTHTOK_TYPE_PASSWORD:
147 16 : if (auth_token_length == 0) {
148 0 : sss_authtok_set_empty(tok);
149 : } else {
150 16 : ret = sss_authtok_set_password(tok, (const char *)auth_token_data,
151 : auth_token_length);
152 : }
153 16 : break;
154 : case SSS_AUTHTOK_TYPE_2FA:
155 4 : ret = sss_authtok_set(tok, SSS_AUTHTOK_TYPE_2FA,
156 : auth_token_data, auth_token_length);
157 4 : break;
158 : case SSS_AUTHTOK_TYPE_SC_PIN:
159 2 : ret = sss_authtok_set_sc_pin(tok, (const char *) auth_token_data,
160 : auth_token_length);
161 2 : break;
162 : case SSS_AUTHTOK_TYPE_SC_KEYPAD:
163 0 : sss_authtok_set_sc_keypad(tok);
164 0 : break;
165 : default:
166 0 : return EINVAL;
167 : }
168 :
169 22 : *c += auth_token_length;
170 :
171 22 : return ret;
172 : }
173 :
174 196 : static int extract_string(char **var, size_t size, uint8_t *body, size_t blen,
175 : size_t *c) {
176 : uint8_t *str;
177 :
178 196 : if (*c+size > blen || SIZE_T_OVERFLOW(*c, size)) return EINVAL;
179 :
180 196 : str = body+(*c);
181 :
182 196 : if (str[size-1]!='\0') return EINVAL;
183 :
184 : /* If the string isn't valid UTF-8, fail */
185 196 : if (!sss_utf8_check(str, size-1)) {
186 0 : return EINVAL;
187 : }
188 :
189 196 : *c += size;
190 :
191 196 : *var = (char *) str;
192 :
193 196 : return EOK;
194 : }
195 :
196 40 : static int extract_uint32_t(uint32_t *var, size_t size, uint8_t *body,
197 : size_t blen, size_t *c) {
198 :
199 40 : if (size != sizeof(uint32_t) || *c+size > blen || SIZE_T_OVERFLOW(*c, size))
200 0 : return EINVAL;
201 :
202 40 : SAFEALIGN_COPY_UINT32_CHECK(var, &body[*c], blen, c);
203 :
204 40 : return EOK;
205 : }
206 :
207 36 : static int pd_set_primary_name(const struct ldb_message *msg,struct pam_data *pd)
208 : {
209 : const char *name;
210 :
211 36 : name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
212 36 : if (!name) {
213 0 : DEBUG(SSSDBG_CRIT_FAILURE, "A user with no name?\n");
214 0 : return EIO;
215 : }
216 :
217 36 : if (strcmp(pd->user, name)) {
218 0 : DEBUG(SSSDBG_TRACE_FUNC, "User's primary name is %s\n", name);
219 0 : talloc_free(pd->user);
220 0 : pd->user = talloc_strdup(pd, name);
221 0 : if (!pd->user) return ENOMEM;
222 : }
223 :
224 36 : return EOK;
225 : }
226 :
227 40 : static int pam_parse_in_data_v2(struct pam_data *pd,
228 : uint8_t *body, size_t blen)
229 : {
230 : size_t c;
231 : uint32_t type;
232 : uint32_t size;
233 : int ret;
234 : uint32_t start;
235 : uint32_t terminator;
236 : char *requested_domains;
237 :
238 40 : if (blen < 4*sizeof(uint32_t)+2) {
239 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n");
240 0 : return EINVAL;
241 : }
242 :
243 40 : SAFEALIGN_COPY_UINT32(&start, body, NULL);
244 40 : SAFEALIGN_COPY_UINT32(&terminator, body + blen - sizeof(uint32_t), NULL);
245 :
246 40 : if (start != SSS_START_OF_PAM_REQUEST
247 40 : || terminator != SSS_END_OF_PAM_REQUEST) {
248 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n");
249 0 : return EINVAL;
250 : }
251 :
252 40 : c = sizeof(uint32_t);
253 : do {
254 298 : SAFEALIGN_COPY_UINT32_CHECK(&type, &body[c], blen, &c);
255 :
256 298 : if (type == SSS_END_OF_PAM_REQUEST) {
257 40 : if (c != blen) return EINVAL;
258 : } else {
259 258 : SAFEALIGN_COPY_UINT32_CHECK(&size, &body[c], blen, &c);
260 : /* the uint32_t end maker SSS_END_OF_PAM_REQUEST does not count to
261 : * the remaining buffer */
262 258 : if (size > (blen - c - sizeof(uint32_t))) {
263 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid data size.\n");
264 0 : return EINVAL;
265 : }
266 :
267 258 : switch(type) {
268 : case SSS_PAM_ITEM_USER:
269 36 : ret = extract_string(&pd->logon_name, size, body, blen, &c);
270 36 : if (ret != EOK) return ret;
271 36 : break;
272 : case SSS_PAM_ITEM_SERVICE:
273 40 : ret = extract_string(&pd->service, size, body, blen, &c);
274 40 : if (ret != EOK) return ret;
275 40 : break;
276 : case SSS_PAM_ITEM_TTY:
277 40 : ret = extract_string(&pd->tty, size, body, blen, &c);
278 40 : if (ret != EOK) return ret;
279 40 : break;
280 : case SSS_PAM_ITEM_RUSER:
281 40 : ret = extract_string(&pd->ruser, size, body, blen, &c);
282 40 : if (ret != EOK) return ret;
283 40 : break;
284 : case SSS_PAM_ITEM_RHOST:
285 40 : ret = extract_string(&pd->rhost, size, body, blen, &c);
286 40 : if (ret != EOK) return ret;
287 40 : break;
288 : case SSS_PAM_ITEM_REQUESTED_DOMAINS:
289 0 : ret = extract_string(&requested_domains, size, body, blen,
290 : &c);
291 0 : if (ret != EOK) return ret;
292 :
293 0 : ret = split_on_separator(pd, requested_domains, ',', true,
294 : true, &pd->requested_domains,
295 : NULL);
296 0 : if (ret != EOK) {
297 0 : DEBUG(SSSDBG_CRIT_FAILURE,
298 : "Failed to parse requested_domains list!\n");
299 0 : return ret;
300 : }
301 0 : break;
302 : case SSS_PAM_ITEM_CLI_PID:
303 40 : ret = extract_uint32_t(&pd->cli_pid, size,
304 : body, blen, &c);
305 40 : if (ret != EOK) return ret;
306 40 : break;
307 : case SSS_PAM_ITEM_AUTHTOK:
308 22 : ret = extract_authtok_v2(pd->authtok,
309 : size, body, blen, &c);
310 22 : if (ret != EOK) return ret;
311 22 : break;
312 : case SSS_PAM_ITEM_NEWAUTHTOK:
313 0 : ret = extract_authtok_v2(pd->newauthtok,
314 : size, body, blen, &c);
315 0 : if (ret != EOK) return ret;
316 0 : break;
317 : default:
318 0 : DEBUG(SSSDBG_CRIT_FAILURE,
319 : "Ignoring unknown data type [%d].\n", type);
320 0 : c += size;
321 : }
322 : }
323 :
324 298 : } while(c < blen);
325 :
326 40 : return EOK;
327 :
328 : }
329 :
330 40 : static int pam_parse_in_data_v3(struct pam_data *pd,
331 : uint8_t *body, size_t blen)
332 : {
333 : int ret;
334 :
335 40 : ret = pam_parse_in_data_v2(pd, body, blen);
336 40 : if (ret != EOK) {
337 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_parse_in_data_v2 failed.\n");
338 0 : return ret;
339 : }
340 :
341 40 : if (pd->cli_pid == 0) {
342 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing client PID.\n");
343 0 : return EINVAL;
344 : }
345 :
346 40 : return EOK;
347 : }
348 :
349 0 : static int extract_authtok_v1(struct sss_auth_token *tok,
350 : uint8_t *body, size_t blen, size_t *c)
351 : {
352 : uint32_t auth_token_type;
353 : uint32_t auth_token_length;
354 : uint8_t *auth_token_data;
355 0 : int ret = EOK;
356 :
357 0 : SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c);
358 0 : SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, &body[*c], blen, c);
359 0 : auth_token_data = body+(*c);
360 :
361 0 : switch (auth_token_type) {
362 : case SSS_AUTHTOK_TYPE_EMPTY:
363 0 : sss_authtok_set_empty(tok);
364 0 : break;
365 : case SSS_AUTHTOK_TYPE_PASSWORD:
366 0 : ret = sss_authtok_set_password(tok, (const char *)auth_token_data,
367 : auth_token_length);
368 0 : break;
369 : default:
370 0 : return EINVAL;
371 : }
372 :
373 0 : *c += auth_token_length;
374 :
375 0 : return ret;
376 : }
377 :
378 0 : static int pam_parse_in_data(struct pam_data *pd,
379 : uint8_t *body, size_t blen)
380 : {
381 : size_t start;
382 : size_t end;
383 : size_t last;
384 : int ret;
385 :
386 0 : last = blen - 1;
387 0 : end = 0;
388 :
389 : /* user name */
390 0 : for (start = end; end < last; end++) if (body[end] == '\0') break;
391 0 : if (body[end++] != '\0') return EINVAL;
392 0 : pd->logon_name = (char *) &body[start];
393 :
394 0 : for (start = end; end < last; end++) if (body[end] == '\0') break;
395 0 : if (body[end++] != '\0') return EINVAL;
396 0 : pd->service = (char *) &body[start];
397 :
398 0 : for (start = end; end < last; end++) if (body[end] == '\0') break;
399 0 : if (body[end++] != '\0') return EINVAL;
400 0 : pd->tty = (char *) &body[start];
401 :
402 0 : for (start = end; end < last; end++) if (body[end] == '\0') break;
403 0 : if (body[end++] != '\0') return EINVAL;
404 0 : pd->ruser = (char *) &body[start];
405 :
406 0 : for (start = end; end < last; end++) if (body[end] == '\0') break;
407 0 : if (body[end++] != '\0') return EINVAL;
408 0 : pd->rhost = (char *) &body[start];
409 :
410 0 : ret = extract_authtok_v1(pd->authtok, body, blen, &end);
411 0 : if (ret) {
412 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid auth token\n");
413 0 : return ret;
414 : }
415 0 : ret = extract_authtok_v1(pd->newauthtok, body, blen, &end);
416 0 : if (ret) {
417 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid new auth token\n");
418 0 : return ret;
419 : }
420 :
421 0 : DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
422 :
423 0 : return EOK;
424 : }
425 :
426 : /*=Save-Last-Login-State===================================================*/
427 :
428 7 : static errno_t set_last_login(struct pam_auth_req *preq)
429 : {
430 : struct sysdb_attrs *attrs;
431 : errno_t ret;
432 :
433 7 : attrs = sysdb_new_attrs(preq);
434 7 : if (!attrs) {
435 0 : ret = ENOMEM;
436 0 : goto fail;
437 : }
438 :
439 7 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_ONLINE_AUTH, time(NULL));
440 7 : if (ret != EOK) {
441 0 : goto fail;
442 : }
443 :
444 7 : ret = sysdb_attrs_add_time_t(attrs,
445 : SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN,
446 : time(NULL));
447 7 : if (ret != EOK) {
448 0 : goto fail;
449 : }
450 :
451 7 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_LOGIN, time(NULL));
452 7 : if (ret != EOK) {
453 0 : goto fail;
454 : }
455 :
456 7 : ret = sysdb_set_user_attr(preq->domain, preq->pd->user, attrs,
457 : SYSDB_MOD_REP);
458 7 : if (ret != EOK) {
459 0 : DEBUG(SSSDBG_OP_FAILURE, "set_last_login failed.\n");
460 0 : preq->pd->pam_status = PAM_SYSTEM_ERR;
461 0 : goto fail;
462 : } else {
463 7 : preq->pd->last_auth_saved = true;
464 : }
465 7 : preq->callback(preq);
466 :
467 7 : return EOK;
468 :
469 : fail:
470 0 : return ret;
471 : }
472 :
473 40 : static errno_t filter_responses(struct confdb_ctx *cdb,
474 : struct response_data *resp_list)
475 : {
476 : int ret;
477 : struct response_data *resp;
478 : uint32_t user_info_type;
479 : int64_t expire_date;
480 : int pam_verbosity;
481 :
482 40 : ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
483 : CONFDB_PAM_VERBOSITY, DEFAULT_PAM_VERBOSITY,
484 : &pam_verbosity);
485 40 : if (ret != EOK) {
486 0 : DEBUG(SSSDBG_CRIT_FAILURE,
487 : "Failed to read PAM verbosity, not fatal.\n");
488 0 : pam_verbosity = DEFAULT_PAM_VERBOSITY;
489 : }
490 :
491 40 : resp = resp_list;
492 93 : while(resp != NULL) {
493 13 : if (resp->type == SSS_PAM_USER_INFO) {
494 9 : if (resp->len < sizeof(uint32_t)) {
495 0 : DEBUG(SSSDBG_CRIT_FAILURE, "User info entry is too short.\n");
496 0 : return EINVAL;
497 : }
498 :
499 9 : if (pam_verbosity == PAM_VERBOSITY_NO_MESSAGES) {
500 0 : resp->do_not_send_to_client = true;
501 0 : resp = resp->next;
502 0 : continue;
503 : }
504 :
505 9 : memcpy(&user_info_type, resp->data, sizeof(uint32_t));
506 :
507 9 : resp->do_not_send_to_client = false;
508 9 : switch (user_info_type) {
509 : case SSS_PAM_USER_INFO_OFFLINE_AUTH:
510 7 : if (resp->len != sizeof(uint32_t) + sizeof(int64_t)) {
511 0 : DEBUG(SSSDBG_CRIT_FAILURE,
512 : "User info offline auth entry is "
513 : "too short.\n");
514 0 : return EINVAL;
515 : }
516 7 : memcpy(&expire_date, resp->data + sizeof(uint32_t),
517 : sizeof(int64_t));
518 14 : if ((expire_date == 0 &&
519 7 : pam_verbosity < PAM_VERBOSITY_INFO) ||
520 0 : (expire_date > 0 &&
521 0 : pam_verbosity < PAM_VERBOSITY_IMPORTANT)) {
522 7 : resp->do_not_send_to_client = true;
523 : }
524 :
525 7 : break;
526 : default:
527 2 : DEBUG(SSSDBG_TRACE_LIBS,
528 : "User info type [%d] not filtered.\n",
529 : user_info_type);
530 : }
531 4 : } else if (resp->type & SSS_SERVER_INFO) {
532 0 : resp->do_not_send_to_client = true;
533 : }
534 :
535 13 : resp = resp->next;
536 : }
537 :
538 40 : return EOK;
539 : }
540 :
541 0 : static void pam_reply_delay(struct tevent_context *ev, struct tevent_timer *te,
542 : struct timeval tv, void *pvt)
543 : {
544 : struct pam_auth_req *preq;
545 :
546 0 : DEBUG(SSSDBG_CONF_SETTINGS, "pam_reply_delay get called.\n");
547 :
548 0 : preq = talloc_get_type(pvt, struct pam_auth_req);
549 :
550 0 : pam_reply(preq);
551 0 : }
552 :
553 16 : static errno_t get_password_for_cache_auth(struct sss_auth_token *authtok,
554 : const char **password)
555 : {
556 : int ret;
557 : size_t pw_len;
558 : const char *fa2;
559 : size_t fa2_len;
560 :
561 16 : switch (sss_authtok_get_type(authtok)) {
562 : case SSS_AUTHTOK_TYPE_PASSWORD:
563 12 : ret = sss_authtok_get_password(authtok, password, NULL);
564 12 : break;
565 : case SSS_AUTHTOK_TYPE_2FA:
566 4 : ret = sss_authtok_get_2fa(authtok, password, &pw_len, &fa2, &fa2_len);
567 4 : break;
568 : default:
569 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Unsupported auth token type [%d].\n",
570 : sss_authtok_get_type(authtok));
571 0 : ret = EINVAL;
572 : }
573 16 : if (ret != EOK) {
574 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get password.\n");
575 0 : return ret;
576 : }
577 :
578 16 : return EOK;
579 : }
580 :
581 : static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd);
582 : static void pam_handle_cached_login(struct pam_auth_req *preq, int ret,
583 : time_t expire_date, time_t delayed_until, bool cached_auth);
584 :
585 63 : static void pam_reply(struct pam_auth_req *preq)
586 : {
587 : struct cli_ctx *cctx;
588 : uint8_t *body;
589 : size_t blen;
590 : int ret;
591 : int32_t resp_c;
592 : int32_t resp_size;
593 : struct response_data *resp;
594 : int p;
595 : struct timeval tv;
596 : struct tevent_timer *te;
597 : struct pam_data *pd;
598 : struct pam_ctx *pctx;
599 : uint32_t user_info_type;
600 63 : time_t exp_date = -1;
601 63 : time_t delay_until = -1;
602 : char* pam_account_expired_message;
603 : char* pam_account_locked_message;
604 : int pam_verbosity;
605 :
606 63 : pd = preq->pd;
607 63 : cctx = preq->cctx;
608 63 : pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
609 :
610 63 : ret = confdb_get_int(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY,
611 : CONFDB_PAM_VERBOSITY, DEFAULT_PAM_VERBOSITY,
612 : &pam_verbosity);
613 63 : if (ret != EOK) {
614 0 : DEBUG(SSSDBG_CRIT_FAILURE,
615 : "Failed to read PAM verbosity, not fatal.\n");
616 0 : pam_verbosity = DEFAULT_PAM_VERBOSITY;
617 : }
618 :
619 63 : DEBUG(SSSDBG_FUNC_DATA,
620 : "pam_reply called with result [%d]: %s.\n",
621 : pd->pam_status, pam_strerror(NULL, pd->pam_status));
622 63 : if (pd->pam_status == PAM_AUTHINFO_UNAVAIL || preq->use_cached_auth) {
623 :
624 18 : switch(pd->cmd) {
625 : case SSS_PAM_AUTHENTICATE:
626 32 : if ((preq->domain != NULL) &&
627 32 : (preq->domain->cache_credentials == true) &&
628 16 : (pd->offline_auth == false)) {
629 16 : const char *password = NULL;
630 : bool use_cached_auth;
631 :
632 : /* backup value of preq->use_cached_auth*/
633 16 : use_cached_auth = preq->use_cached_auth;
634 : /* set to false to avoid entering this branch when pam_reply()
635 : * is recursively called from pam_handle_cached_login() */
636 16 : preq->use_cached_auth = false;
637 :
638 : /* do auth with offline credentials */
639 16 : pd->offline_auth = true;
640 :
641 16 : if (preq->domain->sysdb == NULL) {
642 0 : DEBUG(SSSDBG_FATAL_FAILURE,
643 : "Fatal: Sysdb CTX not found for domain"
644 : " [%s]!\n", preq->domain->name);
645 0 : goto done;
646 : }
647 :
648 16 : ret = get_password_for_cache_auth(pd->authtok, &password);
649 16 : if (ret != EOK) {
650 0 : DEBUG(SSSDBG_FATAL_FAILURE,
651 : "get_password_and_type_for_cache_auth failed.\n");
652 0 : goto done;
653 : }
654 :
655 32 : ret = sysdb_cache_auth(preq->domain,
656 16 : pd->user, password,
657 16 : pctx->rctx->cdb, false,
658 : &exp_date, &delay_until);
659 :
660 16 : pam_handle_cached_login(preq, ret, exp_date, delay_until,
661 : use_cached_auth);
662 16 : return;
663 : }
664 0 : break;
665 : case SSS_PAM_CHAUTHTOK_PRELIM:
666 : case SSS_PAM_CHAUTHTOK:
667 2 : DEBUG(SSSDBG_FUNC_DATA,
668 : "Password change not possible while offline.\n");
669 2 : pd->pam_status = PAM_AUTHTOK_ERR;
670 2 : user_info_type = SSS_PAM_USER_INFO_OFFLINE_CHPASS;
671 2 : ret = pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t),
672 : (const uint8_t *) &user_info_type);
673 2 : if (ret != EOK) {
674 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
675 0 : goto done;
676 : }
677 2 : break;
678 : /* TODO: we need the pam session cookie here to make sure that cached
679 : * authentication was successful */
680 : case SSS_PAM_SETCRED:
681 : case SSS_PAM_ACCT_MGMT:
682 : case SSS_PAM_OPEN_SESSION:
683 : case SSS_PAM_CLOSE_SESSION:
684 0 : DEBUG(SSSDBG_OP_FAILURE,
685 : "Assuming offline authentication setting status for "
686 : "pam call %d to PAM_SUCCESS.\n", pd->cmd);
687 0 : pd->pam_status = PAM_SUCCESS;
688 0 : break;
689 : default:
690 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown PAM call [%d].\n", pd->cmd);
691 0 : pd->pam_status = PAM_MODULE_UNKNOWN;
692 : }
693 : }
694 :
695 47 : if (pd->pam_status == PAM_SUCCESS && pd->cmd == SSS_PAM_CHAUTHTOK) {
696 1 : ret = pam_null_last_online_auth_with_curr_token(preq->domain,
697 1 : pd->user);
698 1 : if (ret != EOK) {
699 0 : DEBUG(SSSDBG_CRIT_FAILURE,
700 : "sysdb_null_last_online_auth_with_curr_token failed: "
701 : "%s [%d].\n", sss_strerror(ret), ret);
702 0 : goto done;
703 : }
704 : }
705 :
706 47 : if (pd->response_delay > 0) {
707 0 : ret = gettimeofday(&tv, NULL);
708 0 : if (ret != EOK) {
709 0 : DEBUG(SSSDBG_CRIT_FAILURE, "gettimeofday failed [%d][%s].\n",
710 : errno, strerror(errno));
711 0 : goto done;
712 : }
713 0 : tv.tv_sec += pd->response_delay;
714 0 : tv.tv_usec = 0;
715 0 : pd->response_delay = 0;
716 :
717 0 : te = tevent_add_timer(cctx->ev, cctx, tv, pam_reply_delay, preq);
718 0 : if (te == NULL) {
719 0 : DEBUG(SSSDBG_CRIT_FAILURE,
720 : "Failed to add event pam_reply_delay.\n");
721 0 : goto done;
722 : }
723 :
724 0 : return;
725 : }
726 :
727 : /* If this was a successful login, save the lastLogin time */
728 77 : if (pd->cmd == SSS_PAM_AUTHENTICATE &&
729 53 : pd->pam_status == PAM_SUCCESS &&
730 46 : preq->domain->cache_credentials &&
731 37 : !pd->offline_auth &&
732 21 : !pd->last_auth_saved &&
733 14 : NEED_CHECK_PROVIDER(preq->domain->provider)) {
734 7 : ret = set_last_login(preq);
735 7 : if (ret != EOK) {
736 0 : goto done;
737 : }
738 7 : return;
739 : }
740 :
741 40 : ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in),
742 40 : &cctx->creq->out);
743 40 : if (ret != EOK) {
744 0 : goto done;
745 : }
746 :
747 : /* Account expiration warning is printed for sshd. If pam_verbosity
748 : * is equal or above PAM_VERBOSITY_INFO then all services are informed
749 : * about account expiration.
750 : */
751 40 : if (pd->pam_status == PAM_ACCT_EXPIRED &&
752 0 : ((pd->service != NULL && strcasecmp(pd->service, "sshd") == 0) ||
753 0 : pam_verbosity >= PAM_VERBOSITY_INFO)) {
754 :
755 0 : ret = confdb_get_string(pctx->rctx->cdb, pd, CONFDB_PAM_CONF_ENTRY,
756 : CONFDB_PAM_ACCOUNT_EXPIRED_MESSAGE, "",
757 : &pam_account_expired_message);
758 0 : if (ret != EOK) {
759 0 : DEBUG(SSSDBG_MINOR_FAILURE,
760 : "Failed to get expiration message: %d:[%s].\n",
761 : ret, sss_strerror(ret));
762 0 : goto done;
763 : }
764 :
765 0 : inform_user(pd, pam_account_expired_message);
766 : }
767 :
768 40 : if (pd->account_locked) {
769 :
770 0 : ret = confdb_get_string(pctx->rctx->cdb, pd, CONFDB_PAM_CONF_ENTRY,
771 : CONFDB_PAM_ACCOUNT_LOCKED_MESSAGE, "",
772 : &pam_account_locked_message);
773 0 : if (ret != EOK) {
774 0 : DEBUG(SSSDBG_MINOR_FAILURE,
775 : "Failed to get expiration message: %d:[%s].\n",
776 : ret, sss_strerror(ret));
777 0 : goto done;
778 : }
779 :
780 0 : inform_user(pd, pam_account_locked_message);
781 : }
782 :
783 40 : ret = filter_responses(pctx->rctx->cdb, pd->resp_list);
784 40 : if (ret != EOK) {
785 0 : DEBUG(SSSDBG_CRIT_FAILURE, "filter_responses failed, not fatal.\n");
786 : }
787 :
788 40 : if (pd->domain != NULL) {
789 37 : ret = pam_add_response(pd, SSS_PAM_DOMAIN_NAME, strlen(pd->domain)+1,
790 37 : (uint8_t *) pd->domain);
791 37 : if (ret != EOK) {
792 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
793 0 : goto done;
794 : }
795 : }
796 :
797 40 : resp_c = 0;
798 40 : resp_size = 0;
799 40 : resp = pd->resp_list;
800 130 : while(resp != NULL) {
801 50 : if (!resp->do_not_send_to_client) {
802 43 : resp_c++;
803 43 : resp_size += resp->len;
804 : }
805 50 : resp = resp->next;
806 : }
807 :
808 40 : ret = sss_packet_grow(cctx->creq->out, sizeof(int32_t) +
809 40 : sizeof(int32_t) +
810 : resp_c * 2* sizeof(int32_t) +
811 : resp_size);
812 40 : if (ret != EOK) {
813 0 : goto done;
814 : }
815 :
816 40 : sss_packet_get_body(cctx->creq->out, &body, &blen);
817 40 : DEBUG(SSSDBG_FUNC_DATA, "blen: %zu\n", blen);
818 40 : p = 0;
819 :
820 40 : memcpy(&body[p], &pd->pam_status, sizeof(int32_t));
821 40 : p += sizeof(int32_t);
822 :
823 40 : memcpy(&body[p], &resp_c, sizeof(int32_t));
824 40 : p += sizeof(int32_t);
825 :
826 40 : resp = pd->resp_list;
827 130 : while(resp != NULL) {
828 50 : if (!resp->do_not_send_to_client) {
829 43 : memcpy(&body[p], &resp->type, sizeof(int32_t));
830 43 : p += sizeof(int32_t);
831 43 : memcpy(&body[p], &resp->len, sizeof(int32_t));
832 43 : p += sizeof(int32_t);
833 43 : memcpy(&body[p], resp->data, resp->len);
834 43 : p += resp->len;
835 : }
836 :
837 50 : resp = resp->next;
838 : }
839 :
840 : done:
841 40 : sss_cmd_done(cctx, preq);
842 : }
843 :
844 : static void pam_dom_forwarder(struct pam_auth_req *preq);
845 :
846 16 : static void pam_handle_cached_login(struct pam_auth_req *preq, int ret,
847 : time_t expire_date, time_t delayed_until,
848 : bool use_cached_auth)
849 : {
850 : uint32_t resp_type;
851 : size_t resp_len;
852 : uint8_t *resp;
853 : int64_t dummy;
854 :
855 16 : preq->pd->pam_status = cached_login_pam_status(ret);
856 :
857 16 : switch (preq->pd->pam_status) {
858 : case PAM_SUCCESS:
859 7 : resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH;
860 7 : resp_len = sizeof(uint32_t) + sizeof(int64_t);
861 7 : resp = talloc_size(preq->pd, resp_len);
862 7 : if (resp == NULL) {
863 0 : DEBUG(SSSDBG_CRIT_FAILURE,
864 : "talloc_size failed, cannot prepare user info.\n");
865 : } else {
866 7 : memcpy(resp, &resp_type, sizeof(uint32_t));
867 7 : dummy = (int64_t) expire_date;
868 7 : memcpy(resp+sizeof(uint32_t), &dummy, sizeof(int64_t));
869 7 : ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len,
870 : (const uint8_t *) resp);
871 7 : if (ret != EOK) {
872 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
873 : }
874 : }
875 7 : break;
876 : case PAM_PERM_DENIED:
877 1 : if (delayed_until >= 0) {
878 0 : resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH_DELAYED;
879 0 : resp_len = sizeof(uint32_t) + sizeof(int64_t);
880 0 : resp = talloc_size(preq->pd, resp_len);
881 0 : if (resp == NULL) {
882 0 : DEBUG(SSSDBG_CRIT_FAILURE,
883 : "talloc_size failed, cannot prepare user info.\n");
884 : } else {
885 0 : memcpy(resp, &resp_type, sizeof(uint32_t));
886 0 : dummy = (int64_t) delayed_until;
887 0 : memcpy(resp+sizeof(uint32_t), &dummy, sizeof(int64_t));
888 0 : ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len,
889 : (const uint8_t *) resp);
890 0 : if (ret != EOK) {
891 0 : DEBUG(SSSDBG_CRIT_FAILURE,
892 : "pam_add_response failed.\n");
893 : }
894 : }
895 : }
896 1 : break;
897 : case PAM_AUTH_ERR:
898 : /* Was this attempt to authenticate from cache? */
899 8 : if (use_cached_auth) {
900 : /* Don't try cached authentication again, try online check. */
901 2 : DEBUG(SSSDBG_FUNC_DATA,
902 : "Cached authentication failed for: %s\n",
903 : preq->pd->user);
904 2 : preq->cached_auth_failed = true;
905 2 : pam_dom_forwarder(preq);
906 2 : return;
907 : }
908 6 : break;
909 : default:
910 0 : DEBUG(SSSDBG_TRACE_LIBS,
911 : "cached login returned: %d\n", preq->pd->pam_status);
912 : }
913 :
914 14 : pam_reply(preq);
915 14 : return;
916 : }
917 :
918 : static void pam_forwarder_cb(struct tevent_req *req);
919 : static void pam_forwarder_cert_cb(struct tevent_req *req);
920 : static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
921 : const char *err_msg, void *ptr);
922 : static int pam_check_user_search(struct pam_auth_req *preq);
923 : static int pam_check_user_done(struct pam_auth_req *preq, int ret);
924 :
925 : /* TODO: we should probably return some sort of cookie that is set in the
926 : * PAM_ENVIRONMENT, so that we can save performing some calls and cache
927 : * data. */
928 :
929 40 : static errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *pd)
930 : {
931 : uint8_t *body;
932 : size_t blen;
933 : errno_t ret;
934 : uint32_t terminator;
935 :
936 40 : sss_packet_get_body(cctx->creq->in, &body, &blen);
937 40 : if (blen >= sizeof(uint32_t)) {
938 40 : SAFEALIGN_COPY_UINT32(&terminator,
939 : body + blen - sizeof(uint32_t),
940 : NULL);
941 40 : if (terminator != SSS_END_OF_PAM_REQUEST) {
942 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Received data not terminated.\n");
943 0 : ret = EINVAL;
944 0 : goto done;
945 : }
946 : }
947 :
948 40 : switch (cctx->cli_protocol_version->version) {
949 : case 1:
950 0 : ret = pam_parse_in_data(pd, body, blen);
951 0 : break;
952 : case 2:
953 0 : ret = pam_parse_in_data_v2(pd, body, blen);
954 0 : break;
955 : case 3:
956 40 : ret = pam_parse_in_data_v3(pd, body, blen);
957 40 : break;
958 : default:
959 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Illegal protocol version [%d].\n",
960 : cctx->cli_protocol_version->version);
961 0 : ret = EINVAL;
962 : }
963 40 : if (ret != EOK) {
964 0 : goto done;
965 : }
966 :
967 40 : if (pd->logon_name != NULL) {
968 72 : ret = sss_parse_name_for_domains(pd, cctx->rctx->domains,
969 36 : cctx->rctx->default_domain,
970 36 : pd->logon_name,
971 : &pd->domain, &pd->user);
972 : } else {
973 : /* Only SSS_PAM_PREAUTH request may have a missing name, e.g. if the
974 : * name is determined with the help of a certificate */
975 4 : if (pd->cmd == SSS_PAM_PREAUTH
976 4 : && may_do_cert_auth(talloc_get_type(cctx->rctx->pvt_ctx,
977 : struct pam_ctx), pd)) {
978 3 : ret = EOK;
979 : } else {
980 1 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing logon name in PAM request.\n");
981 1 : ret = ERR_NO_CREDS;
982 1 : goto done;
983 : }
984 : }
985 :
986 39 : DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
987 :
988 : done:
989 40 : return ret;
990 : }
991 :
992 40 : static int pam_auth_req_destructor(struct pam_auth_req *preq)
993 : {
994 40 : if (preq && preq->dpreq_spy) {
995 : /* If there is still a request pending, tell the spy
996 : * the client is going away
997 : */
998 0 : preq->dpreq_spy->preq = NULL;
999 : }
1000 40 : return 0;
1001 : }
1002 :
1003 40 : static bool is_uid_trusted(struct cli_creds *creds,
1004 : size_t trusted_uids_count,
1005 : uid_t *trusted_uids)
1006 : {
1007 : errno_t ret;
1008 :
1009 : /* root is always trusted */
1010 40 : if (client_euid(creds) == 0) {
1011 0 : return true;
1012 : }
1013 :
1014 : /* All uids are allowed */
1015 40 : if (trusted_uids_count == 0) {
1016 40 : return true;
1017 : }
1018 :
1019 0 : ret = check_allowed_uids(client_euid(creds), trusted_uids_count, trusted_uids);
1020 0 : if (ret == EOK) return true;
1021 :
1022 0 : return false;
1023 : }
1024 :
1025 0 : static bool is_domain_public(char *name,
1026 : char **public_dom_names,
1027 : size_t public_dom_names_count)
1028 : {
1029 : size_t i;
1030 :
1031 0 : for(i=0; i < public_dom_names_count; i++) {
1032 0 : if (strcasecmp(name, public_dom_names[i]) == 0) {
1033 0 : return true;
1034 : }
1035 : }
1036 0 : return false;
1037 : }
1038 :
1039 9 : static errno_t check_cert(TALLOC_CTX *mctx,
1040 : struct tevent_context *ev,
1041 : struct pam_ctx *pctx,
1042 : struct pam_auth_req *preq,
1043 : struct pam_data *pd)
1044 : {
1045 : int p11_child_timeout;
1046 9 : const int P11_CHILD_TIMEOUT_DEFAULT = 10;
1047 : char *cert_verification_opts;
1048 : errno_t ret;
1049 : struct tevent_req *req;
1050 :
1051 9 : ret = confdb_get_int(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY,
1052 : CONFDB_PAM_P11_CHILD_TIMEOUT,
1053 : P11_CHILD_TIMEOUT_DEFAULT,
1054 : &p11_child_timeout);
1055 9 : if (ret != EOK) {
1056 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1057 : "Failed to read p11_child_timeout from confdb: [%d]: %s\n",
1058 : ret, sss_strerror(ret));
1059 0 : return ret;
1060 : }
1061 :
1062 9 : ret = confdb_get_string(pctx->rctx->cdb, mctx, CONFDB_MONITOR_CONF_ENTRY,
1063 : CONFDB_MONITOR_CERT_VERIFICATION, NULL,
1064 : &cert_verification_opts);
1065 9 : if (ret != EOK) {
1066 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1067 : "Failed to read certificate_verification from confdb: [%d]: %s\n",
1068 : ret, sss_strerror(ret));
1069 0 : return ret;
1070 : }
1071 :
1072 18 : req = pam_check_cert_send(mctx, ev, pctx->p11_child_debug_fd,
1073 9 : pctx->nss_db, p11_child_timeout,
1074 : cert_verification_opts, pd);
1075 9 : if (req == NULL) {
1076 0 : DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n");
1077 0 : return ENOMEM;
1078 : }
1079 :
1080 9 : tevent_req_set_callback(req, pam_forwarder_cert_cb, preq);
1081 9 : return EAGAIN;
1082 : }
1083 :
1084 40 : static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
1085 : {
1086 : struct sss_domain_info *dom;
1087 : struct pam_auth_req *preq;
1088 : struct pam_data *pd;
1089 : int ret;
1090 : errno_t ncret;
1091 40 : struct pam_ctx *pctx =
1092 40 : talloc_get_type(cctx->rctx->pvt_ctx, struct pam_ctx);
1093 : struct tevent_req *req;
1094 :
1095 40 : preq = talloc_zero(cctx, struct pam_auth_req);
1096 40 : if (!preq) {
1097 0 : return ENOMEM;
1098 : }
1099 40 : talloc_set_destructor(preq, pam_auth_req_destructor);
1100 40 : preq->cctx = cctx;
1101 :
1102 40 : preq->pd = create_pam_data(preq);
1103 40 : if (!preq->pd) {
1104 0 : talloc_free(preq);
1105 0 : return ENOMEM;
1106 : }
1107 40 : pd = preq->pd;
1108 :
1109 40 : preq->is_uid_trusted = is_uid_trusted(cctx->creds,
1110 : pctx->trusted_uids_count,
1111 : pctx->trusted_uids);
1112 :
1113 40 : if (!preq->is_uid_trusted) {
1114 0 : DEBUG(SSSDBG_MINOR_FAILURE, "uid %"SPRIuid" is not trusted.\n",
1115 : client_euid(cctx->creds));
1116 : }
1117 :
1118 :
1119 40 : pd->cmd = pam_cmd;
1120 40 : pd->priv = cctx->priv;
1121 :
1122 40 : ret = pam_forwarder_parse_data(cctx, pd);
1123 40 : if (ret == EAGAIN) {
1124 0 : req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, true, pd->domain);
1125 0 : if (req == NULL) {
1126 0 : ret = ENOMEM;
1127 : } else {
1128 0 : tevent_req_set_callback(req, pam_forwarder_cb, preq);
1129 0 : ret = EAGAIN;
1130 : }
1131 0 : goto done;
1132 40 : } else if (ret != EOK) {
1133 1 : goto done;
1134 : }
1135 :
1136 39 : if (pd->user != NULL) {
1137 : /* now check user is valid */
1138 36 : if (pd->domain) {
1139 0 : preq->domain = responder_get_domain(cctx->rctx, pd->domain);
1140 0 : if (!preq->domain) {
1141 0 : ret = ENOENT;
1142 0 : goto done;
1143 : }
1144 :
1145 0 : ncret = sss_ncache_check_user(pctx->rctx->ncache,
1146 0 : preq->domain, pd->user);
1147 0 : if (ncret == EEXIST) {
1148 : /* User found in the negative cache */
1149 0 : ret = ENOENT;
1150 0 : goto done;
1151 : }
1152 : } else {
1153 72 : for (dom = preq->cctx->rctx->domains;
1154 : dom;
1155 0 : dom = get_next_domain(dom, 0)) {
1156 36 : if (dom->fqnames) continue;
1157 :
1158 36 : ncret = sss_ncache_check_user(pctx->rctx->ncache,
1159 36 : dom, pd->user);
1160 36 : if (ncret == ENOENT) {
1161 : /* User not found in the negative cache
1162 : * Proceed with PAM actions
1163 : */
1164 36 : break;
1165 : }
1166 :
1167 : /* Try the next domain */
1168 0 : DEBUG(SSSDBG_TRACE_FUNC,
1169 : "User [%s@%s] filtered out (negative cache). "
1170 : "Trying next domain.\n", pd->user, dom->name);
1171 : }
1172 :
1173 36 : if (!dom) {
1174 0 : ret = ENOENT;
1175 0 : goto done;
1176 : }
1177 36 : preq->domain = dom;
1178 : }
1179 : }
1180 :
1181 :
1182 39 : if (may_do_cert_auth(pctx, pd)) {
1183 9 : ret = check_cert(cctx, cctx->ev, pctx, preq, pd);
1184 : /* Finish here */
1185 9 : goto done;
1186 : }
1187 :
1188 :
1189 30 : if (preq->domain->provider == NULL) {
1190 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1191 : "Domain [%s] has no auth provider.\n", preq->domain->name);
1192 0 : ret = EINVAL;
1193 0 : goto done;
1194 : }
1195 :
1196 30 : preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider);
1197 :
1198 30 : ret = pam_check_user_search(preq);
1199 30 : if (ret == EOK) {
1200 30 : pam_dom_forwarder(preq);
1201 : }
1202 :
1203 : done:
1204 40 : return pam_check_user_done(preq, ret);
1205 : }
1206 :
1207 : static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req);
1208 9 : static void pam_forwarder_cert_cb(struct tevent_req *req)
1209 : {
1210 9 : struct pam_auth_req *preq = tevent_req_callback_data(req,
1211 : struct pam_auth_req);
1212 9 : struct cli_ctx *cctx = preq->cctx;
1213 : struct pam_data *pd;
1214 9 : errno_t ret = EOK;
1215 : char *cert;
1216 9 : struct pam_ctx *pctx =
1217 9 : talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
1218 :
1219 9 : ret = pam_check_cert_recv(req, preq, &cert, &preq->token_name);
1220 9 : talloc_free(req);
1221 9 : if (ret != EOK) {
1222 0 : DEBUG(SSSDBG_OP_FAILURE, "get_cert request failed.\n");
1223 0 : goto done;
1224 : }
1225 :
1226 9 : pd = preq->pd;
1227 :
1228 9 : if (cert == NULL) {
1229 2 : if (pd->logon_name == NULL) {
1230 1 : DEBUG(SSSDBG_CRIT_FAILURE,
1231 : "No certificate found and no logon name given, " \
1232 : "authentication not possible.\n");;
1233 1 : ret = ENOENT;
1234 : } else {
1235 1 : if (pd->cmd == SSS_PAM_AUTHENTICATE) {
1236 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1237 : "No certificate returned, authentication failed.\n");
1238 0 : ret = ENOENT;
1239 : } else {
1240 1 : ret = pam_check_user_search(preq);
1241 1 : if (ret == EOK) {
1242 1 : pam_dom_forwarder(preq);
1243 : }
1244 : }
1245 :
1246 : }
1247 2 : goto done;
1248 : }
1249 :
1250 :
1251 14 : req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx,
1252 7 : pctx->rctx->ncache, 0, NULL, cert);
1253 7 : if (req == NULL) {
1254 0 : DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n");
1255 0 : ret = ENOMEM;
1256 0 : goto done;
1257 : }
1258 7 : tevent_req_set_callback(req, pam_forwarder_lookup_by_cert_done, preq);
1259 16 : return;
1260 :
1261 : done:
1262 2 : pam_check_user_done(preq, ret);
1263 : }
1264 :
1265 7 : static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
1266 : {
1267 : int ret;
1268 : struct ldb_result *res;
1269 : struct sss_domain_info *domain;
1270 7 : struct pam_auth_req *preq = tevent_req_callback_data(req,
1271 : struct pam_auth_req);
1272 : const char *cert_user;
1273 :
1274 :
1275 7 : ret = cache_req_user_by_cert_recv(preq, req, &res, &domain, NULL);
1276 7 : talloc_zfree(req);
1277 7 : if (ret != EOK && ret != ENOENT) {
1278 0 : DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert request failed.\n");
1279 0 : goto done;
1280 : }
1281 :
1282 7 : if (ret == EOK && res->count > 1) {
1283 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1284 : "Search by certificate returned more than one result.\n");
1285 0 : ret = EINVAL;
1286 0 : goto done;
1287 : }
1288 :
1289 7 : if (ret == EOK) {
1290 5 : if (preq->domain == NULL) {
1291 1 : preq->domain = domain;
1292 : }
1293 :
1294 5 : preq->cert_user_obj = talloc_steal(preq, res->msgs[0]);
1295 :
1296 5 : if (preq->pd->logon_name == NULL) {
1297 1 : cert_user = ldb_msg_find_attr_as_string(preq->cert_user_obj,
1298 : SYSDB_NAME, NULL);
1299 1 : if (cert_user == NULL) {
1300 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1301 : "Certificate user object has not name.\n");
1302 0 : ret = ENOENT;
1303 0 : goto done;
1304 : }
1305 :
1306 1 : DEBUG(SSSDBG_FUNC_DATA, "Found certificate user [%s].\n",
1307 : cert_user);
1308 :
1309 1 : ret = add_pam_cert_response(preq->pd, cert_user, preq->token_name);
1310 1 : if (ret != EOK) {
1311 0 : DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n");
1312 : }
1313 :
1314 1 : preq->pd->domain = talloc_strdup(preq->pd, domain->name);
1315 1 : if (preq->pd->domain == NULL) {
1316 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
1317 0 : ret = ENOMEM;
1318 0 : goto done;
1319 : }
1320 1 : preq->pd->pam_status = PAM_SUCCESS;
1321 1 : pam_reply(preq);
1322 8 : return;
1323 : }
1324 : } else {
1325 2 : if (preq->pd->logon_name == NULL) {
1326 1 : DEBUG(SSSDBG_CRIT_FAILURE,
1327 : "Missing logon name and no certificate user found.\n");
1328 1 : ret = ENOENT;
1329 1 : goto done;
1330 : }
1331 : }
1332 :
1333 5 : ret = pam_check_user_search(preq);
1334 5 : if (ret == EOK) {
1335 5 : pam_dom_forwarder(preq);
1336 : }
1337 :
1338 : done:
1339 6 : pam_check_user_done(preq, ret);
1340 : }
1341 :
1342 0 : static void pam_forwarder_cb(struct tevent_req *req)
1343 : {
1344 0 : struct pam_auth_req *preq = tevent_req_callback_data(req,
1345 : struct pam_auth_req);
1346 0 : struct cli_ctx *cctx = preq->cctx;
1347 : struct pam_data *pd;
1348 0 : errno_t ret = EOK;
1349 0 : struct pam_ctx *pctx =
1350 0 : talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
1351 :
1352 0 : ret = sss_dp_get_domains_recv(req);
1353 0 : talloc_free(req);
1354 0 : if (ret != EOK) {
1355 0 : goto done;
1356 : }
1357 :
1358 0 : pd = preq->pd;
1359 :
1360 0 : ret = pam_forwarder_parse_data(cctx, pd);
1361 0 : if (ret == EAGAIN) {
1362 0 : if (strchr(preq->pd->logon_name, '@') == NULL) {
1363 0 : goto done;
1364 : }
1365 : /* Assuming Kerberos principal */
1366 0 : preq->domain = preq->cctx->rctx->domains;
1367 0 : preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider);
1368 0 : preq->pd->user = talloc_strdup(preq->pd, preq->pd->logon_name);
1369 0 : if (preq->pd->user == NULL) {
1370 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
1371 0 : ret = ENOMEM;
1372 0 : goto done;
1373 : }
1374 0 : preq->pd->name_is_upn = true;
1375 0 : preq->pd->domain = NULL;
1376 0 : } else if (ret != EOK) {
1377 0 : ret = EINVAL;
1378 0 : goto done;
1379 : }
1380 :
1381 0 : if (preq->pd->domain) {
1382 0 : preq->domain = responder_get_domain(cctx->rctx, preq->pd->domain);
1383 0 : if (preq->domain == NULL) {
1384 0 : ret = ENOENT;
1385 0 : goto done;
1386 : }
1387 : }
1388 :
1389 0 : if (may_do_cert_auth(pctx, pd)) {
1390 0 : ret = check_cert(cctx, cctx->ev, pctx, preq, pd);
1391 : /* Finish here */
1392 0 : goto done;
1393 : }
1394 :
1395 0 : ret = pam_check_user_search(preq);
1396 0 : if (ret == EOK) {
1397 0 : pam_dom_forwarder(preq);
1398 : }
1399 :
1400 : done:
1401 0 : pam_check_user_done(preq, ret);
1402 0 : }
1403 :
1404 : static void pam_dp_send_acct_req_done(struct tevent_req *req);
1405 36 : static int pam_check_user_search(struct pam_auth_req *preq)
1406 : {
1407 36 : struct sss_domain_info *dom = preq->domain;
1408 36 : char *name = NULL;
1409 : time_t cacheExpire;
1410 : int ret;
1411 : struct tevent_req *dpreq;
1412 : struct dp_callback_ctx *cb_ctx;
1413 36 : struct pam_ctx *pctx =
1414 36 : talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
1415 : static const char *user_attrs[] = SYSDB_PW_ATTRS;
1416 : struct ldb_message *msg;
1417 : struct ldb_result *res;
1418 :
1419 36 : while (dom) {
1420 : /* if it is a domainless search, skip domains that require fully
1421 : * qualified names instead */
1422 72 : while (dom && !preq->pd->domain && !preq->pd->name_is_upn
1423 36 : && dom->fqnames) {
1424 0 : dom = get_next_domain(dom, 0);
1425 : }
1426 :
1427 36 : if (!dom) break;
1428 :
1429 36 : if (dom != preq->domain) {
1430 : /* make sure we reset the check_provider flag when we check
1431 : * a new domain */
1432 0 : preq->check_provider = NEED_CHECK_PROVIDER(dom->provider);
1433 : }
1434 :
1435 : /* make sure to update the preq if we changed domain */
1436 36 : preq->domain = dom;
1437 :
1438 36 : talloc_free(name);
1439 36 : name = sss_get_cased_name(preq, preq->pd->user,
1440 36 : dom->case_sensitive);
1441 36 : if (!name) {
1442 0 : return ENOMEM;
1443 : }
1444 :
1445 36 : name = sss_reverse_replace_space(preq, name,
1446 36 : pctx->rctx->override_space);
1447 36 : if (name == NULL) {
1448 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1449 : "sss_reverse_replace_space failed\n");
1450 0 : return ENOMEM;
1451 : }
1452 :
1453 : /* Refresh the user's cache entry on any PAM query
1454 : * We put a timeout in the client context so that we limit
1455 : * the number of updates within a reasonable timeout
1456 : */
1457 36 : if (preq->check_provider) {
1458 30 : ret = pam_initgr_check_timeout(pctx->id_table,
1459 30 : preq->pd->logon_name);
1460 30 : if (ret != EOK
1461 0 : && ret != ENOENT) {
1462 0 : DEBUG(SSSDBG_OP_FAILURE,
1463 : "Could not look up initgroup timout\n");
1464 0 : return EIO;
1465 30 : } else if (ret == ENOENT) {
1466 : /* Call provider first */
1467 0 : break;
1468 : }
1469 : /* Entry is still valid, get it from the sysdb */
1470 : }
1471 :
1472 36 : DEBUG(SSSDBG_CONF_SETTINGS,
1473 : "Requesting info for [%s@%s]\n", name, dom->name);
1474 :
1475 36 : if (dom->sysdb == NULL) {
1476 0 : DEBUG(SSSDBG_FATAL_FAILURE,
1477 : "Fatal: Sysdb CTX not found for this domain!\n");
1478 0 : preq->pd->pam_status = PAM_SYSTEM_ERR;
1479 0 : return EFAULT;
1480 : }
1481 :
1482 36 : if (preq->pd->name_is_upn) {
1483 0 : ret = sysdb_search_user_by_upn(preq, dom, name, user_attrs, &msg);
1484 : } else {
1485 36 : ret = sysdb_getpwnam_with_views(preq, dom, name, &res);
1486 36 : if (res->count > 1) {
1487 0 : DEBUG(SSSDBG_FATAL_FAILURE,
1488 : "getpwnam call returned more than one result !?!\n");
1489 0 : sss_log(SSS_LOG_ERR,
1490 : "More users have the same name [%s@%s] in SSSD cache. "
1491 : "SSSD will not work correctly.\n",
1492 : name, dom->name);
1493 0 : return ENOENT;
1494 36 : } else if (res->count == 0) {
1495 0 : ret = ENOENT;
1496 : } else {
1497 36 : msg = res->msgs[0];
1498 : }
1499 : }
1500 36 : if (ret != EOK && ret != ENOENT) {
1501 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1502 : "Failed to make request to our cache!\n");
1503 0 : return EIO;
1504 : }
1505 :
1506 36 : if (ret == ENOENT) {
1507 0 : if (preq->check_provider == false) {
1508 : /* set negative cache only if not result of cache check */
1509 0 : ret = sss_ncache_set_user(pctx->rctx->ncache, false, dom, name);
1510 0 : if (ret != EOK) {
1511 : /* Should not be fatal, just slower next time */
1512 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1513 : "Cannot set ncache for [%s@%s]\n", name,
1514 : dom->name);
1515 : }
1516 : }
1517 :
1518 : /* if a multidomain search, try with next */
1519 0 : if (!preq->pd->domain) {
1520 0 : dom = get_next_domain(dom, 0);
1521 0 : continue;
1522 : }
1523 :
1524 0 : DEBUG(SSSDBG_OP_FAILURE, "No results for getpwnam call\n");
1525 :
1526 : /* TODO: store negative cache ? */
1527 :
1528 0 : return ENOENT;
1529 : }
1530 :
1531 : /* One result found */
1532 :
1533 : /* if we need to check the remote account go on */
1534 36 : if (preq->check_provider) {
1535 30 : cacheExpire = ldb_msg_find_attr_as_uint64(msg,
1536 : SYSDB_CACHE_EXPIRE, 0);
1537 30 : if (cacheExpire < time(NULL)) {
1538 0 : break;
1539 : }
1540 : }
1541 :
1542 36 : DEBUG(SSSDBG_TRACE_FUNC,
1543 : "Returning info for user [%s@%s]\n", name, dom->name);
1544 :
1545 : /* We might have searched by alias. Pass on the primary name */
1546 36 : ret = pd_set_primary_name(msg, preq->pd);
1547 36 : if (ret != EOK) {
1548 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not canonicalize username\n");
1549 0 : return ret;
1550 : }
1551 :
1552 36 : return EOK;
1553 : }
1554 :
1555 0 : if (!dom) {
1556 : /* Ensure that we don't try to check a provider without a domain,
1557 : * since this will cause a NULL-dereference below.
1558 : */
1559 0 : preq->check_provider = false;
1560 : }
1561 :
1562 0 : if (preq->check_provider) {
1563 :
1564 : /* dont loop forever :-) */
1565 0 : preq->check_provider = false;
1566 :
1567 0 : dpreq = sss_dp_get_account_send(preq, preq->cctx->rctx,
1568 : dom, false, SSS_DP_INITGROUPS, name, 0,
1569 0 : preq->pd->name_is_upn ? EXTRA_NAME_IS_UPN : NULL);
1570 0 : if (!dpreq) {
1571 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1572 : "Out of memory sending data provider request\n");
1573 0 : return ENOMEM;
1574 : }
1575 :
1576 0 : cb_ctx = talloc_zero(preq, struct dp_callback_ctx);
1577 0 : if(!cb_ctx) {
1578 0 : talloc_zfree(dpreq);
1579 0 : return ENOMEM;
1580 : }
1581 :
1582 0 : cb_ctx->callback = pam_check_user_dp_callback;
1583 0 : cb_ctx->ptr = preq;
1584 0 : cb_ctx->cctx = preq->cctx;
1585 0 : cb_ctx->mem_ctx = preq;
1586 :
1587 0 : tevent_req_set_callback(dpreq, pam_dp_send_acct_req_done, cb_ctx);
1588 :
1589 : /* tell caller we are in an async call */
1590 0 : return EAGAIN;
1591 : }
1592 :
1593 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1594 : "No matching domain found for [%s], fail!\n", preq->pd->user);
1595 0 : return ENOENT;
1596 : }
1597 :
1598 0 : static void pam_dp_send_acct_req_done(struct tevent_req *req)
1599 : {
1600 0 : struct dp_callback_ctx *cb_ctx =
1601 0 : tevent_req_callback_data(req, struct dp_callback_ctx);
1602 :
1603 : errno_t ret;
1604 : dbus_uint16_t err_maj;
1605 : dbus_uint32_t err_min;
1606 : char *err_msg;
1607 :
1608 0 : ret = sss_dp_get_account_recv(cb_ctx->mem_ctx, req,
1609 : &err_maj, &err_min,
1610 : &err_msg);
1611 0 : talloc_zfree(req);
1612 0 : if (ret != EOK) {
1613 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1614 : "Fatal error, killing connection!\n");
1615 0 : talloc_free(cb_ctx->cctx);
1616 0 : return;
1617 : }
1618 :
1619 0 : cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
1620 : }
1621 :
1622 48 : static int pam_check_user_done(struct pam_auth_req *preq, int ret)
1623 : {
1624 48 : switch (ret) {
1625 : case EOK:
1626 36 : break;
1627 :
1628 : case EAGAIN:
1629 : /* performing async request, just return */
1630 9 : break;
1631 :
1632 : case ENOENT:
1633 2 : preq->pd->pam_status = PAM_USER_UNKNOWN;
1634 2 : pam_reply(preq);
1635 2 : break;
1636 :
1637 : case ERR_NO_CREDS:
1638 1 : preq->pd->pam_status = PAM_CRED_INSUFFICIENT;
1639 1 : pam_reply(preq);
1640 1 : break;
1641 :
1642 : default:
1643 0 : preq->pd->pam_status = PAM_SYSTEM_ERR;
1644 0 : pam_reply(preq);
1645 0 : break;
1646 : }
1647 :
1648 48 : return EOK;
1649 : }
1650 :
1651 0 : static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
1652 : const char *err_msg, void *ptr)
1653 : {
1654 0 : struct pam_auth_req *preq = talloc_get_type(ptr, struct pam_auth_req);
1655 : int ret;
1656 0 : struct pam_ctx *pctx =
1657 0 : talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
1658 :
1659 0 : if (err_maj) {
1660 0 : DEBUG(SSSDBG_OP_FAILURE,
1661 : "Unable to get information from Data Provider\n"
1662 : "Error: %u, %u, %s\n",
1663 : (unsigned int)err_maj, (unsigned int)err_min, err_msg);
1664 : }
1665 :
1666 0 : ret = pam_check_user_search(preq);
1667 0 : if (ret == EOK) {
1668 : /* Make sure we don't go to the ID provider too often */
1669 0 : ret = pam_initgr_cache_set(pctx->rctx->ev, pctx->id_table,
1670 0 : preq->pd->logon_name, pctx->id_timeout);
1671 0 : if (ret != EOK) {
1672 0 : DEBUG(SSSDBG_OP_FAILURE,
1673 : "Could not save initgr timestamp. "
1674 : "Proceeding with PAM actions\n");
1675 : /* This is non-fatal, we'll just end up going to the
1676 : * data provider again next time.
1677 : */
1678 : }
1679 :
1680 0 : pam_dom_forwarder(preq);
1681 : }
1682 :
1683 0 : ret = pam_check_user_done(preq, ret);
1684 :
1685 0 : if (ret) {
1686 0 : preq->pd->pam_status = PAM_SYSTEM_ERR;
1687 0 : pam_reply(preq);
1688 : }
1689 0 : }
1690 :
1691 8 : static errno_t pam_is_last_online_login_fresh(struct sss_domain_info *domain,
1692 : const char* user,
1693 : int cached_auth_timeout,
1694 : bool *_result)
1695 : {
1696 : errno_t ret;
1697 : bool result;
1698 : uint64_t last_login;
1699 :
1700 8 : ret = pam_get_last_online_auth_with_curr_token(domain, user, &last_login);
1701 8 : if (ret != EOK) {
1702 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1703 : "sysdb_get_last_online_auth_with_curr_token failed: %s:[%d]\n",
1704 : sss_strerror(ret), ret);
1705 0 : goto done;
1706 : }
1707 :
1708 8 : result = time(NULL) < (last_login + cached_auth_timeout);
1709 8 : ret = EOK;
1710 :
1711 : done:
1712 8 : if (ret == EOK) {
1713 8 : *_result = result;
1714 : }
1715 8 : return ret;
1716 : }
1717 :
1718 8 : static bool pam_is_cmd_cachable(int cmd)
1719 : {
1720 : bool is_cachable;
1721 :
1722 8 : switch(cmd) {
1723 : case SSS_PAM_AUTHENTICATE:
1724 8 : is_cachable = true;
1725 8 : break;
1726 : default:
1727 0 : is_cachable = false;
1728 : }
1729 :
1730 8 : return is_cachable;
1731 : }
1732 :
1733 14 : static bool pam_is_authtok_cachable(struct sss_auth_token *authtok)
1734 : {
1735 : enum sss_authtok_type type;
1736 14 : bool cachable = false;
1737 :
1738 14 : type = sss_authtok_get_type(authtok);
1739 14 : if (type == SSS_AUTHTOK_TYPE_PASSWORD) {
1740 8 : cachable = true;
1741 : } else {
1742 6 : DEBUG(SSSDBG_TRACE_LIBS, "Authentication token can't be cached\n");
1743 : }
1744 :
1745 14 : return cachable;
1746 : }
1747 :
1748 38 : static bool pam_can_user_cache_auth(struct sss_domain_info *domain,
1749 : int pam_cmd,
1750 : struct sss_auth_token *authtok,
1751 : const char* user,
1752 : bool cached_auth_failed)
1753 : {
1754 : errno_t ret;
1755 38 : bool result = false;
1756 :
1757 38 : if (!cached_auth_failed /* don't try cached auth again */
1758 36 : && domain->cache_credentials
1759 36 : && domain->cached_auth_timeout > 0
1760 14 : && pam_is_authtok_cachable(authtok)
1761 8 : && pam_is_cmd_cachable(pam_cmd)) {
1762 :
1763 8 : ret = pam_is_last_online_login_fresh(domain, user,
1764 8 : domain->cached_auth_timeout,
1765 : &result);
1766 8 : if (ret != EOK) {
1767 : /* non-critical, consider fail as 'non-fresh value' */
1768 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1769 : "pam_is_last_online_login_fresh failed: %s:[%d]\n",
1770 : sss_strerror(ret), ret);
1771 : }
1772 : }
1773 :
1774 38 : return result;
1775 : }
1776 :
1777 38 : static void pam_dom_forwarder(struct pam_auth_req *preq)
1778 : {
1779 : int ret;
1780 38 : struct pam_ctx *pctx =
1781 38 : talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
1782 : const char *cert_user;
1783 :
1784 38 : if (!preq->pd->domain) {
1785 36 : preq->pd->domain = preq->domain->name;
1786 : }
1787 :
1788 : /* Untrusted users can access only public domains. */
1789 38 : if (!preq->is_uid_trusted &&
1790 0 : !is_domain_public(preq->pd->domain, pctx->public_domains,
1791 0 : pctx->public_domains_count)) {
1792 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1793 : "Untrusted user %"SPRIuid" cannot access non-public domain %s.\n",
1794 : client_euid(preq->cctx->creds), preq->pd->domain);
1795 0 : preq->pd->pam_status = PAM_PERM_DENIED;
1796 0 : pam_reply(preq);
1797 0 : return;
1798 : }
1799 :
1800 : /* skip this domain if not requested and the user is trusted
1801 : * as untrusted users can't request a domain */
1802 76 : if (preq->is_uid_trusted &&
1803 38 : !is_domain_requested(preq->pd, preq->pd->domain)) {
1804 0 : preq->pd->pam_status = PAM_USER_UNKNOWN;
1805 0 : pam_reply(preq);
1806 0 : return;
1807 : }
1808 :
1809 114 : if (pam_can_user_cache_auth(preq->domain,
1810 38 : preq->pd->cmd,
1811 38 : preq->pd->authtok,
1812 38 : preq->pd->user,
1813 38 : preq->cached_auth_failed)) {
1814 4 : preq->use_cached_auth = true;
1815 4 : pam_reply(preq);
1816 4 : return;
1817 : }
1818 :
1819 34 : if (may_do_cert_auth(pctx, preq->pd) && preq->cert_user_obj != NULL) {
1820 : /* Check if user matches certificate user */
1821 4 : cert_user = ldb_msg_find_attr_as_string(preq->cert_user_obj, SYSDB_NAME,
1822 : NULL);
1823 4 : if (cert_user == NULL) {
1824 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1825 : "Certificate user object has not name.\n");
1826 0 : preq->pd->pam_status = PAM_USER_UNKNOWN;
1827 0 : pam_reply(preq);
1828 0 : return;
1829 : }
1830 :
1831 : /* pam_check_user_search() calls pd_set_primary_name() is the search
1832 : * was successful, so pd->user contains the canonical name as well */
1833 4 : if (strcmp(cert_user, preq->pd->user) == 0) {
1834 :
1835 3 : preq->pd->pam_status = PAM_SUCCESS;
1836 :
1837 3 : if (preq->pd->cmd == SSS_PAM_PREAUTH) {
1838 1 : ret = add_pam_cert_response(preq->pd, cert_user,
1839 1 : preq->token_name);
1840 1 : if (ret != EOK) {
1841 0 : DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n");
1842 0 : preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
1843 : }
1844 : }
1845 :
1846 3 : preq->callback = pam_reply;
1847 3 : pam_reply(preq);
1848 3 : return;
1849 : } else {
1850 1 : if (preq->pd->cmd == SSS_PAM_PREAUTH) {
1851 1 : DEBUG(SSSDBG_TRACE_FUNC,
1852 : "User and certificate user do not match, " \
1853 : "continue with other authentication methods.\n");
1854 : } else {
1855 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1856 : "User and certificate user do not match.\n");
1857 0 : preq->pd->pam_status = PAM_AUTH_ERR;
1858 0 : pam_reply(preq);
1859 0 : return;
1860 : }
1861 : }
1862 : }
1863 :
1864 31 : if (!NEED_CHECK_PROVIDER(preq->domain->provider) ) {
1865 0 : preq->callback = pam_reply;
1866 0 : ret = LOCAL_pam_handler(preq);
1867 : }
1868 : else {
1869 31 : preq->callback = pam_reply;
1870 31 : ret = pam_dp_send_req(preq, SSS_CLI_SOCKET_TIMEOUT/2);
1871 31 : DEBUG(SSSDBG_CONF_SETTINGS, "pam_dp_send_req returned %d\n", ret);
1872 : }
1873 :
1874 31 : if (ret != EOK) {
1875 0 : preq->pd->pam_status = PAM_SYSTEM_ERR;
1876 0 : pam_reply(preq);
1877 : }
1878 : }
1879 :
1880 23 : static int pam_cmd_authenticate(struct cli_ctx *cctx) {
1881 23 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_authenticate\n");
1882 23 : return pam_forwarder(cctx, SSS_PAM_AUTHENTICATE);
1883 : }
1884 :
1885 1 : static int pam_cmd_setcred(struct cli_ctx *cctx) {
1886 1 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_setcred\n");
1887 1 : return pam_forwarder(cctx, SSS_PAM_SETCRED);
1888 : }
1889 :
1890 1 : static int pam_cmd_acct_mgmt(struct cli_ctx *cctx) {
1891 1 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_acct_mgmt\n");
1892 1 : return pam_forwarder(cctx, SSS_PAM_ACCT_MGMT);
1893 : }
1894 :
1895 1 : static int pam_cmd_open_session(struct cli_ctx *cctx) {
1896 1 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_open_session\n");
1897 1 : return pam_forwarder(cctx, SSS_PAM_OPEN_SESSION);
1898 : }
1899 :
1900 1 : static int pam_cmd_close_session(struct cli_ctx *cctx) {
1901 1 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_close_session\n");
1902 1 : return pam_forwarder(cctx, SSS_PAM_CLOSE_SESSION);
1903 : }
1904 :
1905 2 : static int pam_cmd_chauthtok(struct cli_ctx *cctx) {
1906 2 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_chauthtok\n");
1907 2 : return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK);
1908 : }
1909 :
1910 2 : static int pam_cmd_chauthtok_prelim(struct cli_ctx *cctx) {
1911 2 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_chauthtok_prelim\n");
1912 2 : return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK_PRELIM);
1913 : }
1914 :
1915 9 : static int pam_cmd_preauth(struct cli_ctx *cctx)
1916 : {
1917 9 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_preauth\n");
1918 9 : return pam_forwarder(cctx, SSS_PAM_PREAUTH);
1919 : }
1920 :
1921 38 : struct cli_protocol_version *register_cli_protocol_version(void)
1922 : {
1923 : static struct cli_protocol_version pam_cli_protocol_version[] = {
1924 : {3, "2009-09-14", "make cli_pid mandatory"},
1925 : {2, "2009-05-12", "new format <type><size><data>"},
1926 : {1, "2008-09-05", "initial version, \\0 terminated strings"},
1927 : {0, NULL, NULL}
1928 : };
1929 :
1930 38 : return pam_cli_protocol_version;
1931 : }
1932 :
1933 38 : struct sss_cmd_table *get_pam_cmds(void)
1934 : {
1935 : static struct sss_cmd_table sss_cmds[] = {
1936 : {SSS_GET_VERSION, sss_cmd_get_version},
1937 : {SSS_PAM_AUTHENTICATE, pam_cmd_authenticate},
1938 : {SSS_PAM_SETCRED, pam_cmd_setcred},
1939 : {SSS_PAM_ACCT_MGMT, pam_cmd_acct_mgmt},
1940 : {SSS_PAM_OPEN_SESSION, pam_cmd_open_session},
1941 : {SSS_PAM_CLOSE_SESSION, pam_cmd_close_session},
1942 : {SSS_PAM_CHAUTHTOK, pam_cmd_chauthtok},
1943 : {SSS_PAM_CHAUTHTOK_PRELIM, pam_cmd_chauthtok_prelim},
1944 : {SSS_PAM_PREAUTH, pam_cmd_preauth},
1945 : {SSS_CLI_NULL, NULL}
1946 : };
1947 :
1948 38 : return sss_cmds;
1949 : }
1950 :
1951 : errno_t
1952 5 : pam_set_last_online_auth_with_curr_token(struct sss_domain_info *domain,
1953 : const char *username,
1954 : uint64_t value)
1955 : {
1956 : TALLOC_CTX *tmp_ctx;
1957 : struct sysdb_attrs *attrs;
1958 : int ret;
1959 :
1960 5 : tmp_ctx = talloc_new(NULL);
1961 5 : if (tmp_ctx == NULL) {
1962 0 : ret = ENOMEM;
1963 0 : goto done;
1964 : }
1965 :
1966 5 : attrs = sysdb_new_attrs(tmp_ctx);
1967 5 : if (attrs == NULL) {
1968 0 : ret = ENOMEM;
1969 0 : goto done;
1970 : }
1971 :
1972 5 : ret = sysdb_attrs_add_time_t(attrs,
1973 : SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN,
1974 : value);
1975 5 : if (ret != EOK) { goto done; }
1976 :
1977 5 : ret = sysdb_set_user_attr(domain, username, attrs, SYSDB_MOD_REP);
1978 5 : if (ret != EOK) { goto done; }
1979 :
1980 : done:
1981 5 : if (ret != EOK) {
1982 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, sss_strerror(ret));
1983 : }
1984 :
1985 5 : talloc_zfree(tmp_ctx);
1986 5 : return ret;
1987 : }
1988 :
1989 : static errno_t
1990 1 : pam_null_last_online_auth_with_curr_token(struct sss_domain_info *domain,
1991 : const char *username)
1992 : {
1993 1 : return pam_set_last_online_auth_with_curr_token(domain, username, 0);
1994 : }
1995 :
1996 : static errno_t
1997 8 : pam_get_last_online_auth_with_curr_token(struct sss_domain_info *domain,
1998 : const char *name,
1999 : uint64_t *_value)
2000 : {
2001 8 : TALLOC_CTX *tmp_ctx = NULL;
2002 8 : const char *attrs[] = { SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN, NULL };
2003 : struct ldb_message *ldb_msg;
2004 : uint64_t value;
2005 : errno_t ret;
2006 :
2007 8 : if (name == NULL || *name == '\0') {
2008 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing user name.\n");
2009 0 : ret = EINVAL;
2010 0 : goto done;
2011 : }
2012 :
2013 8 : if (domain->sysdb == NULL) {
2014 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing sysdb db context.\n");
2015 0 : ret = EINVAL;
2016 0 : goto done;
2017 : }
2018 :
2019 8 : tmp_ctx = talloc_new(NULL);
2020 8 : if (tmp_ctx == NULL) {
2021 0 : ret = ENOMEM;
2022 0 : goto done;
2023 : }
2024 :
2025 8 : ret = sysdb_search_user_by_name(tmp_ctx, domain, name, attrs, &ldb_msg);
2026 8 : if (ret != EOK) {
2027 0 : DEBUG(SSSDBG_CRIT_FAILURE,
2028 : "sysdb_search_user_by_name failed [%d][%s].\n",
2029 : ret, strerror(ret));
2030 0 : goto done;
2031 : }
2032 :
2033 : /* Check offline_auth_cache_timeout */
2034 8 : value = ldb_msg_find_attr_as_uint64(ldb_msg,
2035 : SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN,
2036 : 0);
2037 8 : ret = EOK;
2038 :
2039 : done:
2040 8 : if (ret == EOK) {
2041 8 : *_value = value;
2042 : }
2043 :
2044 8 : talloc_free(tmp_ctx);
2045 8 : return ret;
2046 : }
|