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 : #define DEFAULT_PAM_VERBOSITY PAM_VERBOSITY_IMPORTANT
38 :
39 : static errno_t
40 : pam_null_last_online_auth_with_curr_token(struct sss_domain_info *domain,
41 : const char *username);
42 : static errno_t
43 : pam_get_last_online_auth_with_curr_token(struct sss_domain_info *domain,
44 : const char *name,
45 : uint64_t *_value);
46 :
47 : static void pam_reply(struct pam_auth_req *preq);
48 :
49 27 : static bool is_domain_requested(struct pam_data *pd, const char *domain_name)
50 : {
51 : int i;
52 :
53 : /* If none specific domains got requested via pam, all domains are allowed.
54 : * Which mimics the default/original behaviour.
55 : */
56 27 : if (!pd->requested_domains) {
57 27 : return true;
58 : }
59 :
60 0 : for (i = 0; pd->requested_domains[i]; i++) {
61 0 : if (strcasecmp(domain_name, pd->requested_domains[i])) {
62 0 : continue;
63 : }
64 :
65 0 : return true;
66 : }
67 :
68 0 : return false;
69 : }
70 :
71 27 : static int pd_set_primary_name(const struct ldb_message *msg,struct pam_data *pd)
72 : {
73 : const char *name;
74 :
75 27 : name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
76 27 : if (!name) {
77 0 : DEBUG(SSSDBG_CRIT_FAILURE, "A user with no name?\n");
78 0 : return EIO;
79 : }
80 :
81 27 : if (strcmp(pd->user, name)) {
82 0 : DEBUG(SSSDBG_TRACE_FUNC, "User's primary name is %s\n", name);
83 0 : talloc_free(pd->user);
84 0 : pd->user = talloc_strdup(pd, name);
85 0 : if (!pd->user) return ENOMEM;
86 : }
87 :
88 27 : return EOK;
89 : }
90 :
91 :
92 : /*=Save-Last-Login-State===================================================*/
93 :
94 2 : static errno_t set_last_login(struct pam_auth_req *preq)
95 : {
96 : struct sysdb_attrs *attrs;
97 : errno_t ret;
98 :
99 2 : attrs = sysdb_new_attrs(preq);
100 2 : if (!attrs) {
101 0 : ret = ENOMEM;
102 0 : goto fail;
103 : }
104 :
105 2 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_ONLINE_AUTH, time(NULL));
106 2 : if (ret != EOK) {
107 0 : goto fail;
108 : }
109 :
110 2 : ret = sysdb_attrs_add_time_t(attrs,
111 : SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN,
112 : time(NULL));
113 2 : if (ret != EOK) {
114 0 : goto fail;
115 : }
116 :
117 2 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_LOGIN, time(NULL));
118 2 : if (ret != EOK) {
119 0 : goto fail;
120 : }
121 :
122 2 : ret = sysdb_set_user_attr(preq->domain, preq->pd->user, attrs,
123 : SYSDB_MOD_REP);
124 2 : if (ret != EOK) {
125 0 : DEBUG(SSSDBG_OP_FAILURE, "set_last_login failed.\n");
126 0 : preq->pd->pam_status = PAM_SYSTEM_ERR;
127 0 : goto fail;
128 : } else {
129 2 : preq->pd->last_auth_saved = true;
130 : }
131 2 : preq->callback(preq);
132 :
133 2 : return EOK;
134 :
135 : fail:
136 0 : return ret;
137 : }
138 :
139 31 : static errno_t filter_responses(struct confdb_ctx *cdb,
140 : struct response_data *resp_list)
141 : {
142 : int ret;
143 : struct response_data *resp;
144 : uint32_t user_info_type;
145 : int64_t expire_date;
146 : int pam_verbosity;
147 :
148 31 : ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
149 : CONFDB_PAM_VERBOSITY, DEFAULT_PAM_VERBOSITY,
150 : &pam_verbosity);
151 31 : if (ret != EOK) {
152 0 : DEBUG(SSSDBG_CRIT_FAILURE,
153 : "Failed to read PAM verbosity, not fatal.\n");
154 0 : pam_verbosity = DEFAULT_PAM_VERBOSITY;
155 : }
156 :
157 31 : resp = resp_list;
158 71 : while(resp != NULL) {
159 9 : if (resp->type == SSS_PAM_USER_INFO) {
160 7 : if (resp->len < sizeof(uint32_t)) {
161 0 : DEBUG(SSSDBG_CRIT_FAILURE, "User info entry is too short.\n");
162 0 : return EINVAL;
163 : }
164 :
165 7 : if (pam_verbosity == PAM_VERBOSITY_NO_MESSAGES) {
166 0 : resp->do_not_send_to_client = true;
167 0 : resp = resp->next;
168 0 : continue;
169 : }
170 :
171 7 : memcpy(&user_info_type, resp->data, sizeof(uint32_t));
172 :
173 7 : resp->do_not_send_to_client = false;
174 7 : switch (user_info_type) {
175 : case SSS_PAM_USER_INFO_OFFLINE_AUTH:
176 5 : if (resp->len != sizeof(uint32_t) + sizeof(int64_t)) {
177 0 : DEBUG(SSSDBG_CRIT_FAILURE,
178 : "User info offline auth entry is "
179 : "too short.\n");
180 0 : return EINVAL;
181 : }
182 5 : memcpy(&expire_date, resp->data + sizeof(uint32_t),
183 : sizeof(int64_t));
184 10 : if ((expire_date == 0 &&
185 5 : pam_verbosity < PAM_VERBOSITY_INFO) ||
186 0 : (expire_date > 0 &&
187 0 : pam_verbosity < PAM_VERBOSITY_IMPORTANT)) {
188 5 : resp->do_not_send_to_client = true;
189 : }
190 :
191 5 : break;
192 : default:
193 2 : DEBUG(SSSDBG_TRACE_LIBS,
194 : "User info type [%d] not filtered.\n",
195 : user_info_type);
196 : }
197 2 : } else if (resp->type & SSS_SERVER_INFO) {
198 0 : resp->do_not_send_to_client = true;
199 : }
200 :
201 9 : resp = resp->next;
202 : }
203 :
204 31 : return EOK;
205 : }
206 :
207 0 : static void pam_reply_delay(struct tevent_context *ev, struct tevent_timer *te,
208 : struct timeval tv, void *pvt)
209 : {
210 : struct pam_auth_req *preq;
211 :
212 0 : DEBUG(SSSDBG_CONF_SETTINGS, "pam_reply_delay get called.\n");
213 :
214 0 : preq = talloc_get_type(pvt, struct pam_auth_req);
215 :
216 0 : pam_reply(preq);
217 0 : }
218 :
219 12 : static errno_t get_password_for_cache_auth(struct sss_auth_token *authtok,
220 : const char **password)
221 : {
222 : int ret;
223 : size_t pw_len;
224 : const char *fa2;
225 : size_t fa2_len;
226 :
227 12 : switch (sss_authtok_get_type(authtok)) {
228 : case SSS_AUTHTOK_TYPE_PASSWORD:
229 8 : ret = sss_authtok_get_password(authtok, password, NULL);
230 8 : break;
231 : case SSS_AUTHTOK_TYPE_2FA:
232 4 : ret = sss_authtok_get_2fa(authtok, password, &pw_len, &fa2, &fa2_len);
233 4 : break;
234 : default:
235 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Unsupported auth token type [%d].\n",
236 : sss_authtok_get_type(authtok));
237 0 : ret = EINVAL;
238 : }
239 12 : if (ret != EOK) {
240 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get password.\n");
241 0 : return ret;
242 : }
243 :
244 12 : return EOK;
245 : }
246 :
247 31 : static errno_t add_warning_about_expiration(struct pam_data *pd,
248 : struct confdb_ctx *cdb)
249 : {
250 : char *pam_account_expired_message;
251 : int pam_verbosity;
252 : errno_t ret;
253 :
254 31 : ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
255 : CONFDB_PAM_VERBOSITY, DEFAULT_PAM_VERBOSITY,
256 : &pam_verbosity);
257 31 : if (ret != EOK) {
258 0 : DEBUG(SSSDBG_CRIT_FAILURE,
259 : "Failed to read PAM verbosity, not fatal.\n");
260 0 : pam_verbosity = DEFAULT_PAM_VERBOSITY;
261 : }
262 :
263 31 : if (pd->pam_status != PAM_ACCT_EXPIRED ||
264 0 : ((pd->service == NULL || strcasecmp(pd->service, "sshd") != 0) ||
265 0 : pam_verbosity < PAM_VERBOSITY_INFO)) {
266 31 : return EOK;
267 : }
268 :
269 0 : ret = confdb_get_string(cdb, pd, CONFDB_PAM_CONF_ENTRY,
270 : CONFDB_PAM_ACCOUNT_EXPIRED_MESSAGE, "",
271 : &pam_account_expired_message);
272 0 : if (ret != EOK) {
273 0 : DEBUG(SSSDBG_MINOR_FAILURE,
274 : "Failed to get expiration message: %d:[%s].\n",
275 : ret, sss_strerror(ret));
276 0 : goto done;
277 : }
278 :
279 0 : ret = pamsrv_exp_warn(pd, pam_verbosity, pam_account_expired_message);
280 0 : if (ret != EOK) {
281 0 : DEBUG(SSSDBG_MINOR_FAILURE,
282 : "Failed to add password expiration warning: %d: %s\n",
283 : ret, sss_strerror(ret));
284 0 : goto done;
285 : }
286 :
287 0 : ret = EOK;
288 :
289 : done:
290 0 : return ret;
291 : }
292 :
293 :
294 : static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd);
295 : static void pam_handle_cached_login(struct pam_auth_req *preq, int ret,
296 : time_t expire_date, time_t delayed_until, bool cached_auth);
297 :
298 45 : static void pam_reply(struct pam_auth_req *preq)
299 : {
300 : struct cli_ctx *cctx;
301 : int ret;
302 : struct timeval tv;
303 : struct tevent_timer *te;
304 : struct pam_data *pd;
305 : struct pam_ctx *pctx;
306 : uint32_t user_info_type;
307 45 : time_t exp_date = -1;
308 45 : time_t delay_until = -1;
309 :
310 45 : pd = preq->pd;
311 45 : cctx = preq->cctx;
312 45 : pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
313 :
314 45 : DEBUG(SSSDBG_FUNC_DATA,
315 : "pam_reply called with result [%d]: %s.\n",
316 : pd->pam_status, pam_strerror(NULL, pd->pam_status));
317 45 : if (pd->pam_status == PAM_AUTHINFO_UNAVAIL || preq->use_cached_auth) {
318 :
319 14 : switch(pd->cmd) {
320 : case SSS_PAM_AUTHENTICATE:
321 24 : if ((preq->domain != NULL) &&
322 24 : (preq->domain->cache_credentials == true) &&
323 12 : (pd->offline_auth == false)) {
324 12 : const char *password = NULL;
325 : bool use_cached_auth;
326 :
327 : /* backup value of preq->use_cached_auth*/
328 12 : use_cached_auth = preq->use_cached_auth;
329 : /* set to false to avoid entering this branch when pam_reply()
330 : * is recursively called from pam_handle_cached_login() */
331 12 : preq->use_cached_auth = false;
332 :
333 : /* do auth with offline credentials */
334 12 : pd->offline_auth = true;
335 :
336 12 : if (preq->domain->sysdb == NULL) {
337 0 : DEBUG(SSSDBG_FATAL_FAILURE,
338 : "Fatal: Sysdb CTX not found for domain"
339 : " [%s]!\n", preq->domain->name);
340 0 : goto done;
341 : }
342 :
343 12 : ret = get_password_for_cache_auth(pd->authtok, &password);
344 12 : if (ret != EOK) {
345 0 : DEBUG(SSSDBG_FATAL_FAILURE,
346 : "get_password_and_type_for_cache_auth failed.\n");
347 0 : goto done;
348 : }
349 :
350 24 : ret = sysdb_cache_auth(preq->domain,
351 12 : pd->user, password,
352 12 : pctx->rctx->cdb, false,
353 : &exp_date, &delay_until);
354 :
355 12 : pam_handle_cached_login(preq, ret, exp_date, delay_until,
356 : use_cached_auth);
357 12 : return;
358 : }
359 0 : break;
360 : case SSS_PAM_CHAUTHTOK_PRELIM:
361 : case SSS_PAM_CHAUTHTOK:
362 2 : DEBUG(SSSDBG_FUNC_DATA,
363 : "Password change not possible while offline.\n");
364 2 : pd->pam_status = PAM_AUTHTOK_ERR;
365 2 : user_info_type = SSS_PAM_USER_INFO_OFFLINE_CHPASS;
366 2 : ret = pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t),
367 : (const uint8_t *) &user_info_type);
368 2 : if (ret != EOK) {
369 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
370 0 : goto done;
371 : }
372 2 : break;
373 : /* TODO: we need the pam session cookie here to make sure that cached
374 : * authentication was successful */
375 : case SSS_PAM_SETCRED:
376 : case SSS_PAM_ACCT_MGMT:
377 : case SSS_PAM_OPEN_SESSION:
378 : case SSS_PAM_CLOSE_SESSION:
379 0 : DEBUG(SSSDBG_OP_FAILURE,
380 : "Assuming offline authentication setting status for "
381 : "pam call %d to PAM_SUCCESS.\n", pd->cmd);
382 0 : pd->pam_status = PAM_SUCCESS;
383 0 : break;
384 : default:
385 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown PAM call [%d].\n", pd->cmd);
386 0 : pd->pam_status = PAM_MODULE_UNKNOWN;
387 : }
388 : }
389 :
390 33 : if (pd->pam_status == PAM_SUCCESS && pd->cmd == SSS_PAM_CHAUTHTOK) {
391 1 : ret = pam_null_last_online_auth_with_curr_token(preq->domain,
392 1 : pd->user);
393 1 : if (ret != EOK) {
394 0 : DEBUG(SSSDBG_CRIT_FAILURE,
395 : "sysdb_null_last_online_auth_with_curr_token failed: "
396 : "%s [%d].\n", sss_strerror(ret), ret);
397 0 : goto done;
398 : }
399 : }
400 :
401 33 : if (pd->response_delay > 0) {
402 0 : ret = gettimeofday(&tv, NULL);
403 0 : if (ret != EOK) {
404 0 : DEBUG(SSSDBG_CRIT_FAILURE, "gettimeofday failed [%d][%s].\n",
405 : errno, strerror(errno));
406 0 : goto done;
407 : }
408 0 : tv.tv_sec += pd->response_delay;
409 0 : tv.tv_usec = 0;
410 0 : pd->response_delay = 0;
411 :
412 0 : te = tevent_add_timer(cctx->ev, cctx, tv, pam_reply_delay, preq);
413 0 : if (te == NULL) {
414 0 : DEBUG(SSSDBG_CRIT_FAILURE,
415 : "Failed to add event pam_reply_delay.\n");
416 0 : goto done;
417 : }
418 :
419 0 : return;
420 : }
421 :
422 : /* If this was a successful login, save the lastLogin time */
423 49 : if (pd->cmd == SSS_PAM_AUTHENTICATE &&
424 25 : pd->pam_status == PAM_SUCCESS &&
425 18 : preq->domain->cache_credentials &&
426 13 : !pd->offline_auth &&
427 6 : !pd->last_auth_saved &&
428 4 : NEED_CHECK_PROVIDER(preq->domain->provider)) {
429 2 : ret = set_last_login(preq);
430 2 : if (ret != EOK) {
431 0 : goto done;
432 : }
433 2 : return;
434 : }
435 :
436 31 : ret = add_warning_about_expiration(pd, pctx->rctx->cdb);
437 31 : if (ret != EOK) {
438 0 : DEBUG(SSSDBG_MINOR_FAILURE, "warn_about_expiration failed: %d:[%s]\n",
439 : ret, sss_strerror(ret));
440 0 : goto done;
441 : }
442 :
443 31 : ret = filter_responses(pctx->rctx->cdb, pd->resp_list);
444 31 : if (ret != EOK) {
445 0 : DEBUG(SSSDBG_CRIT_FAILURE, "filter_responses failed, not fatal.\n");
446 : }
447 :
448 31 : if (pd->domain != NULL) {
449 28 : ret = pam_add_response(pd, SSS_PAM_DOMAIN_NAME, strlen(pd->domain)+1,
450 28 : (uint8_t *) pd->domain);
451 28 : if (ret != EOK) {
452 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
453 0 : goto done;
454 : }
455 : }
456 :
457 31 : ret = pamsrv_reply_packet(cctx->creq, pd, sss_packet_get_cmd(cctx->creq->in),
458 31 : &cctx->creq->out);
459 31 : if (ret != EOK) {
460 0 : goto done;
461 : }
462 :
463 : done:
464 31 : sss_cmd_done(cctx, preq);
465 : }
466 :
467 : static void pam_dom_forwarder(struct pam_auth_req *preq);
468 :
469 12 : static void pam_handle_cached_login(struct pam_auth_req *preq, int ret,
470 : time_t expire_date, time_t delayed_until,
471 : bool use_cached_auth)
472 : {
473 : uint32_t resp_type;
474 : size_t resp_len;
475 : uint8_t *resp;
476 : int64_t dummy;
477 :
478 12 : preq->pd->pam_status = cached_login_pam_status(ret);
479 :
480 12 : switch (preq->pd->pam_status) {
481 : case PAM_SUCCESS:
482 5 : resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH;
483 5 : resp_len = sizeof(uint32_t) + sizeof(int64_t);
484 5 : resp = talloc_size(preq->pd, resp_len);
485 5 : if (resp == NULL) {
486 0 : DEBUG(SSSDBG_CRIT_FAILURE,
487 : "talloc_size failed, cannot prepare user info.\n");
488 : } else {
489 5 : memcpy(resp, &resp_type, sizeof(uint32_t));
490 5 : dummy = (int64_t) expire_date;
491 5 : memcpy(resp+sizeof(uint32_t), &dummy, sizeof(int64_t));
492 5 : ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len,
493 : (const uint8_t *) resp);
494 5 : if (ret != EOK) {
495 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
496 : }
497 : }
498 5 : break;
499 : case PAM_PERM_DENIED:
500 1 : if (delayed_until >= 0) {
501 0 : resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH_DELAYED;
502 0 : resp_len = sizeof(uint32_t) + sizeof(int64_t);
503 0 : resp = talloc_size(preq->pd, resp_len);
504 0 : if (resp == NULL) {
505 0 : DEBUG(SSSDBG_CRIT_FAILURE,
506 : "talloc_size failed, cannot prepare user info.\n");
507 : } else {
508 0 : memcpy(resp, &resp_type, sizeof(uint32_t));
509 0 : dummy = (int64_t) delayed_until;
510 0 : memcpy(resp+sizeof(uint32_t), &dummy, sizeof(int64_t));
511 0 : ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len,
512 : (const uint8_t *) resp);
513 0 : if (ret != EOK) {
514 0 : DEBUG(SSSDBG_CRIT_FAILURE,
515 : "pam_add_response failed.\n");
516 : }
517 : }
518 : }
519 1 : break;
520 : case PAM_AUTH_ERR:
521 : /* Was this attempt to authenticate from cache? */
522 6 : if (use_cached_auth) {
523 : /* Don't try cached authentication again, try online check. */
524 0 : DEBUG(SSSDBG_FUNC_DATA,
525 : "Cached authentication failed for: %s\n",
526 : preq->pd->user);
527 0 : preq->cached_auth_failed = true;
528 0 : pam_dom_forwarder(preq);
529 0 : return;
530 : }
531 6 : break;
532 : default:
533 0 : DEBUG(SSSDBG_TRACE_LIBS,
534 : "cached login returned: %d\n", preq->pd->pam_status);
535 : }
536 :
537 12 : pam_reply(preq);
538 12 : return;
539 : }
540 :
541 : static void pam_forwarder_cb(struct tevent_req *req);
542 : static void pam_forwarder_cert_cb(struct tevent_req *req);
543 : static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
544 : const char *err_msg, void *ptr);
545 : static int pam_check_user_search(struct pam_auth_req *preq);
546 : static int pam_check_user_done(struct pam_auth_req *preq, int ret);
547 :
548 : /* TODO: we should probably return some sort of cookie that is set in the
549 : * PAM_ENVIRONMENT, so that we can save performing some calls and cache
550 : * data. */
551 :
552 :
553 31 : static int pam_auth_req_destructor(struct pam_auth_req *preq)
554 : {
555 31 : if (preq && preq->dpreq_spy) {
556 : /* If there is still a request pending, tell the spy
557 : * the client is going away
558 : */
559 0 : preq->dpreq_spy->preq = NULL;
560 : }
561 31 : return 0;
562 : }
563 :
564 31 : static bool is_uid_trusted(uint32_t uid,
565 : size_t trusted_uids_count,
566 : uid_t *trusted_uids)
567 : {
568 : size_t i;
569 :
570 : /* root is always trusted */
571 31 : if (uid == 0) {
572 31 : return true;
573 : }
574 :
575 : /* All uids are allowed */
576 0 : if (trusted_uids_count == 0) {
577 0 : return true;
578 : }
579 :
580 0 : for(i = 0; i < trusted_uids_count; i++) {
581 0 : if (trusted_uids[i] == uid) {
582 0 : return true;
583 : }
584 : }
585 :
586 0 : return false;
587 : }
588 :
589 0 : static bool is_domain_public(char *name,
590 : char **public_dom_names,
591 : size_t public_dom_names_count)
592 : {
593 : size_t i;
594 :
595 0 : for(i=0; i < public_dom_names_count; i++) {
596 0 : if (strcasecmp(name, public_dom_names[i]) == 0) {
597 0 : return true;
598 : }
599 : }
600 0 : return false;
601 : }
602 :
603 8 : static errno_t check_cert(TALLOC_CTX *mctx,
604 : struct tevent_context *ev,
605 : struct pam_ctx *pctx,
606 : struct pam_auth_req *preq,
607 : struct pam_data *pd)
608 : {
609 : int p11_child_timeout;
610 8 : const int P11_CHILD_TIMEOUT_DEFAULT = 10;
611 : errno_t ret;
612 : struct tevent_req *req;
613 :
614 8 : ret = confdb_get_int(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY,
615 : CONFDB_PAM_P11_CHILD_TIMEOUT,
616 : P11_CHILD_TIMEOUT_DEFAULT,
617 : &p11_child_timeout);
618 8 : if (ret != EOK) {
619 0 : DEBUG(SSSDBG_CRIT_FAILURE,
620 : "Failed to read p11_child_timeout from confdb: [%d]: %s\n",
621 : ret, sss_strerror(ret));
622 0 : return ret;
623 : }
624 :
625 16 : req = pam_check_cert_send(mctx, ev, pctx->p11_child_debug_fd,
626 8 : pctx->nss_db, p11_child_timeout, pd);
627 8 : if (req == NULL) {
628 0 : DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n");
629 0 : return ENOMEM;
630 : }
631 :
632 8 : tevent_req_set_callback(req, pam_forwarder_cert_cb, preq);
633 8 : return EAGAIN;
634 : }
635 :
636 31 : static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
637 : {
638 : struct sss_domain_info *dom;
639 : struct pam_auth_req *preq;
640 : struct pam_data *pd;
641 : int ret;
642 : errno_t ncret;
643 31 : struct pam_ctx *pctx =
644 31 : talloc_get_type(cctx->rctx->pvt_ctx, struct pam_ctx);
645 : struct tevent_req *req;
646 :
647 31 : preq = talloc_zero(cctx, struct pam_auth_req);
648 31 : if (!preq) {
649 0 : return ENOMEM;
650 : }
651 31 : talloc_set_destructor(preq, pam_auth_req_destructor);
652 31 : preq->cctx = cctx;
653 :
654 31 : preq->pd = create_pam_data(preq);
655 31 : if (!preq->pd) {
656 0 : talloc_free(preq);
657 0 : return ENOMEM;
658 : }
659 31 : pd = preq->pd;
660 :
661 31 : preq->is_uid_trusted = is_uid_trusted(cctx->client_euid,
662 : pctx->trusted_uids_count,
663 : pctx->trusted_uids);
664 :
665 31 : if (!preq->is_uid_trusted) {
666 0 : DEBUG(SSSDBG_MINOR_FAILURE, "uid %"PRIu32" is not trusted.\n",
667 : cctx->client_euid);
668 : }
669 :
670 :
671 31 : pd->cmd = pam_cmd;
672 31 : pd->priv = cctx->priv;
673 :
674 31 : ret = pam_forwarder_parse_data(cctx, pd);
675 31 : if (ret == EAGAIN) {
676 0 : req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, true, pd->domain);
677 0 : if (req == NULL) {
678 0 : ret = ENOMEM;
679 : } else {
680 0 : tevent_req_set_callback(req, pam_forwarder_cb, preq);
681 0 : ret = EAGAIN;
682 : }
683 0 : goto done;
684 31 : } else if (ret != EOK) {
685 1 : goto done;
686 : }
687 :
688 30 : if (pd->user != NULL) {
689 : /* now check user is valid */
690 27 : if (pd->domain) {
691 0 : preq->domain = responder_get_domain(cctx->rctx, pd->domain);
692 0 : if (!preq->domain) {
693 0 : ret = ENOENT;
694 0 : goto done;
695 : }
696 :
697 0 : ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
698 0 : preq->domain, pd->user);
699 0 : if (ncret == EEXIST) {
700 : /* User found in the negative cache */
701 0 : ret = ENOENT;
702 0 : goto done;
703 : }
704 : } else {
705 54 : for (dom = preq->cctx->rctx->domains;
706 : dom;
707 0 : dom = get_next_domain(dom, false)) {
708 27 : if (dom->fqnames) continue;
709 :
710 27 : ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
711 27 : dom, pd->user);
712 27 : if (ncret == ENOENT) {
713 : /* User not found in the negative cache
714 : * Proceed with PAM actions
715 : */
716 27 : break;
717 : }
718 :
719 : /* Try the next domain */
720 0 : DEBUG(SSSDBG_TRACE_FUNC,
721 : "User [%s@%s] filtered out (negative cache). "
722 : "Trying next domain.\n", pd->user, dom->name);
723 : }
724 :
725 27 : if (!dom) {
726 0 : ret = ENOENT;
727 0 : goto done;
728 : }
729 27 : preq->domain = dom;
730 : }
731 : }
732 :
733 :
734 30 : if (may_do_cert_auth(pctx, pd)) {
735 8 : ret = check_cert(cctx, cctx->ev, pctx, preq, pd);
736 : /* Finish here */
737 8 : goto done;
738 : }
739 :
740 :
741 22 : if (preq->domain->provider == NULL) {
742 0 : DEBUG(SSSDBG_CRIT_FAILURE,
743 : "Domain [%s] has no auth provider.\n", preq->domain->name);
744 0 : ret = EINVAL;
745 0 : goto done;
746 : }
747 :
748 22 : preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider);
749 :
750 22 : ret = pam_check_user_search(preq);
751 22 : if (ret == EOK) {
752 22 : pam_dom_forwarder(preq);
753 : }
754 :
755 : done:
756 31 : return pam_check_user_done(preq, ret);
757 : }
758 :
759 : static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req);
760 8 : static void pam_forwarder_cert_cb(struct tevent_req *req)
761 : {
762 8 : struct pam_auth_req *preq = tevent_req_callback_data(req,
763 : struct pam_auth_req);
764 8 : struct cli_ctx *cctx = preq->cctx;
765 : struct pam_data *pd;
766 8 : errno_t ret = EOK;
767 : char *cert;
768 8 : struct pam_ctx *pctx =
769 8 : talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
770 :
771 8 : ret = pam_check_cert_recv(req, preq, &cert, &preq->token_name);
772 8 : talloc_free(req);
773 8 : if (ret != EOK) {
774 0 : DEBUG(SSSDBG_OP_FAILURE, "get_cert request failed.\n");
775 0 : goto done;
776 : }
777 :
778 8 : pd = preq->pd;
779 :
780 8 : if (cert == NULL) {
781 2 : if (pd->logon_name == NULL) {
782 1 : DEBUG(SSSDBG_CRIT_FAILURE,
783 : "No certificate found and no logon name given, " \
784 : "authentication not possible.\n");;
785 1 : ret = ENOENT;
786 : } else {
787 1 : if (pd->cmd == SSS_PAM_AUTHENTICATE) {
788 0 : DEBUG(SSSDBG_CRIT_FAILURE,
789 : "No certificate returned, authentication failed.\n");
790 0 : ret = ENOENT;
791 : } else {
792 1 : ret = pam_check_user_search(preq);
793 1 : if (ret == EOK) {
794 1 : pam_dom_forwarder(preq);
795 : }
796 : }
797 :
798 : }
799 2 : goto done;
800 : }
801 :
802 :
803 6 : req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx,
804 : pctx->ncache, pctx->neg_timeout,
805 : 0, NULL, cert);
806 6 : if (req == NULL) {
807 0 : DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n");
808 0 : ret = ENOMEM;
809 0 : goto done;
810 : }
811 6 : tevent_req_set_callback(req, pam_forwarder_lookup_by_cert_done, preq);
812 6 : return;
813 :
814 : done:
815 2 : pam_check_user_done(preq, ret);
816 : }
817 :
818 6 : static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
819 : {
820 : int ret;
821 : struct ldb_result *res;
822 : struct sss_domain_info *domain;
823 6 : struct pam_auth_req *preq = tevent_req_callback_data(req,
824 : struct pam_auth_req);
825 : const char *cert_user;
826 :
827 :
828 6 : ret = cache_req_user_by_cert_recv(preq, req, &res, &domain, NULL);
829 6 : talloc_zfree(req);
830 6 : if (ret != EOK && ret != ENOENT) {
831 0 : DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert request failed.\n");
832 0 : goto done;
833 : }
834 :
835 6 : if (ret == EOK && res->count > 1) {
836 0 : DEBUG(SSSDBG_CRIT_FAILURE,
837 : "Search by certificate returned more than one result.\n");
838 0 : ret = EINVAL;
839 0 : goto done;
840 : }
841 :
842 6 : if (ret == EOK) {
843 4 : if (preq->domain == NULL) {
844 1 : preq->domain = domain;
845 : }
846 :
847 4 : preq->cert_user_obj = talloc_steal(preq, res->msgs[0]);
848 :
849 4 : if (preq->pd->logon_name == NULL) {
850 1 : cert_user = ldb_msg_find_attr_as_string(preq->cert_user_obj,
851 : SYSDB_NAME, NULL);
852 1 : if (cert_user == NULL) {
853 0 : DEBUG(SSSDBG_CRIT_FAILURE,
854 : "Certificate user object has not name.\n");
855 0 : ret = ENOENT;
856 0 : goto done;
857 : }
858 :
859 1 : DEBUG(SSSDBG_FUNC_DATA, "Found certificate user [%s].\n",
860 : cert_user);
861 :
862 1 : ret = add_pam_cert_response(preq->pd, cert_user, preq->token_name);
863 1 : if (ret != EOK) {
864 0 : DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n");
865 : }
866 :
867 1 : preq->pd->domain = talloc_strdup(preq->pd, domain->name);
868 1 : if (preq->pd->domain == NULL) {
869 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
870 0 : ret = ENOMEM;
871 0 : goto done;
872 : }
873 1 : preq->pd->pam_status = PAM_SUCCESS;
874 1 : pam_reply(preq);
875 1 : return;
876 : }
877 : } else {
878 2 : if (preq->pd->logon_name == NULL) {
879 1 : DEBUG(SSSDBG_CRIT_FAILURE,
880 : "Missing logon name and no certificate user found.\n");
881 1 : ret = ENOENT;
882 1 : goto done;
883 : }
884 : }
885 :
886 4 : ret = pam_check_user_search(preq);
887 4 : if (ret == EOK) {
888 4 : pam_dom_forwarder(preq);
889 : }
890 :
891 : done:
892 5 : pam_check_user_done(preq, ret);
893 : }
894 :
895 0 : static void pam_forwarder_cb(struct tevent_req *req)
896 : {
897 0 : struct pam_auth_req *preq = tevent_req_callback_data(req,
898 : struct pam_auth_req);
899 0 : struct cli_ctx *cctx = preq->cctx;
900 : struct pam_data *pd;
901 0 : errno_t ret = EOK;
902 0 : struct pam_ctx *pctx =
903 0 : talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
904 :
905 0 : ret = sss_dp_get_domains_recv(req);
906 0 : talloc_free(req);
907 0 : if (ret != EOK) {
908 0 : goto done;
909 : }
910 :
911 0 : pd = preq->pd;
912 :
913 0 : ret = pam_forwarder_parse_data(cctx, pd);
914 0 : if (ret == EAGAIN) {
915 0 : if (strchr(preq->pd->logon_name, '@') == NULL) {
916 0 : goto done;
917 : }
918 : /* Assuming Kerberos principal */
919 0 : preq->domain = preq->cctx->rctx->domains;
920 0 : preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider);
921 0 : preq->pd->user = talloc_strdup(preq->pd, preq->pd->logon_name);
922 0 : if (preq->pd->user == NULL) {
923 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
924 0 : ret = ENOMEM;
925 0 : goto done;
926 : }
927 0 : preq->pd->name_is_upn = true;
928 0 : preq->pd->domain = NULL;
929 0 : } else if (ret != EOK) {
930 0 : ret = EINVAL;
931 0 : goto done;
932 : }
933 :
934 0 : if (preq->pd->domain) {
935 0 : preq->domain = responder_get_domain(cctx->rctx, preq->pd->domain);
936 0 : if (preq->domain == NULL) {
937 0 : ret = ENOENT;
938 0 : goto done;
939 : }
940 : }
941 :
942 0 : if (may_do_cert_auth(pctx, pd)) {
943 0 : ret = check_cert(cctx, cctx->ev, pctx, preq, pd);
944 : /* Finish here */
945 0 : goto done;
946 : }
947 :
948 0 : ret = pam_check_user_search(preq);
949 0 : if (ret == EOK) {
950 0 : pam_dom_forwarder(preq);
951 : }
952 :
953 : done:
954 0 : pam_check_user_done(preq, ret);
955 0 : }
956 :
957 : static void pam_dp_send_acct_req_done(struct tevent_req *req);
958 27 : static int pam_check_user_search(struct pam_auth_req *preq)
959 : {
960 27 : struct sss_domain_info *dom = preq->domain;
961 27 : char *name = NULL;
962 : time_t cacheExpire;
963 : int ret;
964 : struct tevent_req *dpreq;
965 : struct dp_callback_ctx *cb_ctx;
966 27 : struct pam_ctx *pctx =
967 27 : talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
968 : static const char *user_attrs[] = SYSDB_PW_ATTRS;
969 : struct ldb_message *msg;
970 : struct ldb_result *res;
971 :
972 27 : while (dom) {
973 : /* if it is a domainless search, skip domains that require fully
974 : * qualified names instead */
975 54 : while (dom && !preq->pd->domain && !preq->pd->name_is_upn
976 27 : && dom->fqnames) {
977 0 : dom = get_next_domain(dom, false);
978 : }
979 :
980 27 : if (!dom) break;
981 :
982 27 : if (dom != preq->domain) {
983 : /* make sure we reset the check_provider flag when we check
984 : * a new domain */
985 0 : preq->check_provider = NEED_CHECK_PROVIDER(dom->provider);
986 : }
987 :
988 : /* make sure to update the preq if we changed domain */
989 27 : preq->domain = dom;
990 :
991 27 : talloc_free(name);
992 27 : name = sss_get_cased_name(preq, preq->pd->user,
993 27 : dom->case_sensitive);
994 27 : if (!name) {
995 0 : return ENOMEM;
996 : }
997 :
998 27 : name = sss_reverse_replace_space(preq, name,
999 27 : pctx->rctx->override_space);
1000 27 : if (name == NULL) {
1001 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1002 : "sss_reverse_replace_space failed\n");
1003 0 : return ENOMEM;
1004 : }
1005 :
1006 : /* Refresh the user's cache entry on any PAM query
1007 : * We put a timeout in the client context so that we limit
1008 : * the number of updates within a reasonable timeout
1009 : */
1010 27 : if (preq->check_provider) {
1011 22 : ret = pam_initgr_check_timeout(pctx->id_table,
1012 22 : preq->pd->logon_name);
1013 22 : if (ret != EOK
1014 0 : && ret != ENOENT) {
1015 0 : DEBUG(SSSDBG_OP_FAILURE,
1016 : "Could not look up initgroup timout\n");
1017 0 : return EIO;
1018 22 : } else if (ret == ENOENT) {
1019 : /* Call provider first */
1020 0 : break;
1021 : }
1022 : /* Entry is still valid, get it from the sysdb */
1023 : }
1024 :
1025 27 : DEBUG(SSSDBG_CONF_SETTINGS,
1026 : "Requesting info for [%s@%s]\n", name, dom->name);
1027 :
1028 27 : if (dom->sysdb == NULL) {
1029 0 : DEBUG(SSSDBG_FATAL_FAILURE,
1030 : "Fatal: Sysdb CTX not found for this domain!\n");
1031 0 : preq->pd->pam_status = PAM_SYSTEM_ERR;
1032 0 : return EFAULT;
1033 : }
1034 :
1035 27 : if (preq->pd->name_is_upn) {
1036 0 : ret = sysdb_search_user_by_upn(preq, dom, name, user_attrs, &msg);
1037 : } else {
1038 27 : ret = sysdb_getpwnam_with_views(preq, dom, name, &res);
1039 27 : if (res->count > 1) {
1040 0 : DEBUG(SSSDBG_FATAL_FAILURE,
1041 : "getpwnam call returned more than one result !?!\n");
1042 0 : sss_log(SSS_LOG_ERR,
1043 : "More users have the same name [%s@%s] in SSSD cache. "
1044 : "SSSD will not work correctly.\n",
1045 : name, dom->name);
1046 0 : return ENOENT;
1047 27 : } else if (res->count == 0) {
1048 0 : ret = ENOENT;
1049 : } else {
1050 27 : msg = res->msgs[0];
1051 : }
1052 : }
1053 27 : if (ret != EOK && ret != ENOENT) {
1054 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1055 : "Failed to make request to our cache!\n");
1056 0 : return EIO;
1057 : }
1058 :
1059 27 : if (ret == ENOENT) {
1060 0 : if (preq->check_provider == false) {
1061 : /* set negative cache only if not result of cache check */
1062 0 : ret = sss_ncache_set_user(pctx->ncache, false, dom, name);
1063 0 : if (ret != EOK) {
1064 : /* Should not be fatal, just slower next time */
1065 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1066 : "Cannot set ncache for [%s@%s]\n", name,
1067 : dom->name);
1068 : }
1069 : }
1070 :
1071 : /* if a multidomain search, try with next */
1072 0 : if (!preq->pd->domain) {
1073 0 : dom = get_next_domain(dom, false);
1074 0 : continue;
1075 : }
1076 :
1077 0 : DEBUG(SSSDBG_OP_FAILURE, "No results for getpwnam call\n");
1078 :
1079 : /* TODO: store negative cache ? */
1080 :
1081 0 : return ENOENT;
1082 : }
1083 :
1084 : /* One result found */
1085 :
1086 : /* if we need to check the remote account go on */
1087 27 : if (preq->check_provider) {
1088 22 : cacheExpire = ldb_msg_find_attr_as_uint64(msg,
1089 : SYSDB_CACHE_EXPIRE, 0);
1090 22 : if (cacheExpire < time(NULL)) {
1091 0 : break;
1092 : }
1093 : }
1094 :
1095 27 : DEBUG(SSSDBG_TRACE_FUNC,
1096 : "Returning info for user [%s@%s]\n", name, dom->name);
1097 :
1098 : /* We might have searched by alias. Pass on the primary name */
1099 27 : ret = pd_set_primary_name(msg, preq->pd);
1100 27 : if (ret != EOK) {
1101 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not canonicalize username\n");
1102 0 : return ret;
1103 : }
1104 :
1105 27 : return EOK;
1106 : }
1107 :
1108 0 : if (!dom) {
1109 : /* Ensure that we don't try to check a provider without a domain,
1110 : * since this will cause a NULL-dereference below.
1111 : */
1112 0 : preq->check_provider = false;
1113 : }
1114 :
1115 0 : if (preq->check_provider) {
1116 :
1117 : /* dont loop forever :-) */
1118 0 : preq->check_provider = false;
1119 :
1120 0 : dpreq = sss_dp_get_account_send(preq, preq->cctx->rctx,
1121 : dom, false, SSS_DP_INITGROUPS, name, 0,
1122 0 : preq->pd->name_is_upn ? EXTRA_NAME_IS_UPN : NULL);
1123 0 : if (!dpreq) {
1124 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1125 : "Out of memory sending data provider request\n");
1126 0 : return ENOMEM;
1127 : }
1128 :
1129 0 : cb_ctx = talloc_zero(preq, struct dp_callback_ctx);
1130 0 : if(!cb_ctx) {
1131 0 : talloc_zfree(dpreq);
1132 0 : return ENOMEM;
1133 : }
1134 :
1135 0 : cb_ctx->callback = pam_check_user_dp_callback;
1136 0 : cb_ctx->ptr = preq;
1137 0 : cb_ctx->cctx = preq->cctx;
1138 0 : cb_ctx->mem_ctx = preq;
1139 :
1140 0 : tevent_req_set_callback(dpreq, pam_dp_send_acct_req_done, cb_ctx);
1141 :
1142 : /* tell caller we are in an async call */
1143 0 : return EAGAIN;
1144 : }
1145 :
1146 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1147 : "No matching domain found for [%s], fail!\n", preq->pd->user);
1148 0 : return ENOENT;
1149 : }
1150 :
1151 0 : static void pam_dp_send_acct_req_done(struct tevent_req *req)
1152 : {
1153 0 : struct dp_callback_ctx *cb_ctx =
1154 0 : tevent_req_callback_data(req, struct dp_callback_ctx);
1155 :
1156 : errno_t ret;
1157 : dbus_uint16_t err_maj;
1158 : dbus_uint32_t err_min;
1159 : char *err_msg;
1160 :
1161 0 : ret = sss_dp_get_account_recv(cb_ctx->mem_ctx, req,
1162 : &err_maj, &err_min,
1163 : &err_msg);
1164 0 : talloc_zfree(req);
1165 0 : if (ret != EOK) {
1166 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1167 : "Fatal error, killing connection!\n");
1168 0 : talloc_free(cb_ctx->cctx);
1169 0 : return;
1170 : }
1171 :
1172 0 : cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
1173 : }
1174 :
1175 38 : static int pam_check_user_done(struct pam_auth_req *preq, int ret)
1176 : {
1177 38 : switch (ret) {
1178 : case EOK:
1179 27 : break;
1180 :
1181 : case EAGAIN:
1182 : /* performing async request, just return */
1183 8 : break;
1184 :
1185 : case ENOENT:
1186 2 : preq->pd->pam_status = PAM_USER_UNKNOWN;
1187 2 : pam_reply(preq);
1188 2 : break;
1189 :
1190 : case ERR_NO_CREDS:
1191 1 : preq->pd->pam_status = PAM_CRED_INSUFFICIENT;
1192 1 : pam_reply(preq);
1193 1 : break;
1194 :
1195 : default:
1196 0 : preq->pd->pam_status = PAM_SYSTEM_ERR;
1197 0 : pam_reply(preq);
1198 0 : break;
1199 : }
1200 :
1201 38 : return EOK;
1202 : }
1203 :
1204 0 : static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
1205 : const char *err_msg, void *ptr)
1206 : {
1207 0 : struct pam_auth_req *preq = talloc_get_type(ptr, struct pam_auth_req);
1208 : int ret;
1209 0 : struct pam_ctx *pctx =
1210 0 : talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
1211 :
1212 0 : if (err_maj) {
1213 0 : DEBUG(SSSDBG_OP_FAILURE,
1214 : "Unable to get information from Data Provider\n"
1215 : "Error: %u, %u, %s\n",
1216 : (unsigned int)err_maj, (unsigned int)err_min, err_msg);
1217 : }
1218 :
1219 0 : ret = pam_check_user_search(preq);
1220 0 : if (ret == EOK) {
1221 : /* Make sure we don't go to the ID provider too often */
1222 0 : ret = pam_initgr_cache_set(pctx->rctx->ev, pctx->id_table,
1223 0 : preq->pd->logon_name, pctx->id_timeout);
1224 0 : if (ret != EOK) {
1225 0 : DEBUG(SSSDBG_OP_FAILURE,
1226 : "Could not save initgr timestamp. "
1227 : "Proceeding with PAM actions\n");
1228 : /* This is non-fatal, we'll just end up going to the
1229 : * data provider again next time.
1230 : */
1231 : }
1232 :
1233 0 : pam_dom_forwarder(preq);
1234 : }
1235 :
1236 0 : ret = pam_check_user_done(preq, ret);
1237 :
1238 0 : if (ret) {
1239 0 : preq->pd->pam_status = PAM_SYSTEM_ERR;
1240 0 : pam_reply(preq);
1241 : }
1242 0 : }
1243 :
1244 0 : static errno_t pam_is_last_online_login_fresh(struct sss_domain_info *domain,
1245 : const char* user,
1246 : struct confdb_ctx *cdb,
1247 : int cached_auth_timeout,
1248 : bool *_result)
1249 : {
1250 : errno_t ret;
1251 : bool result;
1252 : uint64_t last_login;
1253 :
1254 0 : ret = pam_get_last_online_auth_with_curr_token(domain, user, &last_login);
1255 0 : if (ret != EOK) {
1256 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1257 : "sysdb_get_last_online_auth_with_curr_token failed: %s:[%d]\n",
1258 : sss_strerror(ret), ret);
1259 0 : goto done;
1260 : }
1261 :
1262 0 : result = time(NULL) < (last_login + cached_auth_timeout);
1263 0 : ret = EOK;
1264 :
1265 : done:
1266 0 : if (ret == EOK) {
1267 0 : *_result = result;
1268 : }
1269 0 : return ret;
1270 : }
1271 :
1272 0 : static bool pam_is_cmd_cachable(int cmd)
1273 : {
1274 : bool is_cachable;
1275 :
1276 0 : switch(cmd) {
1277 : case SSS_PAM_AUTHENTICATE:
1278 0 : is_cachable = true;
1279 0 : break;
1280 : default:
1281 0 : is_cachable = false;
1282 : }
1283 :
1284 0 : return is_cachable;
1285 : }
1286 :
1287 0 : static bool pam_is_authtok_cachable(struct sss_auth_token *authtok)
1288 : {
1289 : enum sss_authtok_type type;
1290 0 : bool cachable = false;
1291 :
1292 0 : type = sss_authtok_get_type(authtok);
1293 0 : if (type == SSS_AUTHTOK_TYPE_PASSWORD) {
1294 0 : cachable = true;
1295 : } else {
1296 0 : DEBUG(SSSDBG_TRACE_LIBS, "Authentication token can't be cached\n");
1297 : }
1298 :
1299 0 : return cachable;
1300 : }
1301 :
1302 27 : static bool pam_can_user_cache_auth(struct confdb_ctx *cdb,
1303 : struct sss_domain_info *domain,
1304 : int pam_cmd,
1305 : struct sss_auth_token *authtok,
1306 : const char* user,
1307 : bool cached_auth_failed)
1308 : {
1309 : errno_t ret;
1310 27 : bool result = false;
1311 :
1312 27 : if (!cached_auth_failed /* don't try cached auth again */
1313 27 : && domain->cache_credentials
1314 27 : && domain->cached_auth_timeout > 0
1315 0 : && pam_is_authtok_cachable(authtok)
1316 0 : && pam_is_cmd_cachable(pam_cmd)) {
1317 :
1318 0 : ret = pam_is_last_online_login_fresh(domain, user, cdb,
1319 0 : domain->cached_auth_timeout,
1320 : &result);
1321 0 : if (ret != EOK) {
1322 : /* non-critical, consider fail as 'non-fresh value' */
1323 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1324 : "pam_is_last_online_login_fresh failed: %s:[%d]\n",
1325 : sss_strerror(ret), ret);
1326 : }
1327 : }
1328 :
1329 27 : return result;
1330 : }
1331 :
1332 27 : static void pam_dom_forwarder(struct pam_auth_req *preq)
1333 : {
1334 : int ret;
1335 27 : struct pam_ctx *pctx =
1336 27 : talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
1337 : const char *cert_user;
1338 :
1339 27 : if (!preq->pd->domain) {
1340 27 : preq->pd->domain = preq->domain->name;
1341 : }
1342 :
1343 : /* Untrusted users can access only public domains. */
1344 27 : if (!preq->is_uid_trusted &&
1345 0 : !is_domain_public(preq->pd->domain, pctx->public_domains,
1346 0 : pctx->public_domains_count)) {
1347 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1348 : "Untrusted user %"PRIu32" cannot access non-public domain %s.\n",
1349 : preq->cctx->client_euid, preq->pd->domain);
1350 0 : preq->pd->pam_status = PAM_PERM_DENIED;
1351 0 : pam_reply(preq);
1352 0 : return;
1353 : }
1354 :
1355 : /* skip this domain if not requested and the user is trusted
1356 : * as untrusted users can't request a domain */
1357 54 : if (preq->is_uid_trusted &&
1358 27 : !is_domain_requested(preq->pd, preq->pd->domain)) {
1359 0 : preq->pd->pam_status = PAM_USER_UNKNOWN;
1360 0 : pam_reply(preq);
1361 0 : return;
1362 : }
1363 :
1364 81 : if (pam_can_user_cache_auth(pctx->rctx->cdb,
1365 : preq->domain,
1366 27 : preq->pd->cmd,
1367 27 : preq->pd->authtok,
1368 27 : preq->pd->user,
1369 27 : preq->cached_auth_failed)) {
1370 0 : preq->use_cached_auth = true;
1371 0 : pam_reply(preq);
1372 0 : return;
1373 : }
1374 :
1375 27 : if (may_do_cert_auth(pctx, preq->pd) && preq->cert_user_obj != NULL) {
1376 : /* Check if user matches certificate user */
1377 3 : cert_user = ldb_msg_find_attr_as_string(preq->cert_user_obj, SYSDB_NAME,
1378 : NULL);
1379 3 : if (cert_user == NULL) {
1380 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1381 : "Certificate user object has not name.\n");
1382 0 : preq->pd->pam_status = PAM_USER_UNKNOWN;
1383 0 : pam_reply(preq);
1384 0 : return;
1385 : }
1386 :
1387 : /* pam_check_user_search() calls pd_set_primary_name() is the search
1388 : * was successful, so pd->user contains the canonical name as well */
1389 3 : if (strcmp(cert_user, preq->pd->user) == 0) {
1390 :
1391 2 : preq->pd->pam_status = PAM_SUCCESS;
1392 :
1393 2 : if (preq->pd->cmd == SSS_PAM_PREAUTH) {
1394 1 : ret = add_pam_cert_response(preq->pd, cert_user,
1395 1 : preq->token_name);
1396 1 : if (ret != EOK) {
1397 0 : DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n");
1398 0 : preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
1399 : }
1400 : }
1401 :
1402 2 : preq->callback = pam_reply;
1403 2 : pam_reply(preq);
1404 2 : return;
1405 : } else {
1406 1 : if (preq->pd->cmd == SSS_PAM_PREAUTH) {
1407 1 : DEBUG(SSSDBG_TRACE_FUNC,
1408 : "User and certificate user do not match, " \
1409 : "continue with other authentication methods.\n");
1410 : } else {
1411 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1412 : "User and certificate user do not match.\n");
1413 0 : preq->pd->pam_status = PAM_AUTH_ERR;
1414 0 : pam_reply(preq);
1415 0 : return;
1416 : }
1417 : }
1418 : }
1419 :
1420 25 : if (!NEED_CHECK_PROVIDER(preq->domain->provider) ) {
1421 0 : preq->callback = pam_reply;
1422 0 : ret = LOCAL_pam_handler(preq);
1423 : }
1424 : else {
1425 25 : preq->callback = pam_reply;
1426 25 : ret = pam_dp_send_req(preq, SSS_CLI_SOCKET_TIMEOUT/2);
1427 25 : DEBUG(SSSDBG_CONF_SETTINGS, "pam_dp_send_req returned %d\n", ret);
1428 : }
1429 :
1430 25 : if (ret != EOK) {
1431 0 : preq->pd->pam_status = PAM_SYSTEM_ERR;
1432 0 : pam_reply(preq);
1433 : }
1434 : }
1435 :
1436 14 : static int pam_cmd_authenticate(struct cli_ctx *cctx) {
1437 14 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_authenticate\n");
1438 14 : return pam_forwarder(cctx, SSS_PAM_AUTHENTICATE);
1439 : }
1440 :
1441 1 : static int pam_cmd_setcred(struct cli_ctx *cctx) {
1442 1 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_setcred\n");
1443 1 : return pam_forwarder(cctx, SSS_PAM_SETCRED);
1444 : }
1445 :
1446 1 : static int pam_cmd_acct_mgmt(struct cli_ctx *cctx) {
1447 1 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_acct_mgmt\n");
1448 1 : return pam_forwarder(cctx, SSS_PAM_ACCT_MGMT);
1449 : }
1450 :
1451 1 : static int pam_cmd_open_session(struct cli_ctx *cctx) {
1452 1 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_open_session\n");
1453 1 : return pam_forwarder(cctx, SSS_PAM_OPEN_SESSION);
1454 : }
1455 :
1456 1 : static int pam_cmd_close_session(struct cli_ctx *cctx) {
1457 1 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_close_session\n");
1458 1 : return pam_forwarder(cctx, SSS_PAM_CLOSE_SESSION);
1459 : }
1460 :
1461 2 : static int pam_cmd_chauthtok(struct cli_ctx *cctx) {
1462 2 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_chauthtok\n");
1463 2 : return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK);
1464 : }
1465 :
1466 2 : static int pam_cmd_chauthtok_prelim(struct cli_ctx *cctx) {
1467 2 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_chauthtok_prelim\n");
1468 2 : return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK_PRELIM);
1469 : }
1470 :
1471 9 : static int pam_cmd_preauth(struct cli_ctx *cctx)
1472 : {
1473 9 : DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_preauth\n");
1474 9 : return pam_forwarder(cctx, SSS_PAM_PREAUTH);
1475 : }
1476 :
1477 31 : struct cli_protocol_version *register_cli_protocol_version(void)
1478 : {
1479 : static struct cli_protocol_version pam_cli_protocol_version[] = {
1480 : {3, "2009-09-14", "make cli_pid mandatory"},
1481 : {2, "2009-05-12", "new format <type><size><data>"},
1482 : {1, "2008-09-05", "initial version, \\0 terminated strings"},
1483 : {0, NULL, NULL}
1484 : };
1485 :
1486 31 : return pam_cli_protocol_version;
1487 : }
1488 :
1489 31 : struct sss_cmd_table *get_pam_cmds(void)
1490 : {
1491 : static struct sss_cmd_table sss_cmds[] = {
1492 : {SSS_GET_VERSION, sss_cmd_get_version},
1493 : {SSS_PAM_AUTHENTICATE, pam_cmd_authenticate},
1494 : {SSS_PAM_SETCRED, pam_cmd_setcred},
1495 : {SSS_PAM_ACCT_MGMT, pam_cmd_acct_mgmt},
1496 : {SSS_PAM_OPEN_SESSION, pam_cmd_open_session},
1497 : {SSS_PAM_CLOSE_SESSION, pam_cmd_close_session},
1498 : {SSS_PAM_CHAUTHTOK, pam_cmd_chauthtok},
1499 : {SSS_PAM_CHAUTHTOK_PRELIM, pam_cmd_chauthtok_prelim},
1500 : {SSS_PAM_PREAUTH, pam_cmd_preauth},
1501 : {SSS_CLI_NULL, NULL}
1502 : };
1503 :
1504 31 : return sss_cmds;
1505 : }
1506 :
1507 : static errno_t
1508 1 : pam_set_last_online_auth_with_curr_token(struct sss_domain_info *domain,
1509 : const char *username,
1510 : uint64_t value)
1511 : {
1512 : TALLOC_CTX *tmp_ctx;
1513 : struct sysdb_attrs *attrs;
1514 : int ret;
1515 :
1516 1 : tmp_ctx = talloc_new(NULL);
1517 1 : if (tmp_ctx == NULL) {
1518 0 : ret = ENOMEM;
1519 0 : goto done;
1520 : }
1521 :
1522 1 : attrs = sysdb_new_attrs(tmp_ctx);
1523 1 : if (attrs == NULL) {
1524 0 : ret = ENOMEM;
1525 0 : goto done;
1526 : }
1527 :
1528 1 : ret = sysdb_attrs_add_time_t(attrs,
1529 : SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN,
1530 : value);
1531 1 : if (ret != EOK) { goto done; }
1532 :
1533 1 : ret = sysdb_set_user_attr(domain, username, attrs, SYSDB_MOD_REP);
1534 1 : if (ret != EOK) { goto done; }
1535 :
1536 : done:
1537 1 : if (ret != EOK) {
1538 0 : DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, sss_strerror(ret));
1539 : }
1540 :
1541 1 : talloc_zfree(tmp_ctx);
1542 1 : return ret;
1543 : }
1544 :
1545 : static errno_t
1546 1 : pam_null_last_online_auth_with_curr_token(struct sss_domain_info *domain,
1547 : const char *username)
1548 : {
1549 1 : return pam_set_last_online_auth_with_curr_token(domain, username, 0);
1550 : }
1551 :
1552 : static errno_t
1553 0 : pam_get_last_online_auth_with_curr_token(struct sss_domain_info *domain,
1554 : const char *name,
1555 : uint64_t *_value)
1556 : {
1557 0 : TALLOC_CTX *tmp_ctx = NULL;
1558 0 : const char *attrs[] = { SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN, NULL };
1559 : struct ldb_message *ldb_msg;
1560 : uint64_t value;
1561 : errno_t ret;
1562 :
1563 0 : if (name == NULL || *name == '\0') {
1564 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing user name.\n");
1565 0 : ret = EINVAL;
1566 0 : goto done;
1567 : }
1568 :
1569 0 : if (domain->sysdb == NULL) {
1570 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing sysdb db context.\n");
1571 0 : ret = EINVAL;
1572 0 : goto done;
1573 : }
1574 :
1575 0 : tmp_ctx = talloc_new(NULL);
1576 0 : if (tmp_ctx == NULL) {
1577 0 : ret = ENOMEM;
1578 0 : goto done;
1579 : }
1580 :
1581 0 : ret = sysdb_search_user_by_name(tmp_ctx, domain, name, attrs, &ldb_msg);
1582 0 : if (ret != EOK) {
1583 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1584 : "sysdb_search_user_by_name failed [%d][%s].\n",
1585 : ret, strerror(ret));
1586 0 : goto done;
1587 : }
1588 :
1589 : /* Check offline_auth_cache_timeout */
1590 0 : value = ldb_msg_find_attr_as_uint64(ldb_msg,
1591 : SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN,
1592 : 0);
1593 0 : ret = EOK;
1594 :
1595 : done:
1596 0 : if (ret == EOK) {
1597 0 : *_value = value;
1598 : }
1599 :
1600 0 : talloc_free(tmp_ctx);
1601 0 : return ret;
1602 : }
|