1 /*
2 SSSD
3
4 Kerberos 5 Backend Module
5
6 Authors:
7 Sumit Bose <sbose@redhat.com>
8
9 Copyright (C) 2009-2010 Red Hat
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include <errno.h>
26 #include <sys/time.h>
27
28 #include <sys/types.h>
29 #include <sys/wait.h>
30 #include <pwd.h>
31 #include <sys/stat.h>
32
33 #include <security/pam_modules.h>
34
35 #include "util/util.h"
36 #include "util/find_uid.h"
37 #include "db/sysdb.h"
38 #include "providers/child_common.h"
39 #include "providers/krb5/krb5_auth.h"
40 #include "providers/krb5/krb5_utils.h"
41
42 #ifndef SSSD_LIBEXEC_PATH
43 #error "SSSD_LIBEXEC_PATH not defined"
44 #else
45 #define KRB5_CHILD SSSD_LIBEXEC_PATH"/krb5_child"
46 #endif
47
48 static errno_t safe_remove_old_ccache_file(const char *old_ccache_file,
49 const char *new_ccache_file)
50 {
51 int ret;
52 size_t old_offset = 0;
53 size_t new_offset = 0;
54
55 if (new_ccache_file == NULL) {
56 DEBUG(1, ("Missing new ccache file, "
57 "old ccache file is not deleted.\n"));
58 return EINVAL;
59 }
60
61 if (old_ccache_file != NULL) {
62 if (strncmp(old_ccache_file, "FILE:", 5) == 0) {
63 old_offset = 5;
64 }
65 if (strncmp(new_ccache_file, "FILE:", 5) == 0) {
66 new_offset = 5;
67 }
68 if (strcmp(old_ccache_file + old_offset,
69 new_ccache_file + new_offset) == 0) {
70 DEBUG(7, ("New and old ccache file are the same, "
71 "no one will be deleted.\n"));
72 return EOK;
73 }
74 if (old_ccache_file[old_offset] != '/') {
75 DEBUG(1, ("Ccache file name [%s] is not an absolute path.\n",
76 old_ccache_file + old_offset));
77 return EINVAL;
78 }
79 ret = unlink(old_ccache_file + old_offset);
80 if (ret == -1 && errno != ENOENT) {
81 ret = errno;
82 DEBUG(1, ("unlink [%s] failed [%d][%s].\n", old_ccache_file, ret,
83 strerror(ret)));
84 return ret;
85 }
86 }
87
88 return EOK;
89 }
90
91 static errno_t check_if_ccache_file_is_used(uid_t uid, const char *ccname,
92 bool *result)
93 {
94 int ret;
95 size_t offset = 0;
96 struct stat stat_buf;
97 const char *filename;
98 bool active;
99
100 *result = false;
101
102 if (ccname == NULL || *ccname == '\0') {
103 return EINVAL;
104 }
105
106 if (strncmp(ccname, "FILE:", 5) == 0) {
107 offset = 5;
108 }
109
110 filename = ccname + offset;
111
112 if (filename[0] != '/') {
113 DEBUG(1, ("Only absolute path names are allowed.\n"));
114 return EINVAL;
115 }
116
117 ret = lstat(filename, &stat_buf);
118
119 if (ret == -1 && errno != ENOENT) {
120 DEBUG(1, ("stat failed [%d][%s].\n", errno, strerror(errno)));
121 return errno;
122 } else if (ret == EOK) {
123 if (stat_buf.st_uid != uid) {
124 DEBUG(1, ("Cache file [%s] exists, but is owned by [%d] instead of "
125 "[%d].\n", filename, stat_buf.st_uid, uid));
126 return EINVAL;
127 }
128
129 if (!S_ISREG(stat_buf.st_mode)) {
130 DEBUG(1, ("Cache file [%s] exists, but is not a regular file.\n",
131 filename));
132 return EINVAL;
133 }
134 }
135
136 ret = check_if_uid_is_active(uid, &active);
137 if (ret != EOK) {
138 DEBUG(1, ("check_if_uid_is_active failed.\n"));
139 return ret;
140 }
141
142 if (!active) {
143 DEBUG(5, ("User [%d] is not active\n", uid));
144 } else {
145 DEBUG(9, ("User [%d] is still active, reusing ccache file [%s].\n",
146 uid, filename));
147 *result = true;
148 }
149 return EOK;
150 }
151
152 struct krb5_save_ccname_state {
153 struct tevent_context *ev;
154 struct sysdb_ctx *sysdb;
155 struct sysdb_handle *handle;
156 struct sss_domain_info *domain;
157 const char *name;
158 struct sysdb_attrs *attrs;
159 };
160
161 static void krb5_save_ccname_trans(struct tevent_req *subreq);
162 static void krb5_set_user_attr_done(struct tevent_req *subreq);
163
164 static struct tevent_req *krb5_save_ccname_send(TALLOC_CTX *mem_ctx,
165 struct tevent_context *ev,
166 struct sysdb_ctx *sysdb,
167 struct sss_domain_info *domain,
168 const char *name,
169 const char *ccname)
170 {
171 struct tevent_req *req;
172 struct tevent_req *subreq;
173 struct krb5_save_ccname_state *state;
174 int ret;
175
176 if (name == NULL || ccname == NULL) {
177 DEBUG(1, ("Missing user or ccache name.\n"));
178 return NULL;
179 }
180
181 req = tevent_req_create(mem_ctx, &state, struct krb5_save_ccname_state);
182 if (req == NULL) {
183 DEBUG(1, ("tevent_req_create failed.\n"));
184 return NULL;
185 }
186
187 state->ev = ev;
188 state->sysdb = sysdb;
189 state->handle = NULL;
190 state->domain = domain;
191 state->name = name;
192
193 state->attrs = sysdb_new_attrs(state);
194 ret = sysdb_attrs_add_string(state->attrs, SYSDB_CCACHE_FILE, ccname);
195 if (ret != EOK) {
196 DEBUG(1, ("sysdb_attrs_add_string failed.\n"));
197 goto failed;
198 }
199
200 subreq = sysdb_transaction_send(state, ev, sysdb);
201 if (subreq == NULL) {
202 goto failed;
203 }
204 tevent_req_set_callback(subreq, krb5_save_ccname_trans, req);
205
206 return req;
207
208 failed:
209 talloc_free(req);
210 return NULL;
211 }
212
213 static void krb5_save_ccname_trans(struct tevent_req *subreq)
214 {
215 struct tevent_req *req = tevent_req_callback_data(subreq,
216 struct tevent_req);
217 struct krb5_save_ccname_state *state = tevent_req_data(req,
218 struct krb5_save_ccname_state);
219 int ret;
220
221 ret = sysdb_transaction_recv(subreq, state, &state->handle);
222 talloc_zfree(subreq);
223 if (ret != EOK) {
224 DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));
225 tevent_req_error(req, ret);
226 return;
227 }
228
229 subreq = sysdb_set_user_attr_send(state, state->ev, state->handle,
230 state->domain, state->name,
231 state->attrs, SYSDB_MOD_REP);
232 if (subreq == NULL) {
233 DEBUG(6, ("Error: Out of memory\n"));
234 tevent_req_error(req, ENOMEM);
235 return;
236 }
237 tevent_req_set_callback(subreq, krb5_set_user_attr_done, req);
238 }
239
240 static void krb5_set_user_attr_done(struct tevent_req *subreq)
241 {
242 struct tevent_req *req = tevent_req_callback_data(subreq,
243 struct tevent_req);
244 struct krb5_save_ccname_state *state = tevent_req_data(req,
245 struct krb5_save_ccname_state);
246 int ret;
247
248 ret = sysdb_set_user_attr_recv(subreq);
249 talloc_zfree(subreq);
250 if (ret != EOK) {
251 DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));
252 tevent_req_error(req, ret);
253 return;
254 }
255
256 subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
257 if (subreq == NULL) {
258 DEBUG(6, ("Error: Out of memory\n"));
259 tevent_req_error(req, ENOMEM);
260 return;
261 }
262 tevent_req_set_callback(subreq, sysdb_transaction_complete, req);
263 return;
264 }
265
266 int krb5_save_ccname_recv(struct tevent_req *req)
267 {
268 TEVENT_REQ_RETURN_ON_ERROR(req);
269
270 return EOK;
271 }
272
273 errno_t create_send_buffer(struct krb5child_req *kr, struct io_buffer **io_buf)
274 {
275 struct io_buffer *buf;
276 size_t rp;
277 const char *keytab;
278 uint32_t validate;
279
280 keytab = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_KEYTAB);
281 if (keytab == NULL) {
282 DEBUG(1, ("Missing keytab option.\n"));
283 return EINVAL;
284 }
285
286 validate = dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) ? 1 : 0;
287
288 buf = talloc(kr, struct io_buffer);
289 if (buf == NULL) {
290 DEBUG(1, ("talloc failed.\n"));
291 return ENOMEM;
292 }
293
294 buf->size = 9*sizeof(uint32_t) + strlen(kr->upn) + strlen(kr->ccname) +
295 strlen(keytab) +
296 kr->pd->authtok_size;
297 if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
298 buf->size += sizeof(uint32_t) + kr->pd->newauthtok_size;
299 }
300
301 buf->data = talloc_size(kr, buf->size);
302 if (buf->data == NULL) {
303 DEBUG(1, ("talloc_size failed.\n"));
304 talloc_free(buf);
305 return ENOMEM;
306 }
307
308 rp = 0;
309 SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->cmd, &rp);
310 SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->uid, &rp);
311 SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->gid, &rp);
312 SAFEALIGN_COPY_UINT32(&buf->data[rp], &validate, &rp);
313 SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->is_offline, &rp);
314
315 SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->upn), &rp);
316 safealign_memcpy(&buf->data[rp], kr->upn, strlen(kr->upn), &rp);
317
318 SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->ccname), &rp);
319 safealign_memcpy(&buf->data[rp], kr->ccname, strlen(kr->ccname), &rp);
320
321 SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab), &rp);
322 safealign_memcpy(&buf->data[rp], keytab, strlen(keytab), &rp);
323
324 SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_size, &rp);
325 safealign_memcpy(&buf->data[rp], kr->pd->authtok,
326 kr->pd->authtok_size, &rp);
327
328 if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
329 SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_size, &rp);
330 safealign_memcpy(&buf->data[rp], kr->pd->newauthtok,
331 kr->pd->newauthtok_size, &rp);
332 }
333
334 *io_buf = buf;
335
336 return EOK;
337 }
338
339 static struct krb5_ctx *get_krb5_ctx(struct be_req *be_req)
340 {
341 struct pam_data *pd;
342
343 pd = talloc_get_type(be_req->req_data, struct pam_data);
344
345 switch (pd->cmd) {
346 case SSS_PAM_AUTHENTICATE:
347 return talloc_get_type(be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data,
348 struct krb5_ctx);
349 break;
350 case SSS_PAM_CHAUTHTOK:
351 case SSS_PAM_CHAUTHTOK_PRELIM:
352 return talloc_get_type(be_req->be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
353 struct krb5_ctx);
354 break;
355 default:
356 DEBUG(1, ("Unsupported PAM task.\n"));
357 return NULL;
358 }
359 }
360
361 static void krb_reply(struct be_req *req, int dp_err, int result);
362
363 static int krb5_cleanup(void *ptr)
364 {
365 struct krb5child_req *kr = talloc_get_type(ptr, struct krb5child_req);
366
367 if (kr == NULL) return EOK;
368
369 child_cleanup(kr->read_from_child_fd, kr->write_to_child_fd);
370 memset(kr, 0, sizeof(struct krb5child_req));
371
372 return EOK;
373 }
374
375 static errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd,
376 struct krb5_ctx *krb5_ctx,
377 struct krb5child_req **krb5_req)
378 {
379 struct krb5child_req *kr = NULL;
380
381 kr = talloc_zero(mem_ctx, struct krb5child_req);
382 if (kr == NULL) {
383 DEBUG(1, ("talloc failed.\n"));
384 return ENOMEM;
385 }
386 kr->read_from_child_fd = -1;
387 kr->write_to_child_fd = -1;
388 kr->is_offline = false;
389 kr->active_ccache_present = true;
390 talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup);
391
392 kr->pd = pd;
393 kr->krb5_ctx = krb5_ctx;
394
395 *krb5_req = kr;
396
397 return EOK;
398
399 }
400
401 struct handle_child_state {
402 struct tevent_context *ev;
403 struct krb5child_req *kr;
404 uint8_t *buf;
405 ssize_t len;
406 };
407
408 static void krb5_child_timeout(struct tevent_context *ev,
409 struct tevent_timer *te,
410 struct timeval tv, void *pvt)
411 {
412 struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
413 struct handle_child_state *state = tevent_req_data(req,
414 struct handle_child_state);
415 struct krb5child_req *kr = state->kr;
416 int ret;
417
418 if (kr->timeout_handler == NULL) {
419 return;
420 }
421
422 DEBUG(9, ("timeout for child [%d] reached.\n", kr->child_pid));
423
424 ret = kill(kr->child_pid, SIGKILL);
425 if (ret == -1) {
426 DEBUG(1, ("kill failed [%d][%s].\n", errno, strerror(errno)));
427 }
428
429 tevent_req_error(req, ETIMEDOUT);
430 }
431
432 static errno_t activate_child_timeout_handler(struct tevent_req *req,
433 struct tevent_context *ev,
434 struct krb5child_req *kr)
435 {
436 struct timeval tv;
437 struct handle_child_state *state = tevent_req_data(req,
438 struct handle_child_state);
439
440 tv = tevent_timeval_current();
441 tv = tevent_timeval_add(&tv,
442 dp_opt_get_int(kr->krb5_ctx->opts,
443 KRB5_AUTH_TIMEOUT),
444 0);
445 kr->timeout_handler = tevent_add_timer(ev, state, tv,
446 krb5_child_timeout, req);
447 if (kr->timeout_handler == NULL) {
448 DEBUG(1, ("tevent_add_timer failed.\n"));
449 return ENOMEM;
450 }
451
452 return EOK;
453 }
454
455 static errno_t fork_child(struct tevent_req *req, struct tevent_context *ev,
456 struct krb5child_req *kr)
457 {
458 int pipefd_to_child[2];
459 int pipefd_from_child[2];
460 pid_t pid;
461 int ret;
462 errno_t err;
463
464 ret = pipe(pipefd_from_child);
465 if (ret == -1) {
466 err = errno;
467 DEBUG(1, ("pipe failed [%d][%s].\n", errno, strerror(errno)));
468 return err;
469 }
470 ret = pipe(pipefd_to_child);
471 if (ret == -1) {
472 err = errno;
473 DEBUG(1, ("pipe failed [%d][%s].\n", errno, strerror(errno)));
474 return err;
475 }
476
477 pid = fork();
478
479 if (pid == 0) { /* child */
480 /* We need to keep the root privileges to read the keytab file if
481 * validation is enabled, otherwise we can drop them here and run
482 * krb5_child with user privileges.
483 * If we are offline and want to create an empty ccache file. In this
484 * case we can drop the privileges, too. */
485 if (!dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) ||
486 kr->is_offline) {
487 ret = become_user(kr->uid, kr->gid);
488 if (ret != EOK) {
489 DEBUG(1, ("become_user failed.\n"));
490 return ret;
491 }
492 }
493
494 err = exec_child(kr,
495 pipefd_to_child, pipefd_from_child,
496 KRB5_CHILD, kr->krb5_ctx->child_debug_fd);
497 if (err != EOK) {
498 DEBUG(1, ("Could not exec LDAP child: [%d][%s].\n",
499 err, strerror(err)));
500 return err;
501 }
502 } else if (pid > 0) { /* parent */
503 kr->child_pid = pid;
504 kr->read_from_child_fd = pipefd_from_child[0];
505 close(pipefd_from_child[1]);
506 kr->write_to_child_fd = pipefd_to_child[1];
507 close(pipefd_to_child[0]);
508 fd_nonblocking(kr->read_from_child_fd);
509 fd_nonblocking(kr->write_to_child_fd);
510
511 ret = child_handler_setup(ev, pid, NULL, NULL);
512 if (ret != EOK) {
513 DEBUG(1, ("Could not set up child signal handler\n"));
514 return ret;
515 }
516
517 err = activate_child_timeout_handler(req, ev, kr);
518 if (err != EOK) {
519 DEBUG(1, ("activate_child_timeout_handler failed.\n"));
520 }
521
522 } else { /* error */
523 err = errno;
524 DEBUG(1, ("fork failed [%d][%s].\n", errno, strerror(errno)));
525 return err;
526 }
527
528 return EOK;
529 }
530
531 static void handle_child_step(struct tevent_req *subreq);
532 static void handle_child_done(struct tevent_req *subreq);
533
534 static struct tevent_req *handle_child_send(TALLOC_CTX *mem_ctx,
535 struct tevent_context *ev,
536 struct krb5child_req *kr)
537 {
538 struct tevent_req *req, *subreq;
539 struct handle_child_state *state;
540 struct io_buffer *buf;
541 int ret;
542
543 req = tevent_req_create(mem_ctx, &state, struct handle_child_state);
544 if (req == NULL) {
545 return NULL;
546 }
547
548 state->ev = ev;
549 state->kr = kr;
550 state->buf = NULL;
551 state->len = 0;
552
553 ret = create_send_buffer(kr, &buf);
554 if (ret != EOK) {
555 DEBUG(1, ("create_send_buffer failed.\n"));
556 goto fail;
557 }
558
559 ret = fork_child(req, ev, kr);
560 if (ret != EOK) {
561 DEBUG(1, ("fork_child failed.\n"));
562 goto fail;
563 }
564
565 subreq = write_pipe_send(state, ev, buf->data, buf->size,
566 kr->write_to_child_fd);
567 if (!subreq) {
568 ret = ENOMEM;
569 goto fail;
570 }
571 tevent_req_set_callback(subreq, handle_child_step, req);
572
573 return req;
574
575 fail:
576 tevent_req_error(req, ret);
577 tevent_req_post(req, ev);
578 return req;
579 }
580
581 static void handle_child_step(struct tevent_req *subreq)
582 {
583 struct tevent_req *req = tevent_req_callback_data(subreq,
584 struct tevent_req);
585 struct handle_child_state *state = tevent_req_data(req,
586 struct handle_child_state);
587 int ret;
588
589 ret = write_pipe_recv(subreq);
590 talloc_zfree(subreq);
591 if (ret != EOK) {
592 tevent_req_error(req, ret);
593 return;
594 }
595
596 close(state->kr->write_to_child_fd);
597 state->kr->write_to_child_fd = -1;
598
599 subreq = read_pipe_send(state, state->ev, state->kr->read_from_child_fd);
600 if (!subreq) {
601 tevent_req_error(req, ENOMEM);
602 return;
603 }
604 tevent_req_set_callback(subreq, handle_child_done, req);
605 }
606
607 static void handle_child_done(struct tevent_req *subreq)
608 {
609 struct tevent_req *req = tevent_req_callback_data(subreq,
610 struct tevent_req);
611 struct handle_child_state *state = tevent_req_data(req,
612 struct handle_child_state);
613 int ret;
614
615 ret = read_pipe_recv(subreq, state, &state->buf, &state->len);
616 talloc_zfree(subreq);
617 if (ret != EOK) {
618 tevent_req_error(req, ret);
619 return;
620 }
621
622 close(state->kr->read_from_child_fd);
623 state->kr->read_from_child_fd = -1;
624
625 tevent_req_done(req);
626 return;
627 }
628
629 static int handle_child_recv(struct tevent_req *req,
630 TALLOC_CTX *mem_ctx,
631 uint8_t **buf, ssize_t *len)
632 {
633 struct handle_child_state *state = tevent_req_data(req,
634 struct handle_child_state);
635
636 TEVENT_REQ_RETURN_ON_ERROR(req);
637
638 *buf = talloc_move(mem_ctx, &state->buf);
639 *len = state->len;
640
641 return EOK;
642 }
643
644 static void krb5_get_user_attr_done(struct tevent_req *req);
645 static void krb5_resolve_kdc_done(struct tevent_req *req);
646 static void krb5_resolve_kpasswd_done(struct tevent_req *req);
647 static void krb5_find_ccache_step(struct tevent_req *req);
648 static void krb5_save_ccname_done(struct tevent_req *req);
649 static void krb5_child_done(struct tevent_req *req);
650 static void krb5_pam_handler_cache_done(struct tevent_req *treq);
651 static void krb5_pam_handler_cache_auth_done(struct tevent_req *subreq);
652
653 struct krb5_auth_state {
654 struct tevent_context *ev;
655 struct be_ctx *be_ctx;
656 struct pam_data *pd;
657 struct krb5_ctx *krb5_ctx;
658 struct krb5child_req *kr;
659
660 int pam_status;
661 int dp_err;
662 };
663
664 int krb5_auth_recv(struct tevent_req *req, int *pam_status, int *dp_err)
665 {
666 struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
667
668 *pam_status = state->pam_status;
669 *dp_err = state->dp_err;
670
671 TEVENT_REQ_RETURN_ON_ERROR(req);
672
673 return EOK;
674 }
675
676 struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
677 struct tevent_context *ev,
678 struct be_ctx *be_ctx,
679 struct pam_data *pd,
680 struct krb5_ctx *krb5_ctx)
681 {
682 const char **attrs;
Event var_decl: Declaring variable "ret" without initializer.
Also see events: [uninit_use] | |
683 int ret;
684 struct krb5_auth_state *state;
685 struct tevent_req *req;
686 struct tevent_req *subreq;
687
688
689 req = tevent_req_create(mem_ctx, &state, struct krb5_auth_state);
At conditional (1): "req == NULL": Taking false branch.
|
690 if (req == NULL) {
691 DEBUG(1, ("tevent_req_create failed.\n"));
692 return NULL;
693 }
694
695 state->ev = ev;
696 state->be_ctx = be_ctx;
697 state->pd = pd;
698 state->krb5_ctx = krb5_ctx;
699 state->kr = NULL;
700 state->pam_status = PAM_SYSTEM_ERR;
701 state->dp_err = DP_ERR_FATAL;
702
703
704 switch (state->pd->cmd) {
705 case SSS_PAM_AUTHENTICATE:
706 case SSS_PAM_CHAUTHTOK:
707 break;
At conditional (2): switch case value "247": Taking true branch.
|
708 case SSS_PAM_CHAUTHTOK_PRELIM:
At conditional (3): "state->pd->priv == 1": Taking true branch.
At conditional (4): "state->pd->authtok_size == 0U": Taking true branch.
| |
709 if (state->pd->priv == 1 && state->pd->authtok_size == 0) {
At conditional (5): "4 <= debug_level": Taking true branch.
At conditional (6): "debug_timestamps": Taking true branch.
| |
710 DEBUG(4, ("Password reset by root is not supported.\n"));
711 state->pam_status = PAM_PERM_DENIED;
712 state->dp_err = DP_ERR_OK;
713 goto done;
714 }
715 break;
716 case SSS_PAM_ACCT_MGMT:
717 case SSS_PAM_SETCRED:
718 case SSS_PAM_OPEN_SESSION:
719 case SSS_PAM_CLOSE_SESSION:
720 state->pam_status = PAM_SUCCESS;
721 state->dp_err = DP_ERR_OK;
722 ret = EOK;
723 goto done;
724 break;
725 default:
726 DEBUG(4, ("krb5 does not handles pam task %d.\n", state->pd->cmd));
727 state->pam_status = PAM_MODULE_UNKNOWN;
728 state->dp_err = DP_ERR_OK;
729 ret = EOK;
730 goto done;
731 }
732
733 if (be_is_offline(be_ctx) &&
734 (state->pd->cmd == SSS_PAM_CHAUTHTOK ||
735 state->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM)) {
736 DEBUG(9, ("Password changes are not possible while offline.\n"));
737 state->pam_status = PAM_AUTHINFO_UNAVAIL;
738 state->dp_err = DP_ERR_OFFLINE;
739 ret = EOK;
740 goto done;
741 }
742
743 attrs = talloc_array(state, const char *, 6);
744 if (attrs == NULL) {
745 ret = ENOMEM;
746 goto done;
747 }
748
749 attrs[0] = SYSDB_UPN;
750 attrs[1] = SYSDB_HOMEDIR;
751 attrs[2] = SYSDB_CCACHE_FILE;
752 attrs[3] = SYSDB_UIDNUM;
753 attrs[4] = SYSDB_GIDNUM;
754 attrs[5] = NULL;
755
756 ret = krb5_setup(state, pd, krb5_ctx, &state->kr);
757 if (ret != EOK) {
758 DEBUG(1, ("krb5_setup failed.\n"));
759 goto done;
760 }
761
762 subreq = sysdb_search_user_by_name_send(state, state->ev, be_ctx->sysdb,
763 NULL, be_ctx->domain,
764 state->pd->user, attrs);
765 if (subreq == NULL) {
766 DEBUG(1, ("sysdb_search_user_by_name_send failed.\n"));
767 ret = ENOMEM;
768 goto done;
769 }
770
771 tevent_req_set_callback(subreq, krb5_get_user_attr_done, req);
772
773 return req;
774
775 done:
Event uninit_use: Using uninitialized value "ret".
Also see events: [var_decl] | |
776 if (ret == EOK) {
777 tevent_req_done(req);
778 } else {
779 tevent_req_error(req, ret);
780 }
781 tevent_req_post(req, state->ev);
782 return req;
783 }
784
785 static void krb5_get_user_attr_done(struct tevent_req *subreq)
786 {
787 struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
788 struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
789 struct krb5_ctx *krb5_ctx = state->kr->krb5_ctx;
790 krb5_error_code kerr;
791 int ret;
792 struct pam_data *pd = state->pd;
793 struct krb5child_req *kr =state->kr;
794 const char *ccache_file = NULL;
795 const char *realm;
796 struct ldb_message *msg;
797
798 ret = sysdb_search_user_recv(subreq, state, &msg);
799 talloc_zfree(subreq);
800 if (ret) {
801 state->pam_status = PAM_SYSTEM_ERR;
802 state->dp_err = DP_ERR_OK;
803 tevent_req_error(req, ret);
804 return;
805 }
806
807 realm = dp_opt_get_cstring(krb5_ctx->opts, KRB5_REALM);
808 if (realm == NULL) {
809 DEBUG(1, ("Missing Kerberos realm.\n"));
810 ret = ENOENT;
811 goto failed;
812 }
813
814 kr->upn = ldb_msg_find_attr_as_string(msg, SYSDB_UPN, NULL);
815 if (kr->upn == NULL) {
816 /* NOTE: this is a hack, works only in some environments */
817 kr->upn = talloc_asprintf(kr, "%s@%s", pd->user, realm);
818 if (kr->upn == NULL) {
819 DEBUG(1, ("failed to build simple upn.\n"));
820 ret = ENOMEM;
821 goto failed;
822 }
823 DEBUG(9, ("Using simple UPN [%s].\n", kr->upn));
824 }
825
826 kr->homedir = ldb_msg_find_attr_as_string(msg, SYSDB_HOMEDIR, NULL);
827 if (kr->homedir == NULL) {
828 DEBUG(4, ("Home directory for user [%s] not known.\n", pd->user));
829 }
830
831 kr->uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
832 if (kr->uid == 0) {
833 DEBUG(4, ("UID for user [%s] not known.\n", pd->user));
834 ret = ENOENT;
835 goto failed;
836 }
837
838 kr->gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
839 if (kr->gid == 0) {
840 DEBUG(4, ("GID for user [%s] not known.\n", pd->user));
841 ret = ENOENT;
842 goto failed;
843 }
844
845 ccache_file = ldb_msg_find_attr_as_string(msg, SYSDB_CCACHE_FILE, NULL);
846 if (ccache_file != NULL) {
847 ret = check_if_ccache_file_is_used(kr->uid, ccache_file,
848 &kr->active_ccache_present);
849 if (ret != EOK) {
850 DEBUG(1, ("check_if_ccache_file_is_used failed.\n"));
851 goto failed;
852 }
853
854 kerr = check_for_valid_tgt(ccache_file, realm, kr->upn,
855 &kr->valid_tgt_present);
856 if (kerr != 0) {
857 DEBUG(1, ("check_for_valid_tgt failed.\n"));
858 ret = kerr;
859 goto failed;
860 }
861 } else {
862 kr->active_ccache_present = false;
863 kr->valid_tgt_present = false;
864 DEBUG(4, ("No ccache file for user [%s] found.\n", pd->user));
865 }
866 DEBUG(9, ("Ccache_file is [%s] and is %s active and TGT is %s valid.\n",
867 ccache_file ? ccache_file : "not set",
868 kr->active_ccache_present ? "" : "not",
869 kr->valid_tgt_present ? "" : "not"));
870
871 if (ccache_file != NULL) {
872 kr->ccname = ccache_file;
873 kr->old_ccname = talloc_strdup(kr, ccache_file);
874 if (kr->old_ccname == NULL) {
875 DEBUG(1, ("talloc_strdup failed.\n"));
876 ret = ENOMEM;
877 goto failed;
878 }
879 } else {
880 kr->ccname = NULL;
881 kr->old_ccname = NULL;
882 }
883
884 kr->srv = NULL;
885 kr->kpasswd_srv = NULL;
886 subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
887 krb5_ctx->service->name);
888 if (subreq == NULL) {
889 DEBUG(1, ("be_resolve_server_send failed.\n"));
890 ret = ENOMEM;
891 goto failed;
892 }
893
894 tevent_req_set_callback(subreq, krb5_resolve_kdc_done, req);
895
896 return;
897
898 failed:
899 tevent_req_error(req, ret);
900 }
901
902 static void krb5_resolve_kdc_done(struct tevent_req *subreq)
903 {
904 struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
905 struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
906 struct krb5child_req *kr = state->kr;
907 int ret;
908
909 ret = be_resolve_server_recv(subreq, &kr->srv);
910 talloc_zfree(subreq);
911 if (ret) {
912 /* all servers have been tried and none
913 * was found good, setting offline,
914 * but we still have to call the child to setup
915 * the ccache file. */
916 be_mark_offline(state->be_ctx);
917 kr->is_offline = true;
918 } else {
919 if (state->pd->cmd == SSS_PAM_CHAUTHTOK &&
920 kr->krb5_ctx->kpasswd_service != NULL) {
921 subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
922 kr->krb5_ctx->kpasswd_service->name);
923 if (subreq == NULL) {
924 DEBUG(1, ("be_resolve_server_send failed.\n"));
925 ret = ENOMEM;
926 goto failed;
927 }
928
929 tevent_req_set_callback(subreq, krb5_resolve_kpasswd_done, req);
930
931 return;
932 }
933 }
934
935 krb5_find_ccache_step(req);
936 return;
937
938 failed:
939 tevent_req_error(req, ret);
940 }
941
942 static void krb5_resolve_kpasswd_done(struct tevent_req *subreq)
943 {
944 struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
945 struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
946 int ret;
947
948 ret = be_resolve_server_recv(subreq, &state->kr->kpasswd_srv);
949 talloc_zfree(subreq);
950 if (ret) {
951 /* all kpasswd servers have been tried and none was found good, but the
952 * kdc seems ok. Password changes are not possible but
953 * authentication. We return an PAM error here, but do not mark the
954 * backend offline. */
955 state->pam_status = PAM_AUTHTOK_LOCK_BUSY;
956 state->dp_err = DP_ERR_OK;
957 tevent_req_done(req);
958 return;
959 }
960
961 krb5_find_ccache_step(req);
962 }
963
964 static void krb5_find_ccache_step(struct tevent_req *req)
965 {
966 struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
967 int ret;
968 struct krb5child_req *kr = state->kr;
969 struct pam_data *pd = state->pd;
970 char *msg;
971 bool private_path = false;
972 struct tevent_req *subreq = NULL;
973
974 if (!kr->is_offline) {
975 kr->is_offline = be_is_offline(state->be_ctx);
976 }
977
978 /* The ccache file should be (re)created if one of the following conditions
979 * is true:
980 * - it doesn't exist (kr->ccname == NULL)
981 * - the backend is online and the current ccache file is not used, i.e
982 * the related user is currently not logged in
983 * (!kr->is_offline && !kr->active_ccache_present)
984 * - the backend is offline and the current cache file not used and
985 * it does not contain a valid tgt
986 * (kr->is_offline &&
987 * !kr->active_ccache_present && !kr->valid_tgt_present)
988 */
989 if (kr->ccname == NULL ||
990 (kr->is_offline && !kr->active_ccache_present &&
991 !kr->valid_tgt_present) ||
992 (!kr->is_offline && !kr->active_ccache_present)) {
993 DEBUG(9, ("Recreating ccache file.\n"));
994 kr->ccname = expand_ccname_template(kr, kr,
995 dp_opt_get_cstring(kr->krb5_ctx->opts,
996 KRB5_CCNAME_TMPL),
997 true, &private_path);
998 if (kr->ccname == NULL) {
999 DEBUG(1, ("expand_ccname_template failed.\n"));
1000 ret = ENOMEM;
1001 goto done;
1002 }
1003
1004 ret = create_ccache_dir(kr, kr->ccname,
1005 kr->krb5_ctx->illegal_path_re,
1006 kr->uid, kr->gid, private_path);
1007 if (ret != EOK) {
1008 DEBUG(1, ("create_ccache_dir failed.\n"));
1009 goto done;
1010 }
1011 }
1012
1013 if (kr->is_offline) {
1014 DEBUG(9, ("Preparing for offline operation.\n"));
1015
1016 if (kr->valid_tgt_present || kr->active_ccache_present) {
1017 DEBUG(9, ("Valid TGT available or "
1018 "ccache file is already in use.\n"));
1019 kr->ccname = kr->old_ccname;
1020 msg = talloc_asprintf(pd, "%s=%s", CCACHE_ENV_NAME, kr->ccname);
1021 if (msg == NULL) {
1022 DEBUG(1, ("talloc_asprintf failed.\n"));
1023 } else {
1024 ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(msg) + 1,
1025 (uint8_t *) msg);
1026 if (ret != EOK) {
1027 DEBUG(1, ("pam_add_response failed.\n"));
1028 }
1029 }
1030
1031 if (dp_opt_get_bool(kr->krb5_ctx->opts,
1032 KRB5_STORE_PASSWORD_IF_OFFLINE)) {
1033 subreq = sysdb_cache_auth_send(state, state->ev,
1034 state->be_ctx->sysdb,
1035 state->be_ctx->domain, pd->user,
1036 pd->authtok, pd->authtok_size,
1037 state->be_ctx->cdb, true);
1038 if (subreq == NULL) {
1039 DEBUG(2, ("sysdb_cache_auth_send failed, "
1040 "delayed online authentication not possible.\n"));
1041 /* This is not a fatal error, we continue with standard
1042 * offline authentication. */
1043 } else {
1044 tevent_req_set_callback(subreq,
1045 krb5_pam_handler_cache_auth_done,
1046 req);
1047 return;
1048 }
1049 }
1050
1051 state->pam_status = PAM_AUTHINFO_UNAVAIL;
1052 state->dp_err = DP_ERR_OFFLINE;
1053 ret = EOK;
1054 goto done;
1055 }
1056 }
1057
1058 subreq = handle_child_send(state, state->ev, kr);
1059 if (subreq == NULL) {
1060 DEBUG(1, ("handle_child_send failed.\n"));
1061 ret = ENOMEM;
1062 goto done;
1063 }
1064
1065 tevent_req_set_callback(subreq, krb5_child_done, req);
1066 return;
1067
1068 done:
1069 if (ret == EOK) {
1070 tevent_req_done(req);
1071 } else {
1072 tevent_req_error(req, ret);
1073 }
1074 }
1075
1076 static struct tevent_req *krb5_next_server(struct tevent_req *req);
1077 static struct tevent_req *krb5_next_kdc(struct tevent_req *req);
1078 static struct tevent_req *krb5_next_kpasswd(struct tevent_req *req);
1079
1080 static void krb5_child_done(struct tevent_req *subreq)
1081 {
1082 struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
1083 struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
1084
1085 struct krb5child_req *kr = state->kr;
1086 struct pam_data *pd = state->pd;
1087 int ret;
1088 uint8_t *buf = NULL;
1089 ssize_t len = -1;
1090 ssize_t pref_len;
1091 size_t p;
1092 int32_t msg_status;
1093 int32_t msg_type;
1094 int32_t msg_len;
1095
1096 ret = handle_child_recv(subreq, pd, &buf, &len);
1097 talloc_zfree(kr->timeout_handler);
1098 talloc_zfree(subreq);
1099 if (ret != EOK) {
1100 DEBUG(1, ("child failed (%d [%s])\n", ret, strerror(ret)));
1101 if (ret == ETIMEDOUT) {
1102 if (krb5_next_server(req) == NULL) {
1103 tevent_req_error(req, ENOMEM);
1104 }
1105 } else {
1106 tevent_req_error(req, ret);
1107 }
1108 return;
1109 }
1110
1111 /* A buffer with the following structure is expected.
1112 * int32_t status of the request (required)
1113 * message (zero or more)
1114 *
1115 * A message consists of:
1116 * int32_t type of the message
1117 * int32_t length of the following data
1118 * uint8_t[len] data
1119 */
1120
1121 if ((size_t) len < sizeof(int32_t)) {
1122 DEBUG(1, ("message too short.\n"));
1123 ret = EINVAL;
1124 goto done;
1125 }
1126
1127 p=0;
1128 SAFEALIGN_COPY_INT32(&msg_status, buf+p, &p);
1129
1130 while (p < len) {
1131 SAFEALIGN_COPY_INT32(&msg_type, buf+p, &p);
1132 SAFEALIGN_COPY_INT32(&msg_len, buf+p, &p);
1133
1134 DEBUG(9, ("child response [%d][%d][%d].\n", msg_status, msg_type,
1135 msg_len));
1136
1137 if ((p + msg_len) > len) {
1138 DEBUG(1, ("message format error [%d] > [%d].\n", p+msg_len, len));
1139 ret = EINVAL;
1140 goto done;
1141 }
1142
1143 /* We need to save the name of the credential cache file. To find it
1144 * we check if the data part of a message starts with
1145 * CCACHE_ENV_NAME"=". pref_len also counts the trailing '=' because
1146 * sizeof() counts the trailing '\0' of a string. */
1147 pref_len = sizeof(CCACHE_ENV_NAME);
1148 if (msg_len > pref_len &&
1149 strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", pref_len) == 0) {
1150 kr->ccname = talloc_strndup(kr, (char *) &buf[p+pref_len],
1151 msg_len-pref_len);
1152 if (kr->ccname == NULL) {
1153 DEBUG(1, ("talloc_strndup failed.\n"));
1154 ret = ENOMEM;
1155 goto done;
1156 }
1157 }
1158
1159 ret = pam_add_response(pd, msg_type, msg_len, &buf[p]);
1160 if (ret != EOK) {
1161 /* This is not a fatal error */
1162 DEBUG(1, ("pam_add_response failed.\n"));
1163 }
1164 p += msg_len;
1165
1166 if ((p < len) && (p + 2*sizeof(int32_t) >= len)) {
1167 DEBUG(1, ("The remainder of the message is too short.\n"));
1168 ret = EINVAL;
1169 goto done;
1170 }
1171 }
1172
1173 /* If the child request failed, but did not return an offline error code,
1174 * return with the status */
1175 if (msg_status != PAM_SUCCESS && msg_status != PAM_AUTHINFO_UNAVAIL &&
1176 msg_status != PAM_AUTHTOK_LOCK_BUSY) {
1177 state->pam_status = msg_status;
1178 state->dp_err = DP_ERR_OK;
1179 ret = EOK;
1180 goto done;
1181 } else {
1182 state->pam_status = msg_status;
1183 }
1184
1185 /* If the child request was successful and we run the first pass of the
1186 * change password request just return success. */
1187 if (msg_status == PAM_SUCCESS && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) {
1188 state->pam_status = PAM_SUCCESS;
1189 state->dp_err = DP_ERR_OK;
1190 ret = EOK;
1191 goto done;
1192 }
1193
1194 /* if using a dedicated kpasswd server.. */
1195 if (kr->kpasswd_srv != NULL) {
1196 /* ..which is unreachable by now.. */
1197 if (msg_status == PAM_AUTHTOK_LOCK_BUSY) {
1198 fo_set_port_status(kr->kpasswd_srv, PORT_NOT_WORKING);
1199 /* ..try to resolve next kpasswd server */
1200 if (krb5_next_kpasswd(req) == NULL) {
1201 tevent_req_error(req, ENOMEM);
1202 }
1203 return;
1204 } else {
1205 fo_set_port_status(kr->kpasswd_srv, PORT_WORKING);
1206 }
1207 }
1208
1209 /* if the KDC for auth (PAM_AUTHINFO_UNAVAIL) or
1210 * chpass (PAM_AUTHTOK_LOCK_BUSY) was not available while using KDC
1211 * also for chpass operation... */
1212 if (msg_status == PAM_AUTHINFO_UNAVAIL ||
1213 (kr->kpasswd_srv == NULL && msg_status == PAM_AUTHTOK_LOCK_BUSY)) {
1214 if (kr->srv != NULL) {
1215 fo_set_port_status(kr->srv, PORT_NOT_WORKING);
1216 /* ..try to resolve next KDC */
1217 if (krb5_next_kdc(req) == NULL) {
1218 tevent_req_error(req, ENOMEM);
1219 }
1220 return;
1221 }
1222 } else if (kr->srv != NULL) {
1223 fo_set_port_status(kr->srv, PORT_WORKING);
1224 }
1225
1226 /* Now only a successful authentication or password change is left.
1227 *
1228 * We expect that one of the messages in the received buffer contains
1229 * the name of the credential cache file. */
1230 if (kr->ccname == NULL) {
1231 DEBUG(1, ("Missing ccache name in child response.\n"));
1232 ret = EINVAL;
1233 goto done;
1234 }
1235
1236 if (kr->old_ccname != NULL) {
1237 ret = safe_remove_old_ccache_file(kr->old_ccname, kr->ccname);
1238 if (ret != EOK) {
1239 DEBUG(1, ("Failed to remove old ccache file [%s], please remove it manually.\n"));
1240 }
1241 }
1242
1243 struct sysdb_attrs *attrs;
1244 attrs = sysdb_new_attrs(state);
1245 ret = sysdb_attrs_add_string(attrs, SYSDB_CCACHE_FILE, kr->ccname);
1246 if (ret != EOK) {
1247 DEBUG(1, ("sysdb_attrs_add_string failed.\n"));
1248 goto done;
1249 }
1250
1251 subreq = krb5_save_ccname_send(state, state->ev, state->be_ctx->sysdb,
1252 state->be_ctx->domain, pd->user, kr->ccname);
1253 if (subreq == NULL) {
1254 DEBUG(1, ("krb5_save_ccname_send failed.\n"));
1255 ret = ENOMEM;
1256 goto done;
1257 }
1258
1259 tevent_req_set_callback(subreq, krb5_save_ccname_done, req);
1260 return;
1261 done:
1262 if (ret == EOK) {
1263 tevent_req_done(req);
1264 } else {
1265 tevent_req_error(req, ret);
1266 }
1267 }
1268
1269 static struct tevent_req *krb5_next_server(struct tevent_req *req)
1270 {
1271 struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
1272 struct pam_data *pd = state->pd;
1273 struct tevent_req *next_req = NULL;
1274
1275 switch (pd->cmd) {
1276 case SSS_PAM_AUTHENTICATE:
1277 fo_set_port_status(state->kr->srv, PORT_NOT_WORKING);
1278 next_req = krb5_next_kdc(req);
1279 break;
1280 case SSS_PAM_CHAUTHTOK:
1281 case SSS_PAM_CHAUTHTOK_PRELIM:
1282 if (state->kr->kpasswd_srv) {
1283 fo_set_port_status(state->kr->kpasswd_srv, PORT_NOT_WORKING);
1284 next_req = krb5_next_kpasswd(req);
1285 break;
1286 } else {
1287 fo_set_port_status(state->kr->srv, PORT_NOT_WORKING);
1288 next_req = krb5_next_kdc(req);
1289 break;
1290 }
1291 default:
1292 DEBUG(1, ("Unexpected PAM task\n"));
1293 }
1294
1295 return next_req;
1296 }
1297
1298 static struct tevent_req *krb5_next_kdc(struct tevent_req *req)
1299 {
1300 struct tevent_req *next_req;
1301 struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
1302
1303 next_req = be_resolve_server_send(state, state->ev,
1304 state->be_ctx,
1305 state->krb5_ctx->service->name);
1306 if (next_req == NULL) {
1307 DEBUG(1, ("be_resolve_server_send failed.\n"));
1308 return NULL;
1309 }
1310 tevent_req_set_callback(next_req, krb5_resolve_kdc_done, req);
1311
1312 return next_req;
1313 }
1314
1315 static struct tevent_req *krb5_next_kpasswd(struct tevent_req *req)
1316 {
1317 struct tevent_req *next_req;
1318 struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
1319
1320 next_req = be_resolve_server_send(state, state->ev,
1321 state->be_ctx,
1322 state->krb5_ctx->kpasswd_service->name);
1323 if (next_req == NULL) {
1324 DEBUG(1, ("be_resolve_server_send failed.\n"));
1325 return NULL;
1326 }
1327 tevent_req_set_callback(next_req, krb5_resolve_kpasswd_done, req);
1328
1329 return next_req;
1330 }
1331
1332 static void krb5_save_ccname_done(struct tevent_req *subreq)
1333 {
1334 struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
1335 struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
1336 struct krb5child_req *kr = state->kr;
1337 struct pam_data *pd = state->pd;
1338 int ret;
1339 char *password = NULL;
1340
1341 ret = sysdb_set_user_attr_recv(subreq);
1342 talloc_zfree(subreq);
1343 if (ret != EOK) {
1344 DEBUG(1, ("Saving ccache name failed.\n"));
1345 tevent_req_error(req, ret);
1346 return;
1347 }
1348
1349 if (kr->is_offline) {
1350 if (dp_opt_get_bool(kr->krb5_ctx->opts,KRB5_STORE_PASSWORD_IF_OFFLINE)) {
1351 subreq = sysdb_cache_auth_send(state, state->ev,
1352 state->be_ctx->sysdb,
1353 state->be_ctx->domain, pd->user,
1354 pd->authtok, pd->authtok_size,
1355 state->be_ctx->cdb, true);
1356 if (subreq == NULL) {
1357 DEBUG(2, ("sysdb_cache_auth_send failed, "
1358 "delayed online authentication not possible.\n"));
1359 /* This is not a fatal error, we continue with standard
1360 * offline authentication. */
1361 } else {
1362 tevent_req_set_callback(subreq,
1363 krb5_pam_handler_cache_auth_done, req);
1364 return;
1365 }
1366 }
1367
1368 DEBUG(4, ("Backend is marked offline, retry later!\n"));
1369 state->pam_status = PAM_AUTHINFO_UNAVAIL;
1370 state->dp_err = DP_ERR_OFFLINE;
1371 ret = EOK;
1372 goto done;
1373 }
1374
1375 if (state->be_ctx->domain->cache_credentials == TRUE) {
1376
1377 /* password caching failures are not fatal errors */
1378 state->pam_status = PAM_SUCCESS;
1379 state->dp_err = DP_ERR_OK;
1380
1381 switch(pd->cmd) {
1382 case SSS_PAM_AUTHENTICATE:
1383 case SSS_PAM_CHAUTHTOK_PRELIM:
1384 password = talloc_size(state, pd->authtok_size + 1);
1385 if (password != NULL) {
1386 memcpy(password, pd->authtok, pd->authtok_size);
1387 password[pd->authtok_size] = '\0';
1388 }
1389 break;
1390 case SSS_PAM_CHAUTHTOK:
1391 password = talloc_size(state, pd->newauthtok_size + 1);
1392 if (password != NULL) {
1393 memcpy(password, pd->newauthtok, pd->newauthtok_size);
1394 password[pd->newauthtok_size] = '\0';
1395 }
1396 break;
1397 default:
1398 DEBUG(0, ("unsupported PAM command [%d].\n", pd->cmd));
1399 }
1400
1401 if (password == NULL) {
1402 DEBUG(0, ("password not available, offline auth may not work.\n"));
1403 ret = EOK; /* password caching failures are not fatal errors */
1404 goto done;
1405 }
1406
1407 talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
1408
1409 subreq = sysdb_cache_password_send(state, state->ev,
1410 state->be_ctx->sysdb, NULL,
1411 state->be_ctx->domain, pd->user,
1412 password);
1413 if (subreq == NULL) {
1414 DEBUG(2, ("cache_password_send failed, "
1415 "offline auth may not work.\n"));
1416 ret = EOK; /* password caching failures are not fatal errors */
1417 goto done;
1418 }
1419 tevent_req_set_callback(subreq, krb5_pam_handler_cache_done, req);
1420 return;
1421 }
1422
1423 state->pam_status = PAM_SUCCESS;
1424 state->dp_err = DP_ERR_OK;
1425 ret = EOK;
1426
1427 done:
1428 if (ret == EOK) {
1429 tevent_req_done(req);
1430 } else {
1431 tevent_req_error(req, ret);
1432 }
1433 }
1434
1435 static void krb5_pam_handler_cache_done(struct tevent_req *subreq)
1436 {
1437 struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
1438 int ret;
1439
1440 ret = sysdb_cache_password_recv(subreq);
1441 talloc_zfree(subreq);
1442
1443 /* password caching failures are not fatal errors,
1444 * so we just log it and return */
1445 if (ret) {
1446 DEBUG(2, ("Failed to cache password (%d)[%s]!?\n",
1447 ret, strerror(ret)));
1448 }
1449
1450 tevent_req_done(req);
1451 }
1452
1453 static void krb5_pam_handler_cache_auth_done(struct tevent_req *subreq)
1454 {
1455 struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
1456 struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
1457 struct pam_data *pd = state->pd;
1458 struct krb5_ctx *krb5_ctx = state->kr->krb5_ctx;
1459 int ret;
1460 time_t expire_date;
1461 time_t delayed_until;
1462
1463 ret = sysdb_cache_auth_recv(subreq, &expire_date, &delayed_until);
1464 talloc_zfree(subreq);
1465
1466 if (ret) {
1467 DEBUG(2, ("Offline authentication failed.\n"));
1468 } else {
1469 ret = add_user_to_delayed_online_authentication(krb5_ctx, pd,
1470 state->kr->uid);
1471 if (ret != EOK) {
1472 /* This error is not fatal */
1473 DEBUG(1, ("add_user_to_delayed_online_authentication failed.\n"));
1474 }
1475 }
1476
1477 state->pam_status = PAM_AUTHINFO_UNAVAIL;
1478 state->dp_err = DP_ERR_OFFLINE;
1479
1480 tevent_req_done(req);
1481 }
1482
1483 static void krb_reply(struct be_req *req, int dp_err, int result)
1484 {
1485 req->fn(req, dp_err, result, NULL);
1486 }
1487
1488 void krb5_auth_done(struct tevent_req *req);
1489
1490 void krb5_pam_handler(struct be_req *be_req)
1491 {
1492 struct tevent_req *req;
1493 struct pam_data *pd;
1494 struct krb5_ctx *krb5_ctx;
1495
1496 pd = talloc_get_type(be_req->req_data, struct pam_data);
1497
1498 krb5_ctx = get_krb5_ctx(be_req);
1499 if (krb5_ctx == NULL) {
1500 DEBUG(1, ("Kerberos context not available.\n"));
1501 goto failed;
1502 }
1503
1504 req = krb5_auth_send(be_req, be_req->be_ctx->ev, be_req->be_ctx, pd,
1505 krb5_ctx);
1506 if (req == NULL) {
1507 DEBUG(1, ("krb5_auth_send failed.\n"));
1508 goto failed;
1509 }
1510
1511 tevent_req_set_callback(req, krb5_auth_done, be_req);
1512
1513 return;
1514
1515 failed:
1516 pd->pam_status = PAM_SYSTEM_ERR;
1517 krb_reply(be_req, DP_ERR_FATAL, pd->pam_status);
1518 }
1519
1520 void krb5_auth_done(struct tevent_req *req)
1521 {
1522 int ret;
1523 struct be_req *be_req = tevent_req_callback_data(req, struct be_req);
1524 int pam_status;
1525 int dp_err;
1526 struct pam_data *pd;
1527
1528 pd = talloc_get_type(be_req->req_data, struct pam_data);
1529
1530 ret = krb5_auth_recv(req, &pam_status, &dp_err);
1531 talloc_zfree(req);
1532 if (ret) {
1533 pd->pam_status = PAM_SYSTEM_ERR;
1534 dp_err = DP_ERR_OK;
1535 } else {
1536 pd->pam_status = pam_status;
1537 }
1538
1539 krb_reply(be_req, dp_err, pd->pam_status);
1540 }