Add journaling restart support, required to produce a robust journaling
[dragonfly.git] / lib / libpam / modules / pam_krb5 / pam_krb5_pass.c
1 /*
2  * pam_krb5_pass.c
3  *
4  * PAM password management functions for pam_krb5
5  *
6  * $FreeBSD: src/lib/libpam/modules/pam_krb5/pam_krb5_pass.c,v 1.1.2.1 2001/06/07 09:37:07 markm Exp $
7  * $DragonFly: src/lib/libpam/modules/pam_krb5/Attic/pam_krb5_pass.c,v 1.3 2004/01/23 14:37:01 joerg Exp $
8  */
9
10 static const char rcsid[] = "$Id: pam_krb5_pass.c,v 1.3 1999/01/19 23:43:11 fcusack Exp $";
11
12 #include <errno.h>
13 #include <stdio.h>      /* sprintf */
14 #include <stdlib.h>     /* malloc */
15 #include <syslog.h>     /* syslog */
16 #include <string.h>
17 #include <security/pam_appl.h>
18 #include <security/pam_modules.h>
19 #include <krb5.h>
20 #include <com_err.h>
21 #include "pam_krb5.h"
22
23 /* A useful logging macro */
24 #define DLOG(error_func, error_msg) \
25 if (debug) \
26     syslog(LOG_DEBUG, "pam_krb5: pam_sm_chauthtok(%s %s): %s: %s", \
27            service, name, error_func, error_msg)
28
29 /* Change a user's password */
30 int
31 pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
32 {
33     krb5_error_code     krbret;
34     krb5_context        pam_context;
35     krb5_creds          creds;
36     krb5_principal      princ;
37     krb5_get_init_creds_opt opts;
38
39     int         result_code;
40     krb5_data   result_code_string, result_string;
41
42     int         pamret, i;
43     char        *name, *service = NULL, *pass = NULL, *pass2;
44     char        *princ_name = NULL;
45     char        *prompt = NULL;
46
47     int debug = 0;
48     int try_first_pass = 0, use_first_pass = 0;
49
50     if (!(flags & PAM_UPDATE_AUTHTOK))
51         return PAM_AUTHTOK_ERR;
52
53     for (i = 0; i < argc; i++) {
54         if (strcmp(argv[i], "debug") == 0)
55             debug = 1;
56         else if (strcmp(argv[i], "try_first_pass") == 0)
57             try_first_pass = 1;
58         else if (strcmp(argv[i], "use_first_pass") == 0)
59             use_first_pass = 1;
60     }
61
62     /* Get username */
63     if ((pam_get_item(pamh, PAM_USER, (const void **) &name)) != 0) {
64         return PAM_SERVICE_ERR;
65     }
66
67     /* Get service name */
68     (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
69     if (!service)
70         service = "unknown";
71
72     DLOG("entry", "");
73
74     if ((krbret = krb5_init_context(&pam_context)) != 0) {
75         DLOG("krb5_init_context()", error_message(krbret));
76         return PAM_SERVICE_ERR;
77     }
78
79     if ((krbret = krb5_init_context(&pam_context)) != 0) {
80         DLOG("krb5_init_context()", error_message(krbret));
81         return PAM_SERVICE_ERR;
82     }
83     krb5_get_init_creds_opt_init(&opts);
84     memset(&creds, 0, sizeof(krb5_creds));
85
86     /* Get principal name */
87     if ((krbret = krb5_parse_name(pam_context, name, &princ)) != 0) {
88         DLOG("krb5_parse_name()", error_message(krbret));
89         pamret = PAM_USER_UNKNOWN;
90         goto cleanup3;
91     }
92
93     /* Now convert the principal name into something human readable */
94     if ((krbret = krb5_unparse_name(pam_context, princ, &princ_name)) != 0) {
95         DLOG("krb5_unparse_name()", error_message(krbret));
96         pamret = PAM_SERVICE_ERR;
97         goto cleanup2;
98     }
99
100     /* Get password */
101     prompt = malloc(16 + strlen(princ_name));
102     if (!prompt) {
103         DLOG("malloc()", "failure");
104         pamret = PAM_BUF_ERR;
105         goto cleanup2;
106     }
107     (void) sprintf(prompt, "Password for %s: ", princ_name);
108
109     if (try_first_pass || use_first_pass)
110         (void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
111
112 get_pass:
113     if (!pass) {
114         try_first_pass = 0;
115         if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, 
116           &pass)) != 0) {
117             DLOG("get_user_info()", pam_strerror(pamh, pamret));
118             pamret = PAM_SERVICE_ERR;
119             goto cleanup2;
120         }
121         /* We have to free pass. */
122         if ((pamret = pam_set_item(pamh, PAM_AUTHTOK, pass)) != 0) {
123             DLOG("pam_set_item()", pam_strerror(pamh, pamret));
124             free(pass);
125             pamret = PAM_SERVICE_ERR;
126             goto cleanup2;
127         }
128         free(pass);
129         /* Now we get it back from the library. */
130         (void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
131     }
132
133     if ((krbret = krb5_get_init_creds_password(pam_context, &creds, princ, 
134       pass, pam_prompter, pamh, 0, "kadmin/changepw", &opts)) != 0) {
135         DLOG("krb5_get_init_creds_password()", error_message(krbret));
136         if (try_first_pass && krbret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
137             pass = NULL;
138             goto get_pass;
139         }
140         pamret = PAM_AUTH_ERR;
141         goto cleanup2;
142     }
143
144     /* Now get the new password */
145     free(prompt);
146     prompt = "Enter new password: ";
147     if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass)) 
148       != 0) {
149         DLOG("get_user_info()", pam_strerror(pamh, pamret));
150         prompt = NULL;
151         pamret = PAM_SERVICE_ERR;
152         goto cleanup;
153     }
154     prompt = "Enter it again: ";
155     if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass2)) 
156       != 0) {
157         DLOG("get_user_info()", pam_strerror(pamh, pamret));
158         prompt = NULL;
159         pamret = PAM_SERVICE_ERR;
160         goto cleanup;
161     }
162     prompt = NULL;
163
164     if (strcmp(pass, pass2) != 0) {
165         DLOG("strcmp()", "passwords not equal");
166         pamret = PAM_AUTHTOK_ERR;
167         goto cleanup;
168     }
169
170     /* Change it */
171     if ((krbret = krb5_change_password(pam_context, &creds, pass,
172       &result_code, &result_code_string, &result_string)) != 0) {
173         DLOG("krb5_change_password()", error_message(krbret));
174         pamret = PAM_AUTHTOK_ERR;
175         goto cleanup;
176     }
177     if (result_code) {
178         DLOG("krb5_change_password() (result_code)", "");
179         pamret = PAM_AUTHTOK_ERR;
180         goto cleanup;
181     }
182
183     if (result_string.data)
184         free(result_string.data);
185     if (result_code_string.data)
186         free(result_code_string.data);
187
188 cleanup:
189     krb5_free_cred_contents(pam_context, &creds);
190 cleanup2:
191     krb5_free_principal(pam_context, princ);
192 cleanup3:
193     if (prompt)
194         free(prompt);
195     if (princ_name)
196         free(princ_name);
197
198     krb5_free_context(pam_context);
199     DLOG("exit", pamret ? "failure" : "success");
200     return pamret;
201 }
202