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 "db/sysdb.h"
26 #include "confdb/confdb.h"
27 #include "responder/common/responder_packet.h"
28 #include "responder/common/responder.h"
29 #include "providers/data_provider.h"
30 #include "responder/pam/pamsrv.h"
31 #include "db/sysdb.h"
32
33 static void pam_reply(struct pam_auth_req *preq);
34
35 static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok, uint8_t *body, size_t blen, size_t *c) {
36 uint32_t data_size;
37
38 if (blen-(*c) < 2*sizeof(uint32_t)) return EINVAL;
39
40 memcpy(&data_size, &body[*c], sizeof(uint32_t));
41 *c += sizeof(uint32_t);
42 if (data_size < sizeof(uint32_t) || (*c)+(data_size) > blen) return EINVAL;
43 *size = data_size - sizeof(uint32_t);
44
45 memcpy(type, &body[*c], sizeof(uint32_t));
46 *c += sizeof(uint32_t);
47
48 *tok = body+(*c);
49
50 *c += (*size);
51
52 return EOK;
53 }
54
55 static int extract_string(char **var, uint8_t *body, size_t blen, size_t *c) {
56 uint32_t size;
57 uint8_t *str;
58
59 if (blen-(*c) < sizeof(uint32_t)+1) return EINVAL;
60
61 memcpy(&size, &body[*c], sizeof(uint32_t));
62 *c += sizeof(uint32_t);
63 if (*c+size > blen) return EINVAL;
64
65 str = body+(*c);
66
67 if (str[size-1]!='\0') return EINVAL;
68
69 *c += size;
70
71 *var = (char *) str;
72
73 return EOK;
74 }
75
76 static int extract_uint32_t(uint32_t *var, uint8_t *body, size_t blen, size_t *c) {
77 uint32_t size;
78
79 if (blen-(*c) < 2*sizeof(uint32_t)) return EINVAL;
80
81 memcpy(&size, &body[*c], sizeof(uint32_t));
82 *c += sizeof(uint32_t);
83
84 memcpy(var, &body[*c], sizeof(uint32_t));
85 *c += sizeof(uint32_t);
86
87 return EOK;
88 }
89
90 static int pam_parse_in_data_v2(struct sss_names_ctx *snctx,
91 struct pam_data *pd,
92 uint8_t *body, size_t blen)
93 {
94 size_t c;
95 uint32_t type;
96 uint32_t size;
97 char *pam_user;
98 int ret;
99 uint32_t terminator = SSS_END_OF_PAM_REQUEST;
100
101 if (blen < 4*sizeof(uint32_t)+2 ||
102 ((uint32_t *)body)[0] != SSS_START_OF_PAM_REQUEST ||
103 memcmp(&body[blen - sizeof(uint32_t)], &terminator, sizeof(uint32_t)) != 0) {
104 DEBUG(1, ("Received data is invalid.\n"));
105 return EINVAL;
106 }
107
108 c = sizeof(uint32_t);
109 do {
110 memcpy(&type, &body[c], sizeof(uint32_t));
111 c += sizeof(uint32_t);
112 if (c > blen) return EINVAL;
113
114 switch(type) {
115 case SSS_PAM_ITEM_USER:
116 ret = extract_string(&pam_user, body, blen, &c);
117 if (ret != EOK) return ret;
118
119 ret = sss_parse_name(pd, snctx, pam_user,
120 &pd->domain, &pd->user);
121 if (ret != EOK) return ret;
122 break;
123 case SSS_PAM_ITEM_SERVICE:
124 ret = extract_string(&pd->service, body, blen, &c);
125 if (ret != EOK) return ret;
126 break;
127 case SSS_PAM_ITEM_TTY:
128 ret = extract_string(&pd->tty, body, blen, &c);
129 if (ret != EOK) return ret;
130 break;
131 case SSS_PAM_ITEM_RUSER:
132 ret = extract_string(&pd->ruser, body, blen, &c);
133 if (ret != EOK) return ret;
134 break;
135 case SSS_PAM_ITEM_RHOST:
136 ret = extract_string(&pd->rhost, body, blen, &c);
137 if (ret != EOK) return ret;
138 break;
139 case SSS_PAM_ITEM_CLI_PID:
140 ret = extract_uint32_t(&pd->cli_pid,
141 body, blen, &c);
142 if (ret != EOK) return ret;
143 break;
144 case SSS_PAM_ITEM_AUTHTOK:
145 ret = extract_authtok(&pd->authtok_type, &pd->authtok_size,
146 &pd->authtok, body, blen, &c);
147 if (ret != EOK) return ret;
148 break;
149 case SSS_PAM_ITEM_NEWAUTHTOK:
150 ret = extract_authtok(&pd->newauthtok_type,
151 &pd->newauthtok_size,
152 &pd->newauthtok, body, blen, &c);
153 if (ret != EOK) return ret;
154 break;
155 case SSS_END_OF_PAM_REQUEST:
156 if (c != blen) return EINVAL;
157 break;
158 default:
159 DEBUG(1,("Ignoring unknown data type [%d].\n", type));
160 size = ((uint32_t *)&body[c])[0];
161 c += size+sizeof(uint32_t);
162 }
163 } while(c < blen);
164
165 if (pd->user == NULL || *pd->user == '\0') return EINVAL;
166
167 DEBUG_PAM_DATA(4, pd);
168
169 return EOK;
170
171 }
172
173 static int pam_parse_in_data_v3(struct sss_names_ctx *snctx,
174 struct pam_data *pd,
175 uint8_t *body, size_t blen)
176 {
177 int ret;
178
179 ret = pam_parse_in_data_v2(snctx, pd, body, blen);
180 if (ret != EOK) {
181 DEBUG(1, ("pam_parse_in_data_v2 failed.\n"));
182 return ret;
183 }
184
185 if (pd->cli_pid == 0) {
186 DEBUG(1, ("Missing client PID.\n"));
187 return EINVAL;
188 }
189
190 return EOK;
191 }
192
193 static int pam_parse_in_data(struct sss_names_ctx *snctx,
194 struct pam_data *pd,
195 uint8_t *body, size_t blen)
196 {
197 int start;
198 int end;
199 int last;
200 int ret;
201
202 last = blen - 1;
203 end = 0;
204
205 /* user name */
206 for (start = end; end < last; end++) if (body[end] == '\0') break;
207 if (body[end++] != '\0') return EINVAL;
208
209 ret = sss_parse_name(pd, snctx, (char *)&body[start], &pd->domain, &pd->user);
210 if (ret != EOK) return ret;
211
212 for (start = end; end < last; end++) if (body[end] == '\0') break;
213 if (body[end++] != '\0') return EINVAL;
214 pd->service = (char *) &body[start];
215
216 for (start = end; end < last; end++) if (body[end] == '\0') break;
217 if (body[end++] != '\0') return EINVAL;
218 pd->tty = (char *) &body[start];
219
220 for (start = end; end < last; end++) if (body[end] == '\0') break;
221 if (body[end++] != '\0') return EINVAL;
222 pd->ruser = (char *) &body[start];
223
224 for (start = end; end < last; end++) if (body[end] == '\0') break;
225 if (body[end++] != '\0') return EINVAL;
226 pd->rhost = (char *) &body[start];
227
228 start = end;
229 pd->authtok_type = (int) body[start];
230
231 start += sizeof(uint32_t);
232 pd->authtok_size = (int) body[start];
233
234 start += sizeof(uint32_t);
235 end = start + pd->authtok_size;
236 if (pd->authtok_size == 0) {
237 pd->authtok = NULL;
238 } else {
239 if (end <= blen) {
240 pd->authtok = (uint8_t *) &body[start];
241 } else {
242 DEBUG(1, ("Invalid authtok size: %d\n", pd->authtok_size));
243 return EINVAL;
244 }
245 }
246
247 start = end;
248 pd->newauthtok_type = (int) body[start];
249
250 start += sizeof(uint32_t);
251 pd->newauthtok_size = (int) body[start];
252
253 start += sizeof(uint32_t);
254 end = start + pd->newauthtok_size;
255
256 if (pd->newauthtok_size == 0) {
257 pd->newauthtok = NULL;
258 } else {
259 if (end <= blen) {
260 pd->newauthtok = (uint8_t *) &body[start];
261 } else {
262 DEBUG(1, ("Invalid newauthtok size: %d\n", pd->newauthtok_size));
263 return EINVAL;
264 }
265 }
266
267 DEBUG_PAM_DATA(4, pd);
268
269 return EOK;
270 }
271
272 /*=Save-Last-Login-State===================================================*/
273
274 struct set_last_login_state {
275 struct tevent_context *ev;
276 struct sysdb_ctx *dbctx;
277
278 struct sss_domain_info *dom;
279 const char *username;
280 struct sysdb_attrs *attrs;
281
282 struct sysdb_handle *handle;
283
284 struct ldb_result *res;
285 };
286
287 static void set_last_login_trans_done(struct tevent_req *subreq);
288 static void set_last_login_attrs_done(struct tevent_req *subreq);
289 static void set_last_login_done(struct tevent_req *subreq);
290
291 static struct tevent_req *set_last_login_send(TALLOC_CTX *memctx,
292 struct tevent_context *ev,
293 struct sysdb_ctx *dbctx,
294 struct sss_domain_info *dom,
295 const char *username,
296 struct sysdb_attrs *attrs)
297 {
298 struct tevent_req *req, *subreq;
299 struct set_last_login_state *state;
300
301 req = tevent_req_create(memctx, &state, struct set_last_login_state);
302 if (!req) {
303 return NULL;
304 }
305
306 state->ev = ev;
307 state->dbctx = dbctx;
308 state->dom = dom;
309 state->username = username;
310 state->attrs = attrs;
311 state->handle = NULL;
312
313 subreq = sysdb_transaction_send(state, state->ev, state->dbctx);
314 if (!subreq) {
315 talloc_free(req);
316 return NULL;
317 }
318 tevent_req_set_callback(subreq, set_last_login_trans_done, req);
319
320 return req;
321 }
322
323 static void set_last_login_trans_done(struct tevent_req *subreq)
324 {
325 struct tevent_req *req = tevent_req_callback_data(subreq,
326 struct tevent_req);
327 struct set_last_login_state *state = tevent_req_data(req,
328 struct set_last_login_state);
329 int ret;
330
331 ret = sysdb_transaction_recv(subreq, state, &state->handle);
332 talloc_zfree(subreq);
333 if (ret != EOK) {
334 DEBUG(1, ("Unable to acquire sysdb transaction lock\n"));
335 tevent_req_error(req, ret);
336 return;
337 }
338
339 subreq = sysdb_set_user_attr_send(state, state->ev, state->handle,
340 state->dom, state->username,
341 state->attrs, SYSDB_MOD_REP);
342 if (!subreq) {
343 tevent_req_error(req, ENOMEM);
344 return;
345 }
346 tevent_req_set_callback(subreq, set_last_login_attrs_done, req);
347 }
348
349 static void set_last_login_attrs_done(struct tevent_req *subreq)
350 {
351 struct tevent_req *req = tevent_req_callback_data(subreq,
352 struct tevent_req);
353 struct set_last_login_state *state = tevent_req_data(req,
354 struct set_last_login_state);
355 int ret;
356
357 ret = sysdb_set_user_attr_recv(subreq);
358 talloc_zfree(subreq);
359 if (ret != EOK) {
360 DEBUG(4, ("set_user_attr_callback, status [%d][%s]\n",
361 ret, strerror(ret)));
362 tevent_req_error(req, ret);
363 return;
364 }
365
366 subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
367 if (!subreq) {
368 tevent_req_error(req, ENOMEM);
369 return;
370 }
371 tevent_req_set_callback(subreq, set_last_login_done, req);
372 }
373
374 static void set_last_login_done(struct tevent_req *subreq)
375 {
376 struct tevent_req *req = tevent_req_callback_data(subreq,
377 struct tevent_req);
378 int ret;
379
380 ret = sysdb_transaction_commit_recv(subreq);
381 if (ret != EOK) {
382 DEBUG(2, ("set_last_login failed.\n"));
383 tevent_req_error(req, ret);
384 return;
385 }
386
387 tevent_req_done(req);
388 }
389
390 static int set_last_login_recv(struct tevent_req *req)
391 {
392 TEVENT_REQ_RETURN_ON_ERROR(req);
393
394 return EOK;
395 }
396
397 /*=========================================================================*/
398
399
400 static void set_last_login_reply(struct tevent_req *req);
401
402 static errno_t set_last_login(struct pam_auth_req *preq)
403 {
404 struct tevent_req *req;
405 struct sysdb_ctx *dbctx;
406 struct sysdb_attrs *attrs;
407 errno_t ret;
408
409 attrs = sysdb_new_attrs(preq);
410 if (!attrs) {
411 ret = ENOMEM;
412 goto fail;
413 }
414
415 ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_ONLINE_AUTH, time(NULL));
416 if (ret != EOK) {
417 goto fail;
418 }
419
420 ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_LOGIN, time(NULL));
421 if (ret != EOK) {
422 goto fail;
423 }
424
425 ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list, preq->domain,
426 &dbctx);
427 if (ret != EOK) {
428 DEBUG(0, ("Fatal: Sysdb context not found for this domain!\n"));
429 goto fail;
430 }
431
432 req = set_last_login_send(preq, preq->cctx->ev, dbctx,
433 preq->domain, preq->pd->user, attrs);
434 if (!req) {
435 ret = ENOMEM;
436 goto fail;
437 }
438 tevent_req_set_callback(req, set_last_login_reply, preq);
439
440 return EOK;
441
442 fail:
443 return ret;
444 }
445
446 static void set_last_login_reply(struct tevent_req *req)
447 {
448 struct pam_auth_req *preq = tevent_req_callback_data(req,
449 struct pam_auth_req);
450 int ret;
451
452 ret = set_last_login_recv(req);
453 if (ret != EOK) {
454 preq->pd->pam_status = PAM_SYSTEM_ERR;
455 } else {
456 preq->pd->last_auth_saved = true;
457 }
458
459 preq->callback(preq);
460 }
461
462 static void pam_reply_delay(struct tevent_context *ev, struct tevent_timer *te,
463 struct timeval tv, void *pvt)
464 {
465 struct pam_auth_req *preq;
466
467 DEBUG(4, ("pam_reply_delay get called.\n"));
468
469 preq = talloc_get_type(pvt, struct pam_auth_req);
470
471 pam_reply(preq);
472 }
473
474 static void pam_cache_auth_done(struct tevent_req *req);
475
476 static void pam_reply(struct pam_auth_req *preq)
477 {
478 struct cli_ctx *cctx;
479 uint8_t *body;
480 size_t blen;
481 int ret;
482 int32_t resp_c;
483 int32_t resp_size;
484 struct response_data *resp;
485 int p;
486 struct timeval tv;
487 struct tevent_timer *te;
488 struct pam_data *pd;
489 struct tevent_req *req;
490 struct sysdb_ctx *sysdb;
491 struct pam_ctx *pctx;
492 uint32_t user_info_type;
493
494 pd = preq->pd;
495 cctx = preq->cctx;
496
497 DEBUG(4, ("pam_reply get called.\n"));
498
499 if (pd->pam_status == PAM_AUTHINFO_UNAVAIL) {
500 switch(pd->cmd) {
501 case SSS_PAM_AUTHENTICATE:
502 if ((preq->domain != NULL) &&
503 (preq->domain->cache_credentials == true) &&
504 (pd->offline_auth == false)) {
505
506 /* do auth with offline credentials */
507 pd->offline_auth = true;
508
509 ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list,
510 preq->domain, &sysdb);
511 if (ret != EOK) {
512 DEBUG(0, ("Fatal: Sysdb CTX not found for "
513 "domain [%s]!\n", preq->domain->name));
514 goto done;
515 }
516
517 pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx,
518 struct pam_ctx);
519
520 req = sysdb_cache_auth_send(preq, preq->cctx->ev, sysdb,
521 preq->domain, pd->user,
522 pd->authtok, pd->authtok_size,
523 pctx->rctx->cdb, false);
524 if (req == NULL) {
525 DEBUG(1, ("Failed to setup offline auth.\n"));
526 /* this error is not fatal, continue */
527 } else {
528 tevent_req_set_callback(req, pam_cache_auth_done, preq);
529 return;
530 }
531 }
532 break;
533 case SSS_PAM_CHAUTHTOK_PRELIM:
534 case SSS_PAM_CHAUTHTOK:
535 DEBUG(5, ("Password change not possible while offline.\n"));
536 pd->pam_status = PAM_AUTHTOK_ERR;
537 user_info_type = SSS_PAM_USER_INFO_OFFLINE_CHPASS;
538 pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t),
539 (const uint8_t *) &user_info_type);
540 break;
541 /* TODO: we need the pam session cookie here to make sure that cached
542 * authentication was successful */
543 case SSS_PAM_SETCRED:
544 case SSS_PAM_ACCT_MGMT:
545 case SSS_PAM_OPEN_SESSION:
546 case SSS_PAM_CLOSE_SESSION:
547 DEBUG(2, ("Assuming offline authentication setting status for "
548 "pam call %d to PAM_SUCCESS.\n", pd->cmd));
549 pd->pam_status = PAM_SUCCESS;
550 break;
551 default:
552 DEBUG(1, ("Unknown PAM call [%d].\n", pd->cmd));
553 pd->pam_status = PAM_MODULE_UNKNOWN;
554 }
555 }
556
557 if (pd->response_delay > 0) {
558 ret = gettimeofday(&tv, NULL);
559 if (ret != EOK) {
560 DEBUG(1, ("gettimeofday failed [%d][%s].\n",
561 errno, strerror(errno)));
562 goto done;
563 }
564 tv.tv_sec += pd->response_delay;
565 tv.tv_usec = 0;
566 pd->response_delay = 0;
567
568 te = tevent_add_timer(cctx->ev, cctx, tv, pam_reply_delay, preq);
569 if (te == NULL) {
570 DEBUG(1, ("Failed to add event pam_reply_delay.\n"));
571 goto done;
572 }
573
574 return;
575 }
576
577 /* If this was a successful login, save the lastLogin time */
578 if (pd->cmd == SSS_PAM_AUTHENTICATE &&
579 pd->pam_status == PAM_SUCCESS &&
580 preq->domain->cache_credentials &&
581 !pd->offline_auth &&
582 !pd->last_auth_saved &&
583 NEED_CHECK_PROVIDER(preq->domain->provider)) {
584 ret = set_last_login(preq);
585 if (ret != EOK) {
586 goto done;
587 }
588
589 return;
590 }
591
592 ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in),
593 &cctx->creq->out);
594 if (ret != EOK) {
595 goto done;
596 }
597
598 if (pd->domain != NULL) {
599 pam_add_response(pd, SSS_PAM_DOMAIN_NAME, strlen(pd->domain)+1,
600 (uint8_t *) pd->domain);
601 }
602
603 resp_c = 0;
604 resp_size = 0;
605 resp = pd->resp_list;
606 while(resp != NULL) {
607 resp_c++;
608 resp_size += resp->len;
609 resp = resp->next;
610 }
611
612 ret = sss_packet_grow(cctx->creq->out, sizeof(int32_t) +
613 sizeof(int32_t) +
614 resp_c * 2* sizeof(int32_t) +
615 resp_size);
616 if (ret != EOK) {
617 goto done;
618 }
619
620 sss_packet_get_body(cctx->creq->out, &body, &blen);
621 DEBUG(4, ("blen: %d\n", blen));
622 p = 0;
623
624 memcpy(&body[p], &pd->pam_status, sizeof(int32_t));
625 p += sizeof(int32_t);
626
627 memcpy(&body[p], &resp_c, sizeof(int32_t));
628 p += sizeof(int32_t);
629
630 resp = pd->resp_list;
631 while(resp != NULL) {
632 memcpy(&body[p], &resp->type, sizeof(int32_t));
633 p += sizeof(int32_t);
634 memcpy(&body[p], &resp->len, sizeof(int32_t));
635 p += sizeof(int32_t);
636 memcpy(&body[p], resp->data, resp->len);
637 p += resp->len;
638
639 resp = resp->next;
640 }
641
642 done:
643 sss_cmd_done(cctx, preq);
644 }
645
646 static void pam_cache_auth_done(struct tevent_req *req)
647 {
648 int ret;
649 struct pam_auth_req *preq = tevent_req_callback_data(req,
650 struct pam_auth_req);
651 uint32_t resp_type;
652 size_t resp_len;
653 uint8_t *resp;
654 time_t expire_date = 0;
655 time_t delayed_until = -1;
656 long long dummy;
657
658 ret = sysdb_cache_auth_recv(req, &expire_date, &delayed_until);
659 talloc_zfree(req);
660
661 switch (ret) {
662 case EOK:
663 preq->pd->pam_status = PAM_SUCCESS;
664
665 resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH;
666 resp_len = sizeof(uint32_t) + sizeof(long long);
667 resp = talloc_size(preq->pd, resp_len);
668 if (resp == NULL) {
669 DEBUG(1, ("talloc_size failed, cannot prepare user info.\n"));
670 } else {
671 memcpy(resp, &resp_type, sizeof(uint32_t));
672 dummy = (long long) expire_date;
673 memcpy(resp+sizeof(uint32_t), &dummy, sizeof(long long));
674 ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len,
675 (const uint8_t *) resp);
676 if (ret != EOK) {
677 DEBUG(1, ("pam_add_response failed.\n"));
678 }
679 }
680 break;
681 case ENOENT:
682 preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
683 break;
684 case EINVAL:
685 preq->pd->pam_status = PAM_AUTH_ERR;
686 break;
687 case EACCES:
688 preq->pd->pam_status = PAM_PERM_DENIED;
689 if (delayed_until >= 0) {
690 resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH_DELAYED;
691 resp_len = sizeof(uint32_t) + sizeof(long long);
692 resp = talloc_size(preq->pd, resp_len);
693 if (resp == NULL) {
694 DEBUG(1, ("talloc_size failed, cannot prepare user info.\n"));
695 } else {
696 memcpy(resp, &resp_type, sizeof(uint32_t));
697 dummy = (long long) delayed_until;
698 memcpy(resp+sizeof(uint32_t), &dummy, sizeof(long long));
699 ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len,
700 (const uint8_t *) resp);
701 if (ret != EOK) {
702 DEBUG(1, ("pam_add_response failed.\n"));
703 }
704 }
705 }
706 break;
707 default:
708 preq->pd->pam_status = PAM_SYSTEM_ERR;
709 }
710
711 pam_reply(preq);
712 return;
713 }
714
715 static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
716 const char *err_msg, void *ptr);
717 static void pam_check_user_callback(void *ptr, int status,
718 struct ldb_result *res);
719 static void pam_dom_forwarder(struct pam_auth_req *preq);
720
721 /* TODO: we should probably return some sort of cookie that is set in the
722 * PAM_ENVIRONMENT, so that we can save performing some calls and cache
723 * data. */
724
725 static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
726 {
727 struct sss_domain_info *dom;
728 struct sysdb_ctx *sysdb;
729 struct pam_auth_req *preq;
730 struct pam_data *pd;
731 uint8_t *body;
732 size_t blen;
733 int timeout;
734 int ret;
735 uint32_t terminator = SSS_END_OF_PAM_REQUEST;
736 preq = talloc_zero(cctx, struct pam_auth_req);
737 if (!preq) {
738 return ENOMEM;
739 }
740 preq->cctx = cctx;
741
742 preq->pd = talloc_zero(preq, struct pam_data);
743 if (!preq->pd) {
744 talloc_free(preq);
745 return ENOMEM;
746 }
747 pd = preq->pd;
748
749 sss_packet_get_body(cctx->creq->in, &body, &blen);
750 if (blen >= sizeof(uint32_t) &&
751 memcmp(&body[blen - sizeof(uint32_t)], &terminator, sizeof(uint32_t)) != 0) {
752 DEBUG(1, ("Received data not terminated.\n"));
753 ret = EINVAL;
754 goto done;
755 }
756
757 pd->cmd = pam_cmd;
758 pd->priv = cctx->priv;
759
760 switch (cctx->cli_protocol_version->version) {
761 case 1:
762 ret = pam_parse_in_data(cctx->rctx->names, pd, body, blen);
763 break;
764 case 2:
765 ret = pam_parse_in_data_v2(cctx->rctx->names, pd, body, blen);
766 break;
767 case 3:
768 ret = pam_parse_in_data_v3(cctx->rctx->names, pd, body, blen);
769 break;
770 default:
771 DEBUG(1, ("Illegal protocol version [%d].\n",
772 cctx->cli_protocol_version->version));
773 ret = EINVAL;
774 }
775 if (ret != EOK) {
776 ret = EINVAL;
777 goto done;
778 }
779
780 /* now check user is valid */
781 if (pd->domain) {
782 for (dom = cctx->rctx->domains; dom; dom = dom->next) {
783 if (strcasecmp(dom->name, pd->domain) == 0) break;
784 }
785 if (!dom) {
786 ret = ENOENT;
787 goto done;
788 }
789 preq->domain = dom;
790 }
791 else {
792 for (dom = preq->cctx->rctx->domains; dom; dom = dom->next) {
793 if (dom->fqnames) continue;
794
795 /* FIXME: need to support negative cache */
796 #if HAVE_NEG_CACHE
797 ncret = sss_ncache_check_user(nctx->ncache, nctx->neg_timeout,
798 dom->name, cmdctx->name);
799 if (ncret == ENOENT) break;
800 #endif
801 break;
802 }
803 if (!dom) {
804 ret = ENOENT;
805 goto done;
806 }
807 preq->domain = dom;
808 }
809
810 if (preq->domain->provider == NULL) {
811 DEBUG(1, ("Domain [%s] has no auth provider.\n", preq->domain->name));
812 ret = EINVAL;
813 goto done;
814 }
815
816 /* When auth is requested always search the provider first,
817 * do not rely on cached data unless the provider is completely
818 * offline */
819 if (NEED_CHECK_PROVIDER(preq->domain->provider) &&
820 (pam_cmd == SSS_PAM_AUTHENTICATE || pam_cmd == SSS_PAM_SETCRED)) {
821
822 /* no need to re-check later on */
823 preq->check_provider = false;
824 timeout = SSS_CLI_SOCKET_TIMEOUT/2;
825
826 ret = sss_dp_send_acct_req(preq->cctx->rctx, preq,
827 pam_check_user_dp_callback, preq,
828 timeout, preq->domain->name,
829 false, SSS_DP_INITGROUPS,
830 preq->pd->user, 0);
831 }
832 else {
833 preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider);
834
835 ret = sysdb_get_ctx_from_list(cctx->rctx->db_list,
836 preq->domain, &sysdb);
837 if (ret != EOK) {
838 DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n"));
839 goto done;
840 }
841 ret = sysdb_getpwnam(preq, sysdb,
842 preq->domain, preq->pd->user,
843 pam_check_user_callback, preq);
844 }
845
846 done:
847 if (ret != EOK) {
848 switch (ret) {
849 case ENOENT:
850 pd->pam_status = PAM_USER_UNKNOWN;
851 default:
852 pd->pam_status = PAM_SYSTEM_ERR;
853 }
854 pam_reply(preq);
855 }
856 return EOK;
857 }
858
859 static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
860 const char *err_msg, void *ptr)
861 {
862 struct pam_auth_req *preq = talloc_get_type(ptr, struct pam_auth_req);
863 struct sysdb_ctx *sysdb;
864 int ret;
865
866 if (err_maj) {
867 DEBUG(2, ("Unable to get information from Data Provider\n"
868 "Error: %u, %u, %s\n",
869 (unsigned int)err_maj, (unsigned int)err_min, err_msg));
870 }
871
872 /* always try to see if we have the user in cache even if the provider
873 * returned an error */
874 ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list,
875 preq->domain, &sysdb);
876 if (ret != EOK) {
877 DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n"));
878 goto done;
879 }
880 ret = sysdb_getpwnam(preq, sysdb,
881 preq->domain, preq->pd->user,
882 pam_check_user_callback, preq);
883
884 done:
885 if (ret != EOK) {
886 preq->pd->pam_status = PAM_SYSTEM_ERR;
887 pam_reply(preq);
888 }
889 }
890
891 static void pam_check_user_callback(void *ptr, int status,
892 struct ldb_result *res)
893 {
894 struct pam_auth_req *preq = talloc_get_type(ptr, struct pam_auth_req);
895 struct sss_domain_info *dom;
896 struct sysdb_ctx *sysdb;
897 uint64_t cacheExpire;
898 bool call_provider = false;
899 time_t timeout;
900 int ret;
901
902 if (status != LDB_SUCCESS) {
903 preq->pd->pam_status = PAM_SYSTEM_ERR;
904 pam_reply(preq);
905 return;
906 }
907
908 timeout = SSS_CLI_SOCKET_TIMEOUT/2;
909
910 if (preq->check_provider) {
911 switch (res->count) {
912 case 0:
913 call_provider = true;
914 break;
915
916 case 1:
917 cacheExpire = ldb_msg_find_attr_as_uint64(res->msgs[0],
918 SYSDB_CACHE_EXPIRE, 0);
919 if (cacheExpire < time(NULL)) {
920 call_provider = true;
921 }
922 break;
923
924 default:
925 DEBUG(1, ("check user call returned more than one result !?!\n"));
926 preq->pd->pam_status = PAM_SYSTEM_ERR;
927 pam_reply(preq);
928 return;
929 }
930 }
931
932 if (call_provider) {
933
934 /* dont loop forever :-) */
935 preq->check_provider = false;
936
937 /* keep around current data in case backend is offline */
938 if (res->count) {
939 preq->data = talloc_steal(preq, res);
940 }
941
942 ret = sss_dp_send_acct_req(preq->cctx->rctx, preq,
943 pam_check_user_dp_callback, preq,
944 timeout, preq->domain->name,
945 false, SSS_DP_USER,
946 preq->pd->user, 0);
947 if (ret != EOK) {
948 DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
949 ret, strerror(ret)));
950 preq->pd->pam_status = PAM_SYSTEM_ERR;
951 pam_reply(preq);
952 }
953 return;
954 }
955
956 switch (res->count) {
957 case 0:
958 if (!preq->pd->domain) {
959 /* search next as the domain was unknown */
960
961 ret = EOK;
962
963 /* skip domains that require FQnames or have negative caches */
964 for (dom = preq->domain->next; dom; dom = dom->next) {
965
966 if (dom->fqnames) continue;
967
968 #if HAVE_NEG_CACHE
969 ncret = nss_ncache_check_user(nctx->ncache,
970 nctx->neg_timeout,
971 dom->name, cmdctx->name);
972 if (ncret == ENOENT) break;
973
974 neghit = true;
975 #endif
976 break;
977 }
978 #if HAVE_NEG_CACHE
979 /* reset neghit if we still have a domain to check */
980 if (dom) neghit = false;
981
982 if (neghit) {
983 DEBUG(2, ("User [%s] does not exist! (negative cache)\n",
984 cmdctx->name));
985 ret = ENOENT;
986 }
987 #endif
988 if (dom == NULL) {
989 DEBUG(2, ("No matching domain found for [%s], fail!\n",
990 preq->pd->user));
991 ret = ENOENT;
992 }
993
994 if (ret == EOK) {
995 preq->domain = dom;
996 preq->data = NULL;
997
998 DEBUG(4, ("Requesting info for [%s@%s]\n",
999 preq->pd->user, preq->domain->name));
1000
1001 /* When auth is requested always search the provider first,
1002 * do not rely on cached data unless the provider is
1003 * completely offline */
1004 if (NEED_CHECK_PROVIDER(preq->domain->provider) &&
1005 (preq->pd->cmd == SSS_PAM_AUTHENTICATE ||
1006 preq->pd->cmd == SSS_PAM_SETCRED)) {
1007
1008 /* no need to re-check later on */
1009 preq->check_provider = false;
1010
1011 ret = sss_dp_send_acct_req(preq->cctx->rctx, preq,
1012 pam_check_user_dp_callback,
1013 preq, timeout,
1014 preq->domain->name,
1015 false, SSS_DP_USER,
1016 preq->pd->user, 0);
1017 }
1018 else {
1019 preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider);
1020
1021 ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list,
1022 preq->domain, &sysdb);
1023 if (ret != EOK) {
1024 DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n"));
1025 preq->pd->pam_status = PAM_SYSTEM_ERR;
1026 pam_reply(preq);
1027 return;
1028 }
1029 ret = sysdb_getpwnam(preq, sysdb,
1030 preq->domain, preq->pd->user,
1031 pam_check_user_callback, preq);
1032 }
1033 if (ret != EOK) {
1034 DEBUG(1, ("Failed to make request to our cache!\n"));
1035 }
1036 }
1037
1038 /* we made another call, end here */
1039 if (ret == EOK) return;
1040 }
1041 else {
1042 ret = ENOENT;
1043 }
1044
1045 DEBUG(2, ("No results for check user call\n"));
1046
1047 #if HAVE_NEG_CACHE
1048 /* set negative cache only if not result of cache check */
1049 if (!neghit) {
1050 ret = nss_ncache_set_user(nctx->ncache, false,
1051 dctx->domain->name, cmdctx->name);
1052 if (ret != EOK) {
1053 NSS_CMD_FATAL_ERROR(cctx);
1054 }
1055 }
1056 #endif
1057
1058 if (ret != EOK) {
1059 if (ret == ENOENT) {
1060 preq->pd->pam_status = PAM_USER_UNKNOWN;
1061 } else {
1062 preq->pd->pam_status = PAM_SYSTEM_ERR;
1063 }
1064 pam_reply(preq);
1065 return;
1066 }
1067 break;
1068
1069 case 1:
1070
1071 /* BINGO */
1072 pam_dom_forwarder(preq);
1073 return;
1074
1075 default:
1076 DEBUG(1, ("check user call returned more than one result !?!\n"));
1077 preq->pd->pam_status = PAM_SYSTEM_ERR;
1078 pam_reply(preq);
1079 }
1080 }
1081
1082 static void pam_dom_forwarder(struct pam_auth_req *preq)
1083 {
1084 int ret;
1085
1086 if (!preq->pd->domain) {
1087 preq->pd->domain = preq->domain->name;
1088 }
1089
1090 if (!NEED_CHECK_PROVIDER(preq->domain->provider)) {
1091 preq->callback = pam_reply;
1092 ret = LOCAL_pam_handler(preq);
1093 }
1094 else {
1095 preq->callback = pam_reply;
1096 ret = pam_dp_send_req(preq, SSS_CLI_SOCKET_TIMEOUT/2);
1097 DEBUG(4, ("pam_dp_send_req returned %d\n", ret));
1098 }
1099
1100 if (ret != EOK) {
1101 preq->pd->pam_status = PAM_SYSTEM_ERR;
1102 pam_reply(preq);
1103 }
1104 }
1105
1106 static int pam_cmd_authenticate(struct cli_ctx *cctx) {
1107 DEBUG(4, ("entering pam_cmd_authenticate\n"));
1108 return pam_forwarder(cctx, SSS_PAM_AUTHENTICATE);
1109 }
1110
1111 static int pam_cmd_setcred(struct cli_ctx *cctx) {
1112 DEBUG(4, ("entering pam_cmd_setcred\n"));
1113 return pam_forwarder(cctx, SSS_PAM_SETCRED);
1114 }
1115
1116 static int pam_cmd_acct_mgmt(struct cli_ctx *cctx) {
1117 DEBUG(4, ("entering pam_cmd_acct_mgmt\n"));
1118 return pam_forwarder(cctx, SSS_PAM_ACCT_MGMT);
1119 }
1120
1121 static int pam_cmd_open_session(struct cli_ctx *cctx) {
1122 DEBUG(4, ("entering pam_cmd_open_session\n"));
1123 return pam_forwarder(cctx, SSS_PAM_OPEN_SESSION);
1124 }
1125
1126 static int pam_cmd_close_session(struct cli_ctx *cctx) {
1127 DEBUG(4, ("entering pam_cmd_close_session\n"));
1128 return pam_forwarder(cctx, SSS_PAM_CLOSE_SESSION);
1129 }
1130
1131 static int pam_cmd_chauthtok(struct cli_ctx *cctx) {
1132 DEBUG(4, ("entering pam_cmd_chauthtok\n"));
1133 return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK);
1134 }
1135
1136 static int pam_cmd_chauthtok_prelim(struct cli_ctx *cctx) {
1137 DEBUG(4, ("entering pam_cmd_chauthtok_prelim\n"));
1138 return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK_PRELIM);
1139 }
1140
1141 struct cli_protocol_version *register_cli_protocol_version(void)
1142 {
1143 static struct cli_protocol_version pam_cli_protocol_version[] = {
1144 {3, "2009-09-14", "make cli_pid mandatory"},
1145 {2, "2009-05-12", "new format <type><size><data>"},
1146 {1, "2008-09-05", "initial version, \\0 terminated strings"},
1147 {0, NULL, NULL}
1148 };
1149
1150 return pam_cli_protocol_version;
1151 }
1152
1153 struct sss_cmd_table *get_pam_cmds(void)
1154 {
1155 static struct sss_cmd_table sss_cmds[] = {
1156 {SSS_GET_VERSION, sss_cmd_get_version},
1157 {SSS_PAM_AUTHENTICATE, pam_cmd_authenticate},
1158 {SSS_PAM_SETCRED, pam_cmd_setcred},
1159 {SSS_PAM_ACCT_MGMT, pam_cmd_acct_mgmt},
1160 {SSS_PAM_OPEN_SESSION, pam_cmd_open_session},
1161 {SSS_PAM_CLOSE_SESSION, pam_cmd_close_session},
1162 {SSS_PAM_CHAUTHTOK, pam_cmd_chauthtok},
1163 {SSS_PAM_CHAUTHTOK_PRELIM, pam_cmd_chauthtok_prelim},
1164 {SSS_CLI_NULL, NULL}
1165 };
1166
1167 return sss_cmds;
1168 }