1    	/*
2    	    Authors:
3    	        Sumit Bose <sbose@redhat.com>
4    	
5    	    Copyright (C) 2009 Red Hat
6    	    Copyright (C) 2010, rhafer@suse.de, Novell Inc.
7    	
8    	    This program is free software; you can redistribute it and/or modify
9    	    it under the terms of the GNU Lesser General Public License as published by
10   	    the Free Software Foundation; either version 3 of the License, or
11   	    (at your option) any later version.
12   	
13   	    This program is distributed in the hope that it will be useful,
14   	    but WITHOUT ANY WARRANTY; without even the implied warranty of
15   	    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   	    GNU Lesser General Public License for more details.
17   	
18   	    You should have received a copy of the GNU Lesser General Public License
19   	    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20   	*/
21   	
22   	#define PAM_SM_AUTH
23   	#define PAM_SM_ACCOUNT
24   	#define PAM_SM_SESSION
25   	#define PAM_SM_PASSWORD
26   	
27   	#ifndef _GNU_SOURCE
28   	#define _GNU_SOURCE
29   	#endif
30   	
31   	#include <sys/types.h>
32   	#include <unistd.h>
33   	#include <stdlib.h>
34   	#include <stdint.h>
35   	#include <stdio.h>
36   	#include <syslog.h>
37   	#include <time.h>
38   	#include <sys/stat.h>
39   	#include <fcntl.h>
40   	#include <errno.h>
41   	#include <locale.h>
42   	#include <stdbool.h>
43   	
44   	#include <security/pam_modules.h>
45   	#include <security/pam_ext.h>
46   	#include <security/pam_modutil.h>
47   	#include "sss_pam_macros.h"
48   	
49   	#include "sss_cli.h"
50   	
51   	#include <libintl.h>
52   	#define _(STRING) dgettext (PACKAGE, STRING)
53   	#include "config.h"
54   	
55   	#define FLAGS_USE_FIRST_PASS (1 << 0)
56   	#define FLAGS_FORWARD_PASS   (1 << 1)
57   	#define FLAGS_USE_AUTHTOK    (1 << 2)
58   	
59   	#define PWEXP_FLAG "pam_sss:password_expired_flag"
60   	
61   	#define PW_RESET_MSG_FILENAME_TEMPLATE SSSD_CONF_DIR"/customize/%s/pam_sss_pw_reset_message.%s"
62   	#define PW_RESET_MSG_MAX_SIZE 4096
63   	
64   	#define OPT_RETRY_KEY "retry="
65   	
66   	struct pam_items {
67   	    const char* pam_service;
68   	    const char* pam_user;
69   	    const char* pam_tty;
70   	    const char* pam_ruser;
71   	    const char* pam_rhost;
72   	    char* pam_authtok;
73   	    char* pam_newauthtok;
74   	    const char* pamstack_authtok;
75   	    const char* pamstack_oldauthtok;
76   	    size_t pam_service_size;
77   	    size_t pam_user_size;
78   	    size_t pam_tty_size;
79   	    size_t pam_ruser_size;
80   	    size_t pam_rhost_size;
81   	    int pam_authtok_type;
82   	    size_t pam_authtok_size;
83   	    int pam_newauthtok_type;
84   	    size_t pam_newauthtok_size;
85   	    pid_t cli_pid;
86   	    const char *login_name;
87   	    char *domain_name;
88   	};
89   	
90   	#define DEBUG_MGS_LEN 1024
91   	#define MAX_AUTHTOK_SIZE (1024*1024)
92   	#define CHECK_AND_RETURN_PI_STRING(s) ((s != NULL && *s != '\0')? s : "(not available)")
93   	
94   	static void logger(pam_handle_t *pamh, int level, const char *fmt, ...) {
95   	    va_list ap;
96   	
97   	    va_start(ap, fmt);
98   	
99   	#ifdef DEBUG
100  	    va_list apd;
101  	    char debug_msg[DEBUG_MGS_LEN];
102  	    int ret;
103  	    va_copy(apd, ap);
104  	
105  	    ret = vsnprintf(debug_msg, DEBUG_MGS_LEN, fmt, apd);
106  	    if (ret >= DEBUG_MGS_LEN) {
107  	        D(("the following message is truncated: %s", debug_msg));
108  	    } else if (ret < 0) {
109  	        D(("vsnprintf failed to format debug message!"));
110  	    } else {
111  	        D((debug_msg));
112  	    }
113  	
114  	    va_end(apd);
115  	#endif
116  	
117  	    pam_vsyslog(pamh, LOG_AUTHPRIV|level, fmt, ap);
118  	
119  	    va_end(ap);
120  	}
121  	
122  	static void free_exp_data(pam_handle_t *pamh, void *ptr, int err)
123  	{
124  	    free(ptr);
125  	    ptr = NULL;
126  	}
127  	
128  	static size_t add_authtok_item(enum pam_item_type type,
129  	                               enum sss_authtok_type authtok_type,
130  	                               const char *tok, const size_t size,
Event noescape: "add_authtok_item" does not free or save its pointer parameter "buf".
Event noescape: "add_authtok_item" does not free or save its pointer parameter "buf".
131  	                               uint8_t *buf) {
132  	    size_t rp=0;
133  	    uint32_t c;
134  	
135  	    if (tok == NULL) return 0;
136  	
137  	    c = type;
138  	    memcpy(&buf[rp], &c, sizeof(uint32_t));
139  	    rp += sizeof(uint32_t);
140  	
141  	    c = size + sizeof(uint32_t);
142  	    memcpy(&buf[rp], &c, sizeof(uint32_t));
143  	    rp += sizeof(uint32_t);
144  	
145  	    c = authtok_type;
146  	    memcpy(&buf[rp], &c, sizeof(uint32_t));
147  	    rp += sizeof(uint32_t);
148  	
149  	    memcpy(&buf[rp], tok, size);
150  	    rp += size;
151  	
152  	    return rp;
153  	}
154  	
155  	
156  	static size_t add_uint32_t_item(enum pam_item_type type, const uint32_t val,
Event noescape: "add_uint32_t_item" does not free or save its pointer parameter "buf".
157  	                                uint8_t *buf) {
158  	    size_t rp=0;
159  	    uint32_t c;
160  	
161  	    c = type;
162  	    memcpy(&buf[rp], &c, sizeof(uint32_t));
163  	    rp += sizeof(uint32_t);
164  	
165  	    c = sizeof(uint32_t);
166  	    memcpy(&buf[rp], &c, sizeof(uint32_t));
167  	    rp += sizeof(uint32_t);
168  	
169  	    c = val;
170  	    memcpy(&buf[rp], &c, sizeof(uint32_t));
171  	    rp += sizeof(uint32_t);
172  	
173  	    return rp;
174  	}
175  	
176  	static size_t add_string_item(enum pam_item_type type, const char *str,
Event noescape: "add_string_item" does not free or save its pointer parameter "buf".
Event noescape: "add_string_item" does not free or save its pointer parameter "buf".
Event noescape: "add_string_item" does not free or save its pointer parameter "buf".
Event noescape: "add_string_item" does not free or save its pointer parameter "buf".
Event noescape: "add_string_item" does not free or save its pointer parameter "buf".
177  	                           const size_t size, uint8_t *buf) {
178  	    size_t rp=0;
179  	    uint32_t c;
180  	
181  	    if (str == NULL || *str == '\0') return 0;
182  	
183  	    c = type;
184  	    memcpy(&buf[rp], &c, sizeof(uint32_t));
185  	    rp += sizeof(uint32_t);
186  	
187  	    c = size;
188  	    memcpy(&buf[rp], &c, sizeof(uint32_t));
189  	    rp += sizeof(uint32_t);
190  	
191  	    memcpy(&buf[rp], str, size);
192  	    rp += size;
193  	
194  	    return rp;
195  	}
196  	
197  	static void overwrite_and_free_pam_items(struct pam_items *pi)
198  	{
199  	    if (pi->pam_authtok != NULL) {
200  	        _pam_overwrite_n((void *)pi->pam_authtok, pi->pam_authtok_size);
201  	        free((void *)pi->pam_authtok);
202  	        pi->pam_authtok = NULL;
203  	    }
204  	
205  	    if (pi->pam_newauthtok != NULL) {
206  	        _pam_overwrite_n((void *)pi->pam_newauthtok,  pi->pam_newauthtok_size);
207  	        free((void *)pi->pam_newauthtok);
208  	        pi->pam_newauthtok = NULL;
209  	    }
210  	
211  	    pi->pamstack_authtok = NULL;
212  	    pi->pamstack_oldauthtok = NULL;
213  	
214  	    free(pi->domain_name);
215  	}
216  	
217  	static int pack_message_v3(struct pam_items *pi, size_t *size,
218  	                           uint8_t **buffer) {
219  	    int len;
220  	    uint8_t *buf;
221  	    int rp;
222  	    uint32_t terminator = SSS_END_OF_PAM_REQUEST;
223  	
224  	    len = sizeof(uint32_t) +
225  	          2*sizeof(uint32_t) + pi->pam_user_size +
226  	          sizeof(uint32_t);
227  	    len += *pi->pam_service != '\0' ?
228  	                2*sizeof(uint32_t) + pi->pam_service_size : 0;
229  	    len += *pi->pam_tty != '\0' ?
230  	                2*sizeof(uint32_t) + pi->pam_tty_size : 0;
231  	    len += *pi->pam_ruser != '\0' ?
232  	                2*sizeof(uint32_t) + pi->pam_ruser_size : 0;
233  	    len += *pi->pam_rhost != '\0' ?
234  	                2*sizeof(uint32_t) + pi->pam_rhost_size : 0;
235  	    len += pi->pam_authtok != NULL ?
236  	                3*sizeof(uint32_t) + pi->pam_authtok_size : 0;
237  	    len += pi->pam_newauthtok != NULL ?
238  	                3*sizeof(uint32_t) + pi->pam_newauthtok_size : 0;
239  	    len += 3*sizeof(uint32_t); /* cli_pid */
240  	
Event alloc_fn: Calling allocation function "malloc".
Event var_assign: Assigning: "buf" = storage returned from "malloc(len)".
Also see events: [leaked_storage][noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape]
241  	    buf = malloc(len);
At conditional (1): "buf == NULL": Taking false branch.
242  	    if (buf == NULL) {
243  	        D(("malloc failed."));
244  	        return PAM_BUF_ERR;
245  	    }
246  	
247  	    rp = 0;
248  	    ((uint32_t *)(&buf[rp]))[0] = SSS_START_OF_PAM_REQUEST;
249  	    rp += sizeof(uint32_t);
250  	
Event noescape: Variable "buf" is not freed or pointed-to in function "add_string_item". [model]
Also see events: [alloc_fn][var_assign][leaked_storage][noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape]
251  	    rp += add_string_item(SSS_PAM_ITEM_USER, pi->pam_user, pi->pam_user_size,
252  	                          &buf[rp]);
253  	
Event noescape: Variable "buf" is not freed or pointed-to in function "add_string_item". [model]
Also see events: [alloc_fn][var_assign][leaked_storage][noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape]
254  	    rp += add_string_item(SSS_PAM_ITEM_SERVICE, pi->pam_service,
255  	                          pi->pam_service_size, &buf[rp]);
256  	
Event noescape: Variable "buf" is not freed or pointed-to in function "add_string_item". [model]
Also see events: [alloc_fn][var_assign][leaked_storage][noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape]
257  	    rp += add_string_item(SSS_PAM_ITEM_TTY, pi->pam_tty, pi->pam_tty_size,
258  	                          &buf[rp]);
259  	
Event noescape: Variable "buf" is not freed or pointed-to in function "add_string_item". [model]
Also see events: [alloc_fn][var_assign][leaked_storage][noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape]
260  	    rp += add_string_item(SSS_PAM_ITEM_RUSER, pi->pam_ruser, pi->pam_ruser_size,
261  	                          &buf[rp]);
262  	
Event noescape: Variable "buf" is not freed or pointed-to in function "add_string_item". [model]
Also see events: [alloc_fn][var_assign][leaked_storage][noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape]
263  	    rp += add_string_item(SSS_PAM_ITEM_RHOST, pi->pam_rhost, pi->pam_rhost_size,
264  	                          &buf[rp]);
265  	
Event noescape: Variable "buf" is not freed or pointed-to in function "add_uint32_t_item". [model]
Also see events: [alloc_fn][var_assign][leaked_storage][noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape]
266  	    rp += add_uint32_t_item(SSS_PAM_ITEM_CLI_PID, (uint32_t) pi->cli_pid,
267  	                            &buf[rp]);
268  	
Event noescape: Variable "buf" is not freed or pointed-to in function "add_authtok_item". [model]
Also see events: [alloc_fn][var_assign][leaked_storage][noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape]
269  	    rp += add_authtok_item(SSS_PAM_ITEM_AUTHTOK, pi->pam_authtok_type,
270  	                           pi->pam_authtok, pi->pam_authtok_size, &buf[rp]);
271  	
Event noescape: Variable "buf" is not freed or pointed-to in function "add_authtok_item". [model]
Also see events: [alloc_fn][var_assign][leaked_storage][noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape]
272  	    rp += add_authtok_item(SSS_PAM_ITEM_NEWAUTHTOK, pi->pam_newauthtok_type,
273  	                           pi->pam_newauthtok, pi->pam_newauthtok_size,
274  	                           &buf[rp]);
275  	
Event noescape: Variable "buf" is not freed or pointed-to in function "memcpy".
Also see events: [alloc_fn][var_assign][leaked_storage][noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape]
276  	    memcpy(&buf[rp], &terminator, sizeof(uint32_t));
277  	    rp += sizeof(uint32_t);
278  	
At conditional (2): "rp != len": Taking true branch.
279  	    if (rp != len) {
280  	        D(("error during packet creation."));
Event leaked_storage: Variable "buf" going out of scope leaks the storage it points to.
Also see events: [alloc_fn][var_assign][noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape][noescape]
281  	        return PAM_BUF_ERR;
282  	    }
283  	
284  	    *size = len;
285  	    *buffer = buf;
286  	
287  	    return 0;
288  	}
289  	
290  	static int null_strcmp(const char *s1, const char *s2) {
291  	    if (s1 == NULL && s2 == NULL) return 0;
292  	    if (s1 == NULL && s2 != NULL) return -1;
293  	    if (s1 != NULL && s2 == NULL) return 1;
294  	    return strcmp(s1, s2);
295  	}
296  	
297  	enum {
298  	    SSS_PAM_CONV_DONE = 0,
299  	    SSS_PAM_CONV_STD,
300  	    SSS_PAM_CONV_REENTER,
301  	};
302  	
303  	static int do_pam_conversation(pam_handle_t *pamh, const int msg_style,
304  	                               const char *msg,
305  	                               const char *reenter_msg,
306  	                               char **answer)
307  	{
308  	    int ret;
309  	    int state = SSS_PAM_CONV_STD;
310  	    struct pam_conv *conv;
311  	    struct pam_message *mesg[1];
312  	    struct pam_response *resp=NULL;
313  	
314  	    if ((msg_style == PAM_TEXT_INFO || msg_style == PAM_ERROR_MSG) &&
315  	        msg == NULL) return PAM_SYSTEM_ERR;
316  	
317  	    if ((msg_style == PAM_PROMPT_ECHO_OFF ||
318  	         msg_style == PAM_PROMPT_ECHO_ON) &&
319  	        (msg == NULL || answer == NULL)) return PAM_SYSTEM_ERR;
320  	
321  	    if (msg_style == PAM_TEXT_INFO || msg_style == PAM_ERROR_MSG) {
322  	        logger(pamh, LOG_INFO, "User %s message: %s",
323  	                               msg_style == PAM_TEXT_INFO ? "info" : "error",
324  	                               msg);
325  	    }
326  	
327  	    ret=pam_get_item(pamh, PAM_CONV, (const void **) &conv);
328  	    if (ret != PAM_SUCCESS) return ret;
329  	
330  	    do {
331  	        mesg[0] = malloc(sizeof(struct pam_message));
332  	        if (mesg[0] == NULL) {
333  	            D(("Malloc failed."));
334  	            return PAM_SYSTEM_ERR;
335  	        }
336  	
337  	        mesg[0]->msg_style = msg_style;
338  	        if (state == SSS_PAM_CONV_REENTER) {
339  	            mesg[0]->msg = reenter_msg;
340  	        } else {
341  	            mesg[0]->msg = msg;
342  	        }
343  	
344  	        ret=conv->conv(1, (const struct pam_message **) mesg, &resp,
345  	                       conv->appdata_ptr);
346  	        free(mesg[0]);
347  	        if (ret != PAM_SUCCESS) {
348  	            D(("Conversation failure: %s.",  pam_strerror(pamh,ret)));
349  	            return ret;
350  	        }
351  	
352  	        if (msg_style == PAM_PROMPT_ECHO_OFF ||
353  	            msg_style == PAM_PROMPT_ECHO_ON) {
354  	            if (resp == NULL) {
355  	                D(("response expected, but resp==NULL"));
356  	                return PAM_SYSTEM_ERR;
357  	            }
358  	
359  	            if (state == SSS_PAM_CONV_REENTER) {
360  	                if (null_strcmp(*answer, resp[0].resp) != 0) {
361  	                    logger(pamh, LOG_NOTICE, "Passwords do not match.");
362  	                    _pam_overwrite((void *)resp[0].resp);
363  	                    free(resp[0].resp);
364  	                    if (*answer != NULL) {
365  	                        _pam_overwrite((void *)*answer);
366  	                        free(*answer);
367  	                        *answer = NULL;
368  	                    }
369  	                    ret = do_pam_conversation(pamh, PAM_ERROR_MSG,
370  	                                              _("Passwords do not match"),
371  	                                              NULL, NULL);
372  	                    if (ret != PAM_SUCCESS) {
373  	                        D(("do_pam_conversation failed."));
374  	                        return PAM_SYSTEM_ERR;
375  	                    }
376  	                    return PAM_CRED_ERR;
377  	                }
378  	                _pam_overwrite((void *)resp[0].resp);
379  	                free(resp[0].resp);
380  	            } else {
381  	                if (resp[0].resp == NULL) {
382  	                    D(("Empty password"));
383  	                    *answer = NULL;
384  	                } else {
385  	                    *answer = strndup(resp[0].resp, MAX_AUTHTOK_SIZE);
386  	                    _pam_overwrite((void *)resp[0].resp);
387  	                    free(resp[0].resp);
388  	                    if(*answer == NULL) {
389  	                        D(("strndup failed"));
390  	                        return PAM_BUF_ERR;
391  	                    }
392  	                }
393  	            }
394  	            free(resp);
395  	            resp = NULL;
396  	        }
397  	
398  	        if (reenter_msg != NULL && state == SSS_PAM_CONV_STD) {
399  	            state = SSS_PAM_CONV_REENTER;
400  	        } else {
401  	            state = SSS_PAM_CONV_DONE;
402  	        }
403  	    } while (state != SSS_PAM_CONV_DONE);
404  	
405  	    return PAM_SUCCESS;
406  	}
407  	
408  	static errno_t display_pw_reset_message(pam_handle_t *pamh,
409  	                                        const char *domain_name,
410  	                                        const char *suffix)
411  	{
412  	    int ret;
413  	    struct stat stat_buf;
414  	    char *msg_buf = NULL;
415  	    int fd = -1;
416  	    size_t size;
417  	    size_t total_len;
418  	    char *filename = NULL;
419  	
420  	    if (strchr(suffix, '/') != NULL || strchr(domain_name, '/') != NULL) {
421  	        D(("Suffix [%s] or domain name [%s] contain illegal character.", suffix,
422  	           domain_name));
423  	        return EINVAL;
424  	    }
425  	
426  	    size = sizeof(PW_RESET_MSG_FILENAME_TEMPLATE) + strlen(domain_name) +
427  	           strlen(suffix);
428  	    filename = malloc(size);
429  	    if (filename == NULL) {
430  	        D(("malloc failed."));
431  	        ret = ENOMEM;
432  	        goto done;
433  	    }
434  	    ret = snprintf(filename, size, PW_RESET_MSG_FILENAME_TEMPLATE, domain_name,
435  	                   suffix);
436  	    if (ret < 0 || ret >= size) {
437  	        D(("snprintf failed."));
438  	        ret = EFAULT;
439  	        goto done;
440  	    }
441  	
442  	    fd = open(filename, O_RDONLY);
443  	    if (fd == -1) {
444  	        ret = errno;
445  	        D(("open failed [%d][%s].\n", ret, strerror(ret)));
446  	        goto done;
447  	    }
448  	
449  	    ret = fstat(fd, &stat_buf);
450  	    if (ret == -1) {
451  	        ret = errno;
452  	        D(("fstat failed [%d][%s].", ret, strerror(ret)));
453  	        goto done;
454  	    }
455  	
456  	    if (!S_ISREG(stat_buf.st_mode)) {
457  	        logger(pamh, LOG_ERR,
458  	               "Password reset message file is not a regular file.");
459  	        ret = EINVAL;
460  	        goto done;
461  	    }
462  	
463  	    if (stat_buf.st_uid != 0 || stat_buf.st_gid != 0 ||
464  	        (stat_buf.st_mode & ~S_IFMT) != 0644) {
465  	        logger(pamh, LOG_ERR,"Permission error, "
466  	               "file [%s] must be owned by root with permissions 0644.",
467  	               filename);
468  	        ret = EPERM;
469  	        goto done;
470  	    }
471  	
472  	    if (stat_buf.st_size > PW_RESET_MSG_MAX_SIZE) {
473  	        logger(pamh, LOG_ERR, "Password reset message file is too large.");
474  	        ret = EFBIG;
475  	        goto done;
476  	    }
477  	
478  	    msg_buf = malloc(stat_buf.st_size + 1);
479  	    if (msg_buf == NULL) {
480  	        D(("malloc failed."));
481  	        ret = ENOMEM;
482  	        goto done;
483  	    }
484  	
485  	
486  	    total_len = 0;
487  	    while (total_len < stat_buf.st_size) {
488  	        ret = read(fd, msg_buf + total_len, stat_buf.st_size - total_len);
489  	        if (ret == -1) {
490  	            if (errno == EINTR) continue;
491  	            ret = errno;
492  	            D(("read failed [%d][%s].", ret, strerror(ret)));
493  	            goto done;
494  	        }
495  	        total_len += ret;
496  	    }
497  	
498  	    ret = close(fd);
499  	    fd = -1;
500  	    if (ret == -1) {
501  	        ret = errno;
502  	        D(("close failed [%d][%s].", ret, strerror(ret)));
503  	    }
504  	
505  	    if (total_len != stat_buf.st_size) {
506  	        D(("read fewer bytes [%d] than expected [%d].", total_len,
507  	           stat_buf.st_size));
508  	        ret = EIO;
509  	        goto done;
510  	    }
511  	
512  	    msg_buf[stat_buf.st_size] = '\0';
513  	
514  	    ret = do_pam_conversation(pamh, PAM_TEXT_INFO, msg_buf, NULL, NULL);
515  	    if (ret != PAM_SUCCESS) {
516  	        D(("do_pam_conversation failed."));
517  	    }
518  	
519  	done:
520  	    if (fd != -1) {
521  	        close(fd);
522  	    }
523  	    free(msg_buf);
524  	    free(filename);
525  	
526  	    return ret;
527  	}
528  	
529  	static errno_t select_pw_reset_message(pam_handle_t *pamh, struct pam_items *pi)
530  	{
531  	    int ret;
532  	    char *locale;
533  	    const char *domain_name;
534  	
535  	    domain_name = pi->domain_name;
536  	    if (domain_name == NULL || *domain_name == '\0') {
537  	        D(("Domain name is unknown."));
538  	        return EINVAL;
539  	    }
540  	
541  	    locale = setlocale(LC_MESSAGES, NULL);
542  	
543  	    ret = -1;
544  	    if (locale != NULL) {
545  	        ret = display_pw_reset_message(pamh, domain_name, locale);
546  	    }
547  	
548  	    if (ret != 0) {
549  	        ret = display_pw_reset_message(pamh, domain_name, "txt");
550  	    }
551  	
552  	    if (ret != 0) {
553  	        ret = do_pam_conversation(pamh, PAM_TEXT_INFO,
554  	                      _("Password reset by root is not supported."),
555  	                      NULL, NULL);
556  	        if (ret != PAM_SUCCESS) {
557  	            D(("do_pam_conversation failed."));
558  	        }
559  	    }
560  	
561  	    return ret;
562  	}
563  	
564  	static int user_info_offline_auth(pam_handle_t *pamh, size_t buflen,
565  	                                  uint8_t *buf)
566  	{
567  	    int ret;
568  	    long long expire_date;
569  	    struct tm tm;
570  	    char expire_str[128];
571  	    char user_msg[256];
572  	
573  	    expire_str[0] = '\0';
574  	
575  	    if (buflen != sizeof(uint32_t) + sizeof(long long)) {
576  	        D(("User info response data has the wrong size"));
577  	        return PAM_BUF_ERR;
578  	    }
579  	
580  	    memcpy(&expire_date, buf + sizeof(uint32_t), sizeof(long long));
581  	
582  	    if (expire_date > 0) {
583  	        if (localtime_r((time_t *) &expire_date, &tm) != NULL) {
584  	            ret = strftime(expire_str, sizeof(expire_str), "%c", &tm);
585  	            if (ret == 0) {
586  	                D(("strftime failed."));
587  	                expire_str[0] = '\0';
588  	            }
589  	        } else {
590  	            D(("localtime_r failed"));
591  	        }
592  	    }
593  	
594  	    ret = snprintf(user_msg, sizeof(user_msg), "%s%s%s.",
595  	               _("Authenticated with cached credentials"),
596  	              expire_str[0] ? _(", your cached password will expire at: ") : "",
597  	              expire_str[0] ? expire_str : "");
598  	    if (ret < 0 || ret >= sizeof(user_msg)) {
599  	        D(("snprintf failed."));
600  	        return PAM_SYSTEM_ERR;
601  	    }
602  	
603  	    ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL);
604  	    if (ret != PAM_SUCCESS) {
605  	        D(("do_pam_conversation failed."));
606  	        return PAM_SYSTEM_ERR;
607  	    }
608  	
609  	    return PAM_SUCCESS;
610  	}
611  	
612  	static int user_info_grace_login(pam_handle_t *pamh,
613  	                                 size_t buflen,
614  	                                 uint8_t *buf)
615  	{
616  	    int ret;
617  	    uint32_t grace;
618  	    char user_msg[256];
619  	
620  	    if (buflen != 2* sizeof(uint32_t)) {
621  	        D(("User info response data has the wrong size"));
622  	        return PAM_BUF_ERR;
623  	    }
624  	    memcpy(&grace, buf + sizeof(uint32_t), sizeof(uint32_t));
625  	    ret = snprintf(user_msg, sizeof(user_msg),
626  	                   _("Your password has expired. "
627  	                     "You have %d grace login(s) remaining."),
628  	                   grace);
629  	    if (ret < 0 || ret >= sizeof(user_msg)) {
630  	        D(("snprintf failed."));
631  	        return PAM_SYSTEM_ERR;
632  	    }
633  	    ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL);
634  	
635  	    if (ret != PAM_SUCCESS) {
636  	        D(("do_pam_conversation failed."));
637  	        return PAM_SYSTEM_ERR;
638  	    }
639  	
640  	    return PAM_SUCCESS;
641  	}
642  	
643  	#define MINSEC 60
644  	#define HOURSEC (60*MINSEC)
645  	#define DAYSEC (24*HOURSEC)
646  	static int user_info_expire_warn(pam_handle_t *pamh,
647  	                                 size_t buflen,
648  	                                 uint8_t *buf)
649  	{
650  	    int ret;
651  	    uint32_t expire;
652  	    char user_msg[256];
653  	    const char* unit="second(s)";
654  	
655  	    if (buflen != 2* sizeof(uint32_t)) {
656  	        D(("User info response data has the wrong size"));
657  	        return PAM_BUF_ERR;
658  	    }
659  	    memcpy(&expire, buf + sizeof(uint32_t), sizeof(uint32_t));
660  	    if (expire >= DAYSEC) {
661  	        expire /= DAYSEC;
662  	        unit = "day(s)";
663  	    } else if (expire >= HOURSEC) {
664  	        expire /= HOURSEC;
665  	        unit = "hour(s)";
666  	    } else if (expire >= MINSEC) {
667  	        expire /= MINSEC;
668  	        unit = "minute(s)";
669  	    }
670  	
671  	    ret = snprintf(user_msg, sizeof(user_msg),
672  	                   _("Your password will expire in %d %s."), expire, unit);
673  	    if (ret < 0 || ret >= sizeof(user_msg)) {
674  	        D(("snprintf failed."));
675  	        return PAM_SYSTEM_ERR;
676  	    }
677  	    ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL);
678  	
679  	    if (ret != PAM_SUCCESS) {
680  	        D(("do_pam_conversation failed."));
681  	        return PAM_SYSTEM_ERR;
682  	    }
683  	
684  	    return PAM_SUCCESS;
685  	}
686  	
687  	static int user_info_offline_auth_delayed(pam_handle_t *pamh, size_t buflen,
688  	                                  uint8_t *buf)
689  	{
690  	    int ret;
691  	    long long delayed_until;
692  	    struct tm tm;
693  	    char delay_str[128];
694  	    char user_msg[256];
695  	
696  	    delay_str[0] = '\0';
697  	
698  	    if (buflen != sizeof(uint32_t) + sizeof(long long)) {
699  	        D(("User info response data has the wrong size"));
700  	        return PAM_BUF_ERR;
701  	    }
702  	
703  	    memcpy(&delayed_until, buf + sizeof(uint32_t), sizeof(long long));
704  	
705  	    if (delayed_until <= 0) {
706  	        D(("User info response data has an invalid value"));
707  	        return PAM_BUF_ERR;
708  	    }
709  	
710  	    if (localtime_r((time_t *) &delayed_until, &tm) != NULL) {
711  	        ret = strftime(delay_str, sizeof(delay_str), "%c", &tm);
712  	        if (ret == 0) {
713  	            D(("strftime failed."));
714  	            delay_str[0] = '\0';
715  	        }
716  	    } else {
717  	        D(("localtime_r failed"));
718  	    }
719  	
720  	    ret = snprintf(user_msg, sizeof(user_msg), "%s%s.",
721  	                   _("Authentication is denied until: "),
722  	                   delay_str);
723  	    if (ret < 0 || ret >= sizeof(user_msg)) {
724  	        D(("snprintf failed."));
725  	        return PAM_SYSTEM_ERR;
726  	    }
727  	
728  	    ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL);
729  	    if (ret != PAM_SUCCESS) {
730  	        D(("do_pam_conversation failed."));
731  	        return PAM_SYSTEM_ERR;
732  	    }
733  	
734  	    return PAM_SUCCESS;
735  	}
736  	
737  	static int user_info_offline_chpass(pam_handle_t *pamh, size_t buflen,
738  	                                    uint8_t *buf)
739  	{
740  	    int ret;
741  	
742  	    if (buflen != sizeof(uint32_t)) {
743  	        D(("User info response data has the wrong size"));
744  	        return PAM_BUF_ERR;
745  	    }
746  	
747  	    ret = do_pam_conversation(pamh, PAM_TEXT_INFO,
748  	                              _("System is offline, password change not possible"),
749  	                              NULL, NULL);
750  	    if (ret != PAM_SUCCESS) {
751  	        D(("do_pam_conversation failed."));
752  	        return PAM_SYSTEM_ERR;
753  	    }
754  	
755  	    return PAM_SUCCESS;
756  	}
757  	
758  	static int user_info_chpass_error(pam_handle_t *pamh, size_t buflen,
759  	                                  uint8_t *buf)
760  	{
761  	    int ret;
762  	    uint32_t msg_len;
763  	    char *user_msg;
764  	    size_t bufsize = 0;
765  	
766  	    if (buflen < 2* sizeof(uint32_t)) {
767  	        D(("User info response data is too short"));
768  	        return PAM_BUF_ERR;
769  	    }
770  	
771  	    memcpy(&msg_len, buf + sizeof(uint32_t), sizeof(uint32_t));
772  	
773  	    if (buflen != 2* sizeof(uint32_t) + msg_len) {
774  	        D(("User info response data has the wrong size"));
775  	        return PAM_BUF_ERR;
776  	    }
777  	
778  	    bufsize = strlen(_("Password change failed. ")) + 1;
779  	
780  	    if (msg_len > 0) {
781  	        bufsize += strlen(_("Server message: ")) + msg_len;
782  	    }
783  	
784  	    user_msg = (char *)malloc(sizeof(char) * bufsize);
785  	    if (!user_msg) {
786  	       D(("Out of memory."));
787  	       return PAM_SYSTEM_ERR;
788  	    }
789  	
790  	    ret = snprintf(user_msg, bufsize, "%s%s%.*s",
791  	                   _("Password change failed. "),
792  	                   msg_len > 0 ? _("Server message: ") : "",
793  	                   msg_len,
794  	                   msg_len > 0 ? (char *)(buf + 2 * sizeof(uint32_t)) : "" );
795  	    if (ret < 0 || ret > bufsize) {
796  	        D(("snprintf failed."));
797  	
798  	        free(user_msg);
799  	        return PAM_SYSTEM_ERR;
800  	    }
801  	
802  	    ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL);
803  	    free(user_msg);
804  	    if (ret != PAM_SUCCESS) {
805  	        D(("do_pam_conversation failed."));
806  	
807  	        return PAM_SYSTEM_ERR;
808  	    }
809  	
810  	    return PAM_SUCCESS;
811  	}
812  	
813  	
814  	static int eval_user_info_response(pam_handle_t *pamh, size_t buflen,
815  	                                   uint8_t *buf)
816  	{
817  	    int ret;
818  	    uint32_t type;
819  	
820  	    if (buflen < sizeof(uint32_t)) {
821  	        D(("User info response data is too short"));
822  	        return PAM_BUF_ERR;
823  	    }
824  	
825  	    memcpy(&type, buf, sizeof(uint32_t));
826  	
827  	    switch(type) {
828  	        case SSS_PAM_USER_INFO_OFFLINE_AUTH:
829  	            ret = user_info_offline_auth(pamh, buflen, buf);
830  	            break;
831  	        case SSS_PAM_USER_INFO_GRACE_LOGIN:
832  	            ret = user_info_grace_login(pamh, buflen, buf);
833  	            break;
834  	        case SSS_PAM_USER_INFO_EXPIRE_WARN:
835  	            ret = user_info_expire_warn(pamh, buflen, buf);
836  	            break;
837  	        case SSS_PAM_USER_INFO_OFFLINE_AUTH_DELAYED:
838  	            ret = user_info_offline_auth_delayed(pamh, buflen, buf);
839  	            break;
840  	        case SSS_PAM_USER_INFO_OFFLINE_CHPASS:
841  	            ret = user_info_offline_chpass(pamh, buflen, buf);
842  	            break;
843  	        case SSS_PAM_USER_INFO_CHPASS_ERROR:
844  	            ret = user_info_chpass_error(pamh, buflen, buf);
845  	            break;
846  	        default:
847  	            D(("Unknown user info type [%d]", type));
848  	            ret = PAM_SYSTEM_ERR;
849  	    }
850  	
851  	    return ret;
852  	}
853  	
854  	static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
855  	                         struct pam_items *pi)
856  	{
857  	    int ret;
858  	    size_t p=0;
859  	    char *env_item;
860  	    int32_t c;
861  	    int32_t type;
862  	    int32_t len;
863  	    int32_t pam_status;
864  	
865  	    if (buflen < (2*sizeof(int32_t))) {
866  	        D(("response buffer is too small"));
867  	        return PAM_BUF_ERR;
868  	    }
869  	
870  	    memcpy(&pam_status, buf+p, sizeof(int32_t));
871  	    p += sizeof(int32_t);
872  	
873  	
874  	    memcpy(&c, buf+p, sizeof(int32_t));
875  	    p += sizeof(int32_t);
876  	
877  	    while(c>0) {
878  	        if (buflen < (p+2*sizeof(int32_t))) {
879  	            D(("response buffer is too small"));
880  	            return PAM_BUF_ERR;
881  	        }
882  	
883  	        memcpy(&type, buf+p, sizeof(int32_t));
884  	        p += sizeof(int32_t);
885  	
886  	        memcpy(&len, buf+p, sizeof(int32_t));
887  	        p += sizeof(int32_t);
888  	
889  	        if (buflen < (p + len)) {
890  	            D(("response buffer is too small"));
891  	            return PAM_BUF_ERR;
892  	        }
893  	
894  	        switch(type) {
895  	            case SSS_PAM_SYSTEM_INFO:
896  	                if (buf[p + (len -1)] != '\0') {
897  	                    D(("system info does not end with \\0."));
898  	                    break;
899  	                }
900  	                logger(pamh, LOG_INFO, "system info: [%s]", &buf[p]);
901  	                break;
902  	            case SSS_PAM_DOMAIN_NAME:
903  	                if (buf[p + (len -1)] != '\0') {
904  	                    D(("domain name does not end with \\0."));
905  	                    break;
906  	                }
907  	                D(("domain name: [%s]", &buf[p]));
908  	                pi->domain_name = strdup((char *) &buf[p]);
909  	                if (pi->domain_name == NULL) {
910  	                    D(("strdup failed"));
911  	                }
912  	                break;
913  	            case SSS_ENV_ITEM:
914  	            case SSS_PAM_ENV_ITEM:
915  	            case SSS_ALL_ENV_ITEM:
916  	                if (buf[p + (len -1)] != '\0') {
917  	                    D(("env item does not end with \\0."));
918  	                    break;
919  	                }
920  	
921  	                D(("env item: [%s]", &buf[p]));
922  	                if (type == SSS_PAM_ENV_ITEM || type == SSS_ALL_ENV_ITEM) {
923  	                    ret = pam_putenv(pamh, (char *)&buf[p]);
924  	                    if (ret != PAM_SUCCESS) {
925  	                        D(("pam_putenv failed."));
926  	                        break;
927  	                    }
928  	                }
929  	
930  	                if (type == SSS_ENV_ITEM || type == SSS_ALL_ENV_ITEM) {
931  	                    env_item = strdup((char *)&buf[p]);
932  	                    if (env_item == NULL) {
933  	                        D(("strdup failed"));
934  	                        break;
935  	                    }
936  	                    ret = putenv(env_item);
937  	                    if (ret == -1) {
938  	                        D(("putenv failed."));
939  	                        break;
940  	                    }
941  	                }
942  	                break;
943  	            case SSS_PAM_USER_INFO:
944  	                ret = eval_user_info_response(pamh, len, &buf[p]);
945  	                if (ret != PAM_SUCCESS) {
946  	                    D(("eval_user_info_response failed"));
947  	                }
948  	                break;
949  	            case SSS_PAM_TEXT_MSG:
950  	                if (buf[p + (len -1)] != '\0') {
951  	                    D(("system info does not end with \\0."));
952  	                    break;
953  	                }
954  	
955  	                ret = do_pam_conversation(pamh, PAM_TEXT_INFO, (char *) &buf[p],
956  	                                          NULL, NULL);
957  	                if (ret != PAM_SUCCESS) {
958  	                    D(("do_pam_conversation failed."));
959  	                }
960  	                break;
961  	            default:
962  	                D(("Unknown response type [%d]", type));
963  	        }
964  	        p += len;
965  	
966  	        --c;
967  	    }
968  	
969  	    return PAM_SUCCESS;
970  	}
971  	
972  	static int get_pam_items(pam_handle_t *pamh, struct pam_items *pi)
973  	{
974  	    int ret;
975  	
976  	    pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY;
977  	    pi->pam_authtok = NULL;
978  	    pi->pam_authtok_size = 0;
979  	    pi->pam_newauthtok_type = SSS_AUTHTOK_TYPE_EMPTY;
980  	    pi->pam_newauthtok = NULL;
981  	    pi->pam_newauthtok_size = 0;
982  	
983  	    ret = pam_get_item(pamh, PAM_SERVICE, (const void **) &(pi->pam_service));
984  	    if (ret != PAM_SUCCESS) return ret;
985  	    if (pi->pam_service == NULL) pi->pam_service="";
986  	    pi->pam_service_size=strlen(pi->pam_service)+1;
987  	
988  	    ret = pam_get_item(pamh, PAM_USER, (const void **) &(pi->pam_user));
989  	    if (ret != PAM_SUCCESS) return ret;
990  	    if (pi->pam_user == NULL) {
991  	        D(("No user found, aborting."));
992  	        return PAM_BAD_ITEM;
993  	    }
994  	    if (strcmp(pi->pam_user, "root") == 0) {
995  	        D(("pam_sss will not handle root."));
996  	        return PAM_USER_UNKNOWN;
997  	    }
998  	    pi->pam_user_size=strlen(pi->pam_user)+1;
999  	
1000 	
1001 	    ret = pam_get_item(pamh, PAM_TTY, (const void **) &(pi->pam_tty));
1002 	    if (ret != PAM_SUCCESS) return ret;
1003 	    if (pi->pam_tty == NULL) pi->pam_tty="";
1004 	    pi->pam_tty_size=strlen(pi->pam_tty)+1;
1005 	
1006 	    ret = pam_get_item(pamh, PAM_RUSER, (const void **) &(pi->pam_ruser));
1007 	    if (ret != PAM_SUCCESS) return ret;
1008 	    if (pi->pam_ruser == NULL) pi->pam_ruser="";
1009 	    pi->pam_ruser_size=strlen(pi->pam_ruser)+1;
1010 	
1011 	    ret = pam_get_item(pamh, PAM_RHOST, (const void **) &(pi->pam_rhost));
1012 	    if (ret != PAM_SUCCESS) return ret;
1013 	    if (pi->pam_rhost == NULL) pi->pam_rhost="";
1014 	    pi->pam_rhost_size=strlen(pi->pam_rhost)+1;
1015 	
1016 	    ret = pam_get_item(pamh, PAM_AUTHTOK,
1017 	                       (const void **) &(pi->pamstack_authtok));
1018 	    if (ret != PAM_SUCCESS) return ret;
1019 	    if (pi->pamstack_authtok == NULL) pi->pamstack_authtok="";
1020 	
1021 	    ret = pam_get_item(pamh, PAM_OLDAUTHTOK,
1022 	                       (const void **) &(pi->pamstack_oldauthtok));
1023 	    if (ret != PAM_SUCCESS) return ret;
1024 	    if (pi->pamstack_oldauthtok == NULL) pi->pamstack_oldauthtok="";
1025 	
1026 	    pi->cli_pid = getpid();
1027 	
1028 	    pi->login_name = pam_modutil_getlogin(pamh);
1029 	    if (pi->login_name == NULL) pi->login_name="";
1030 	
1031 	    pi->domain_name = NULL;
1032 	
1033 	    return PAM_SUCCESS;
1034 	}
1035 	
1036 	static void print_pam_items(struct pam_items *pi)
1037 	{
1038 	    if (pi == NULL) return;
1039 	
1040 	    D(("Service: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_service)));
1041 	    D(("User: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_user)));
1042 	    D(("Tty: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_tty)));
1043 	    D(("Ruser: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_ruser)));
1044 	    D(("Rhost: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_rhost)));
1045 	    D(("Pamstack_Authtok: %s",
1046 	            CHECK_AND_RETURN_PI_STRING(pi->pamstack_authtok)));
1047 	    D(("Pamstack_Oldauthtok: %s",
1048 	            CHECK_AND_RETURN_PI_STRING(pi->pamstack_oldauthtok)));
1049 	    D(("Authtok: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_authtok)));
1050 	    D(("Newauthtok: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_newauthtok)));
1051 	    D(("Cli_PID: %d", pi->cli_pid));
1052 	}
1053 	
1054 	static int send_and_receive(pam_handle_t *pamh, struct pam_items *pi,
1055 	                            enum sss_cli_command task)
1056 	{
1057 	    int ret;
1058 	    int errnop;
1059 	    struct sss_cli_req_data rd;
1060 	    uint8_t *buf = NULL;
1061 	    uint8_t *repbuf = NULL;
1062 	    size_t replen;
1063 	    int pam_status = PAM_SYSTEM_ERR;
1064 	
1065 	    print_pam_items(pi);
1066 	
1067 	    ret = pack_message_v3(pi, &rd.len, &buf);
1068 	    if (ret != 0) {
1069 	        D(("pack_message failed."));
1070 	        pam_status = PAM_SYSTEM_ERR;
1071 	        goto done;
1072 	    }
1073 	    rd.data = buf;
1074 	
1075 	    errnop = 0;
1076 	    ret = sss_pam_make_request(task, &rd, &repbuf, &replen, &errnop);
1077 	
1078 	    if (ret != NSS_STATUS_SUCCESS) {
1079 	        if (errnop != 0) {
1080 	            logger(pamh, LOG_ERR, "Request to sssd failed. %s", ssscli_err2string(errnop));
1081 	        }
1082 	        pam_status = PAM_SYSTEM_ERR;
1083 	        goto done;
1084 	    }
1085 	
1086 	/* FIXME: add an end signature */
1087 	    if (replen < (2*sizeof(int32_t))) {
1088 	        D(("response not in expected format."));
1089 	        pam_status = PAM_SYSTEM_ERR;
1090 	        goto done;
1091 	    }
1092 	
1093 	    pam_status = ((int32_t *)repbuf)[0];
1094 	    ret = eval_response(pamh, replen, repbuf, pi);
1095 	    if (ret != PAM_SUCCESS) {
1096 	        D(("eval_response failed."));
1097 	        pam_status = ret;
1098 	        goto done;
1099 	    }
1100 	
1101 	    switch (task) {
1102 	        case SSS_PAM_AUTHENTICATE:
1103 	            logger(pamh, (pam_status == PAM_SUCCESS ? LOG_INFO : LOG_NOTICE),
1104 	                   "authentication %s; logname=%s uid=%lu euid=%d tty=%s "
1105 	                   "ruser=%s rhost=%s user=%s",
1106 	                   pam_status == PAM_SUCCESS ? "success" : "failure",
1107 	                   pi->login_name, getuid(), (unsigned long) geteuid(),
1108 	                   pi->pam_tty, pi->pam_ruser, pi->pam_rhost, pi->pam_user);
1109 	            if (pam_status != PAM_SUCCESS) {
1110 	                   logger(pamh, LOG_NOTICE, "received for user %s: %d (%s)",
1111 	                          pi->pam_user, pam_status,
1112 	                          pam_strerror(pamh,pam_status));
1113 	            }
1114 	            break;
1115 	        case SSS_PAM_CHAUTHTOK_PRELIM:
1116 	            if (pam_status != PAM_SUCCESS) {
1117 	                   logger(pamh, LOG_NOTICE,
1118 	                          "Authentication failed for user %s: %d (%s)",
1119 	                          pi->pam_user, pam_status,
1120 	                          pam_strerror(pamh,pam_status));
1121 	            }
1122 	            break;
1123 	        case SSS_PAM_CHAUTHTOK:
1124 	            if (pam_status != PAM_SUCCESS) {
1125 	                   logger(pamh, LOG_NOTICE,
1126 	                          "Password change failed for user %s: %d (%s)",
1127 	                          pi->pam_user, pam_status,
1128 	                          pam_strerror(pamh,pam_status));
1129 	            }
1130 	            break;
1131 	        case SSS_PAM_ACCT_MGMT:
1132 	            if (pam_status != PAM_SUCCESS) {
1133 	                   logger(pamh, LOG_NOTICE,
1134 	                          "Access denied for user %s: %d (%s)",
1135 	                          pi->pam_user, pam_status,
1136 	                          pam_strerror(pamh,pam_status));
1137 	            }
1138 	            break;
1139 	        case SSS_PAM_SETCRED:
1140 	        case SSS_PAM_OPEN_SESSION:
1141 	        case SSS_PAM_CLOSE_SESSION:
1142 	            break;
1143 	        default:
1144 	            D(("Illegal task [%d]", task));
1145 	            return PAM_SYSTEM_ERR;
1146 	    }
1147 	
1148 	done:
1149 	    if (buf != NULL ) {
1150 	        _pam_overwrite_n((void *)buf, rd.len);
1151 	        free(buf);
1152 	    }
1153 	    free(repbuf);
1154 	
1155 	    return pam_status;
1156 	}
1157 	
1158 	static int prompt_password(pam_handle_t *pamh, struct pam_items *pi,
1159 	                           const char *prompt)
1160 	{
1161 	    int ret;
1162 	    char *answer = NULL;
1163 	
1164 	    ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, NULL, &answer);
1165 	    if (ret != PAM_SUCCESS) {
1166 	        D(("do_pam_conversation failed."));
1167 	        return ret;
1168 	    }
1169 	
1170 	    if (answer == NULL) {
1171 	        pi->pam_authtok = NULL;
1172 	        pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY;
1173 	        pi->pam_authtok_size=0;
1174 	    } else {
1175 	        pi->pam_authtok = strdup(answer);
1176 	        _pam_overwrite((void *)answer);
1177 	        free(answer);
1178 	        answer=NULL;
1179 	        if (pi->pam_authtok == NULL) {
1180 	            return PAM_BUF_ERR;
1181 	        }
1182 	        pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
1183 	        pi->pam_authtok_size=strlen(pi->pam_authtok);
1184 	    }
1185 	
1186 	    return PAM_SUCCESS;
1187 	}
1188 	
1189 	static int prompt_new_password(pam_handle_t *pamh, struct pam_items *pi)
1190 	{
1191 	    int ret;
1192 	    char *answer = NULL;
1193 	
1194 	    ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF,
1195 	                              _("New Password: "),
1196 	                              _("Reenter new Password: "),
1197 	                              &answer);
1198 	    if (ret != PAM_SUCCESS) {
1199 	        D(("do_pam_conversation failed."));
1200 	        return ret;
1201 	    }
1202 	    if (answer == NULL) {
1203 	        pi->pam_newauthtok = NULL;
1204 	        pi->pam_newauthtok_type = SSS_AUTHTOK_TYPE_EMPTY;
1205 	        pi->pam_newauthtok_size=0;
1206 	    } else {
1207 	        pi->pam_newauthtok = strdup(answer);
1208 	        _pam_overwrite((void *)answer);
1209 	        free(answer);
1210 	        answer=NULL;
1211 	        if (pi->pam_newauthtok == NULL) {
1212 	            return PAM_BUF_ERR;
1213 	        }
1214 	        pi->pam_newauthtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
1215 	        pi->pam_newauthtok_size=strlen(pi->pam_newauthtok);
1216 	    }
1217 	
1218 	    return PAM_SUCCESS;
1219 	}
1220 	
1221 	static void eval_argv(pam_handle_t *pamh, int argc, const char **argv,
1222 	                      uint32_t *flags, int *retries)
1223 	{
1224 	    char *ep;
1225 	
1226 	    for (; argc-- > 0; ++argv) {
1227 	        if (strcmp(*argv, "forward_pass") == 0) {
1228 	            *flags |= FLAGS_FORWARD_PASS;
1229 	        } else if (strcmp(*argv, "use_first_pass") == 0) {
1230 	            *flags |= FLAGS_USE_FIRST_PASS;
1231 	        } else if (strcmp(*argv, "use_authtok") == 0) {
1232 	            *flags |= FLAGS_USE_AUTHTOK;
1233 	        } else if (strncmp(*argv, OPT_RETRY_KEY, strlen(OPT_RETRY_KEY)) == 0) {
1234 	            if (*(*argv+6) == '\0') {
1235 	                logger(pamh, LOG_ERR, "Missing argument to option retry.");
1236 	                *retries = 0;
1237 	            } else {
1238 	                errno = 0;
1239 	                *retries = strtol(*argv+6, &ep, 10);
1240 	                if (errno != 0) {
1241 	                    D(("strtol failed [%d][%s]", errno, strerror(errno)));
1242 	                    *retries = 0;
1243 	                }
1244 	                if (*ep != '\0') {
1245 	                    logger(pamh, LOG_ERR, "Argument to option retry contains "
1246 	                                          "extra characters.");
1247 	                    *retries = 0;
1248 	                }
1249 	                if (*retries < 0) {
1250 	                    logger(pamh, LOG_ERR, "Argument to option retry must not "
1251 	                                          "be negative.");
1252 	                    *retries = 0;
1253 	                }
1254 	            }
1255 	        } else {
1256 	            logger(pamh, LOG_WARNING, "unknown option: %s", *argv);
1257 	        }
1258 	    }
1259 	
1260 	    return;
1261 	}
1262 	
1263 	static int get_authtok_for_authentication(pam_handle_t *pamh,
1264 	                                          struct pam_items *pi,
1265 	                                          uint32_t flags)
1266 	{
1267 	    int ret;
1268 	
1269 	    if (flags & FLAGS_USE_FIRST_PASS) {
1270 	        pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
1271 	        pi->pam_authtok = strdup(pi->pamstack_authtok);
1272 	        if (pi->pam_authtok == NULL) {
1273 	            D(("option use_first_pass set, but no password found"));
1274 	            return PAM_BUF_ERR;
1275 	        }
1276 	        pi->pam_authtok_size = strlen(pi->pam_authtok);
1277 	    } else {
1278 	        ret = prompt_password(pamh, pi, _("Password: "));
1279 	        if (ret != PAM_SUCCESS) {
1280 	            D(("failed to get password from user"));
1281 	            return ret;
1282 	        }
1283 	
1284 	        if (flags & FLAGS_FORWARD_PASS) {
1285 	            ret = pam_set_item(pamh, PAM_AUTHTOK, pi->pam_authtok);
1286 	            if (ret != PAM_SUCCESS) {
1287 	                D(("Failed to set PAM_AUTHTOK [%s], "
1288 	                   "authtok may not be available for other modules",
1289 	                   pam_strerror(pamh,ret)));
1290 	            }
1291 	        }
1292 	    }
1293 	
1294 	    return PAM_SUCCESS;
1295 	}
1296 	
1297 	static int get_authtok_for_password_change(pam_handle_t *pamh,
1298 	                                           struct pam_items *pi,
1299 	                                           uint32_t flags,
1300 	                                           int pam_flags)
1301 	{
1302 	    int ret;
1303 	    int *exp_data = NULL;
1304 	    pam_get_data(pamh, PWEXP_FLAG, (const void **) &exp_data);
1305 	    
1306 	    /* we query for the old password during PAM_PRELIM_CHECK to make
1307 	     * pam_sss work e.g. with pam_cracklib */
1308 	    if (pam_flags & PAM_PRELIM_CHECK) {
1309 	        if ( (getuid() != 0 || exp_data ) && !(flags & FLAGS_USE_FIRST_PASS)) {
1310 	            ret = prompt_password(pamh, pi, _("Current Password: "));
1311 	            if (ret != PAM_SUCCESS) {
1312 	                D(("failed to get password from user"));
1313 	                return ret;
1314 	            }
1315 	
1316 	            ret = pam_set_item(pamh, PAM_OLDAUTHTOK, pi->pam_authtok);
1317 	            if (ret != PAM_SUCCESS) {
1318 	                D(("Failed to set PAM_OLDAUTHTOK [%s], "
1319 	                   "oldauthtok may not be available",
1320 	                   pam_strerror(pamh,ret)));
1321 	                   return ret;
1322 	            }
1323 	        }
1324 	
1325 	        return PAM_SUCCESS;
1326 	    }
1327 	
1328 	    if (pi->pamstack_oldauthtok == NULL) {
1329 	        if (getuid() != 0) {
1330 	            D(("no password found for chauthtok"));
1331 	            return PAM_BUF_ERR;
1332 	        } else {
1333 	            pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY;
1334 	            pi->pam_authtok = NULL;
1335 	            pi->pam_authtok_size = 0;
1336 	        }
1337 	    } else {
1338 	        pi->pam_authtok = strdup(pi->pamstack_oldauthtok);
1339 	        pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
1340 	        pi->pam_authtok_size = strlen(pi->pam_authtok);
1341 	    }
1342 	
1343 	    if (flags & FLAGS_USE_AUTHTOK) {
1344 	        pi->pam_newauthtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
1345 	        pi->pam_newauthtok =  strdup(pi->pamstack_authtok);
1346 	        if (pi->pam_newauthtok == NULL) {
1347 	            D(("option use_authtok set, but no new password found"));
1348 	            return PAM_BUF_ERR;
1349 	        }
1350 	        pi->pam_newauthtok_size = strlen(pi->pam_newauthtok);
1351 	    } else {
1352 	        ret = prompt_new_password(pamh, pi);
1353 	        if (ret != PAM_SUCCESS) {
1354 	            D(("failed to get new password from user"));
1355 	            return ret;
1356 	        }
1357 	
1358 	        if (flags & FLAGS_FORWARD_PASS) {
1359 	            ret = pam_set_item(pamh, PAM_AUTHTOK, pi->pam_newauthtok);
1360 	            if (ret != PAM_SUCCESS) {
1361 	                D(("Failed to set PAM_AUTHTOK [%s], "
1362 	                   "oldauthtok may not be available",
1363 	                   pam_strerror(pamh,ret)));
1364 	            }
1365 	        }
1366 	    }
1367 	
1368 	    return PAM_SUCCESS;
1369 	}
1370 	
1371 	static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
1372 	                   int pam_flags, int argc, const char **argv)
1373 	{
1374 	    int ret;
1375 	    int pam_status;
1376 	    struct pam_items pi;
1377 	    uint32_t flags = 0;
1378 	    int *exp_data;
1379 	    bool retry = false;
1380 	    int retries = 0;
1381 	
1382 	    bindtextdomain(PACKAGE, LOCALEDIR);
1383 	
1384 	    D(("Hello pam_sssd: %d", task));
1385 	
1386 	    eval_argv(pamh, argc, argv, &flags, &retries);
1387 	
1388 	    ret = get_pam_items(pamh, &pi);
1389 	    if (ret != PAM_SUCCESS) {
1390 	        D(("get items returned error: %s", pam_strerror(pamh,ret)));
1391 	        return ret;
1392 	    }
1393 	
1394 	    do {
1395 	        retry = false;
1396 	
1397 	        switch(task) {
1398 	            case SSS_PAM_AUTHENTICATE:
1399 	                ret = get_authtok_for_authentication(pamh, &pi, flags);
1400 	                if (ret != PAM_SUCCESS) {
1401 	                    D(("failed to get authentication token: %s",
1402 	                       pam_strerror(pamh, ret)));
1403 	                    return ret;
1404 	                }
1405 	                break;
1406 	            case SSS_PAM_CHAUTHTOK:
1407 	                ret = get_authtok_for_password_change(pamh, &pi, flags, pam_flags);
1408 	                if (ret != PAM_SUCCESS) {
1409 	                    D(("failed to get tokens for password change: %s",
1410 	                       pam_strerror(pamh, ret)));
1411 	                    return ret;
1412 	                }
1413 	                if (pam_flags & PAM_PRELIM_CHECK) {
1414 	                    task = SSS_PAM_CHAUTHTOK_PRELIM;
1415 	                }
1416 	                break;
1417 	            case SSS_PAM_ACCT_MGMT:
1418 	            case SSS_PAM_SETCRED:
1419 	            case SSS_PAM_OPEN_SESSION:
1420 	            case SSS_PAM_CLOSE_SESSION:
1421 	                break;
1422 	            default:
1423 	                D(("Illegal task [%d]", task));
1424 	                return PAM_SYSTEM_ERR;
1425 	        }
1426 	
1427 	        pam_status = send_and_receive(pamh, &pi, task);
1428 	
1429 	        switch (task) {
1430 	            case SSS_PAM_AUTHENTICATE:
1431 	                /* We allow sssd to send the return code PAM_NEW_AUTHTOK_REQD during
1432 	                 * authentication, see sss_cli.h for details */
1433 	                if (pam_status == PAM_NEW_AUTHTOK_REQD) {
1434 	                    D(("Authtoken expired, trying to change it"));
1435 	
1436 	                    exp_data = malloc(sizeof(int));
1437 	                    if (exp_data == NULL) {
1438 	                        D(("malloc failed."));
1439 	                        pam_status = PAM_BUF_ERR;
1440 	                        break;
1441 	                    }
1442 	                    *exp_data = 1;
1443 	
1444 	                    pam_status = pam_set_data(pamh, PWEXP_FLAG, exp_data,
1445 	                                              free_exp_data);
1446 	                    if (pam_status != PAM_SUCCESS) {
1447 	                        D(("pam_set_data failed."));
1448 	                    }
1449 	                }
1450 	                break;
1451 	            case SSS_PAM_ACCT_MGMT:
1452 	                if (pam_status == PAM_SUCCESS &&
1453 	                    pam_get_data(pamh, PWEXP_FLAG, (const void **) &exp_data) ==
1454 	                                                                      PAM_SUCCESS) {
1455 	                    ret = do_pam_conversation(pamh, PAM_TEXT_INFO,
1456 	                                   _("Password expired. Change your password now."),
1457 	                                   NULL, NULL);
1458 	                    if (ret != PAM_SUCCESS) {
1459 	                        D(("do_pam_conversation failed."));
1460 	                    }
1461 	                    pam_status = PAM_NEW_AUTHTOK_REQD;
1462 	                }
1463 	                break;
1464 	            case SSS_PAM_CHAUTHTOK:
1465 	                if (pam_status != PAM_SUCCESS && pam_status != PAM_USER_UNKNOWN) {
1466 	                    ret = pam_set_item(pamh, PAM_AUTHTOK, NULL);
1467 	                    if (ret != PAM_SUCCESS) {
1468 	                        D(("Failed to unset PAM_AUTHTOK [%s]",
1469 	                           pam_strerror(pamh,ret)));
1470 	                    }
1471 	                    ret = pam_set_item(pamh, PAM_OLDAUTHTOK, NULL);
1472 	                    if (ret != PAM_SUCCESS) {
1473 	                        D(("Failed to unset PAM_OLDAUTHTOK [%s]",
1474 	                           pam_strerror(pamh,ret)));
1475 	                    }
1476 	                }
1477 	                break;
1478 	            case SSS_PAM_CHAUTHTOK_PRELIM:
1479 	                if (pam_status == PAM_PERM_DENIED && pi.pam_authtok_size == 0 &&
1480 	                    getuid() == 0 &&
1481 	                    pam_get_data(pamh, PWEXP_FLAG, (const void **) &exp_data) !=
1482 	                                                                      PAM_SUCCESS) {
1483 	
1484 	                    ret = select_pw_reset_message(pamh, &pi);
1485 	                    if (ret != 0) {
1486 	                        D(("select_pw_reset_message failed.\n"));
1487 	                    }
1488 	                }
1489 	            default:
1490 	                /* nothing to do */
1491 	                break;
1492 	        }
1493 	
1494 	        overwrite_and_free_pam_items(&pi);
1495 	
1496 	        D(("retries [%d].", retries));
1497 	
1498 	        if (pam_status != PAM_SUCCESS &&
1499 	            (task == SSS_PAM_AUTHENTICATE || task == SSS_PAM_CHAUTHTOK_PRELIM) &&
1500 	            retries > 0) {
1501 	            retry = true;
1502 	            retries--;
1503 	
1504 	            flags &= !FLAGS_USE_FIRST_PASS;
1505 	            ret = pam_set_item(pamh, PAM_AUTHTOK, NULL);
1506 	            if (ret != PAM_SUCCESS) {
1507 	                D(("Failed to unset PAM_AUTHTOK [%s]",
1508 	                   pam_strerror(pamh,ret)));
1509 	            }
1510 	            ret = pam_set_item(pamh, PAM_OLDAUTHTOK, NULL);
1511 	            if (ret != PAM_SUCCESS) {
1512 	                D(("Failed to unset PAM_OLDAUTHTOK [%s]",
1513 	                   pam_strerror(pamh,ret)));
1514 	            }
1515 	        }
1516 	    } while(retry);
1517 	
1518 	    return pam_status;
1519 	}
1520 	
1521 	PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
1522 	                                   const char **argv )
1523 	{
1524 	    return pam_sss(SSS_PAM_AUTHENTICATE, pamh, flags, argc, argv);
1525 	}
1526 	
1527 	
1528 	PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
1529 	                              const char **argv )
1530 	{
1531 	    return pam_sss(SSS_PAM_SETCRED, pamh, flags, argc, argv);
1532 	}
1533 	
1534 	PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc,
1535 	                                const char **argv )
1536 	{
1537 	    return pam_sss(SSS_PAM_ACCT_MGMT, pamh, flags, argc, argv);
1538 	}
1539 	
1540 	PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc,
1541 	                                const char **argv )
1542 	{
1543 	    return pam_sss(SSS_PAM_CHAUTHTOK, pamh, flags, argc, argv);
1544 	}
1545 	
1546 	PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc,
1547 	                                   const char **argv )
1548 	{
1549 	    return pam_sss(SSS_PAM_OPEN_SESSION, pamh, flags, argc, argv);
1550 	}
1551 	
1552 	PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc,
1553 	                                    const char **argv )
1554 	{
1555 	    return pam_sss(SSS_PAM_CLOSE_SESSION, pamh, flags, argc, argv);
1556 	}
1557 	
1558 	
1559 	#ifdef PAM_STATIC
1560 	
1561 	/* static module data */
1562 	
1563 	struct pam_module _pam_sssd_modstruct ={
1564 	     "pam_sssd",
1565 	     pam_sm_authenticate,
1566 	     pam_sm_setcred,
1567 	     pam_sm_acct_mgmt,
1568 	     pam_sm_open_session,
1569 	     pam_sm_close_session,
1570 	     pam_sm_chauthtok
1571 	};
1572 	
1573 	#endif