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