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 	}