krb5_passwd.c revision 1.17.8.1 1 /* $NetBSD: krb5_passwd.c,v 1.17.8.1 2009/05/13 19:20:00 jym Exp $ */
2
3 /*
4 * Copyright (c) 2000, 2005 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Johan Danielsson; and by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /* uses the `Kerberos Change Password Protocol' */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <pwd.h>
41 #include <unistd.h>
42
43 #include <openssl/ui.h>
44 #include <krb5.h>
45
46 #include "extern.h"
47
48 #ifdef USE_PAM
49
50 void
51 pwkrb5_usage(const char *prefix)
52 {
53
54 (void) fprintf(stderr, "%s %s [-d krb5 | -k] [principal]\n",
55 prefix, getprogname());
56 }
57
58 void
59 pwkrb5_argv0_usage(const char *prefix)
60 {
61
62 (void) fprintf(stderr, "%s %s [principal]\n",
63 prefix, getprogname());
64 }
65
66 void
67 pwkrb5_process(const char *username, int argc, char **argv)
68 {
69 krb5_context context;
70 krb5_error_code ret;
71 krb5_get_init_creds_opt opt;
72 krb5_principal principal;
73 krb5_creds cred;
74 int result_code;
75 krb5_data result_code_string, result_string;
76 char pwbuf[BUFSIZ];
77 int ch;
78
79 while ((ch = getopt(argc, argv, "5ku:")) != -1) {
80 switch (ch) {
81 case '5':
82 /*
83 * Compatibility option that historically
84 * specified to use Kerberos 5. Silently
85 * ignore it.
86 */
87 break;
88
89 case 'k':
90 /*
91 * Absorb the -k that may have gotten us here.
92 */
93 break;
94
95 case 'u':
96 /*
97 * Historical option to specify principal.
98 */
99 username = optarg;
100 break;
101
102 default:
103 usage();
104 /* NOTREACHED */
105 }
106 }
107
108 argc -= optind;
109 argv += optind;
110
111 switch (argc) {
112 case 0:
113 /* username already provided */
114 break;
115 case 1:
116 /* overrides -u <principal> */
117 username = argv[0];
118 break;
119 default:
120 usage();
121 /* NOTREACHED */
122 }
123
124 ret = krb5_init_context(&context);
125 if (ret != 0) {
126 if (ret == ENXIO)
127 errx(1, "Kerberos 5 not in use.");
128 warnx("Unable to initialize Kerberos 5: %s",
129 krb5_get_err_text(context, ret));
130 goto bad;
131 }
132
133 krb5_get_init_creds_opt_init(&opt);
134
135 krb5_get_init_creds_opt_set_tkt_life(&opt, 300L);
136 krb5_get_init_creds_opt_set_forwardable(&opt, FALSE);
137 krb5_get_init_creds_opt_set_proxiable(&opt, FALSE);
138
139 ret = krb5_parse_name(context, username, &principal);
140 if (ret) {
141 warnx("failed to parse principal: %s",
142 krb5_get_err_text(context, ret));
143 goto bad;
144 }
145
146 ret = krb5_get_init_creds_password(context,
147 &cred,
148 principal,
149 NULL,
150 krb5_prompter_posix,
151 NULL,
152 0L,
153 "kadmin/changepw",
154 &opt);
155
156
157 switch (ret) {
158 case 0:
159 break;
160
161 case KRB5_LIBOS_PWDINTR :
162 /* XXX */
163 goto bad;
164
165 case KRB5KRB_AP_ERR_BAD_INTEGRITY :
166 case KRB5KRB_AP_ERR_MODIFIED :
167 fprintf(stderr, "Password incorrect\n");
168 goto bad;
169
170 default:
171 warnx("failed to get credentials: %s",
172 krb5_get_err_text(context, ret));
173 goto bad;
174 }
175
176 krb5_data_zero(&result_code_string);
177 krb5_data_zero(&result_string);
178
179 /* XXX use getpass? It has a broken interface. */
180 if (UI_UTIL_read_pw_string(pwbuf, sizeof(pwbuf),
181 "New password: ", 1) != 0)
182 goto bad;
183
184 ret = krb5_set_password(context, &cred, pwbuf, NULL,
185 &result_code,
186 &result_code_string,
187 &result_string);
188 if (ret) {
189 warnx("unable to set password: %s",
190 krb5_get_err_text(context, ret));
191 goto bad;
192 }
193
194 printf("%s%s%.*s\n",
195 krb5_passwd_result_to_string(context, result_code),
196 result_string.length > 0 ? " : " : "",
197 (int)result_string.length,
198 result_string.length > 0 ? (char *)result_string.data : "");
199
200 krb5_data_free(&result_code_string);
201 krb5_data_free(&result_string);
202
203 krb5_free_cred_contents(context, &cred);
204 krb5_free_context(context);
205 if (result_code)
206 exit(1);
207 return;
208
209 bad:
210 krb5_free_context(context);
211 exit(1);
212 }
213
214 #else /* ! USE_PAM */
215
216 static krb5_context defcontext;
217 static krb5_principal defprinc;
218 static int kusage = PW_USE;
219
220 int
221 krb5_init(const char *progname)
222 {
223 return krb5_init_context(&defcontext);
224 }
225
226 int
227 krb5_arg (char ch, const char *opt)
228 {
229 krb5_error_code ret;
230 switch(ch) {
231 case '5':
232 case 'k':
233 kusage = PW_USE_FORCE;
234 return 1;
235 case 'u':
236 ret = krb5_parse_name(defcontext, opt, &defprinc);
237 if(ret) {
238 krb5_warn(defcontext, ret, "%s", opt);
239 return 0;
240 }
241 return 1;
242 }
243 return 0;
244 }
245
246 int
247 krb5_arg_end(void)
248 {
249 return kusage;
250 }
251
252 void
253 krb5_end(void)
254 {
255 if (defcontext == NULL)
256 return;
257 if(defprinc)
258 krb5_free_principal(defcontext, defprinc);
259 krb5_free_context(defcontext);
260 }
261
262
263 int
264 krb5_chpw(const char *username)
265 {
266 krb5_error_code ret;
267 krb5_context context;
268 krb5_principal principal;
269 krb5_get_init_creds_opt opt;
270 krb5_creds cred;
271 int result_code;
272 krb5_data result_code_string, result_string;
273 char pwbuf[BUFSIZ];
274
275 ret = krb5_init_context (&context);
276 if (ret) {
277 warnx("failed kerberos initialisation: %s",
278 krb5_get_err_text(context, ret));
279 return 1;
280 }
281
282 krb5_get_init_creds_opt_init (&opt);
283
284 krb5_get_init_creds_opt_set_tkt_life (&opt, 300);
285 krb5_get_init_creds_opt_set_forwardable (&opt, FALSE);
286 krb5_get_init_creds_opt_set_proxiable (&opt, FALSE);
287
288 if(username != NULL) {
289 ret = krb5_parse_name (context, username, &principal);
290 if (ret) {
291 warnx("failed to parse principal: %s",
292 krb5_get_err_text(context, ret));
293 return 1;
294 }
295 } else
296 principal = defprinc;
297
298 ret = krb5_get_init_creds_password (context,
299 &cred,
300 principal,
301 NULL,
302 krb5_prompter_posix,
303 NULL,
304 0,
305 "kadmin/changepw",
306 &opt);
307
308 switch (ret) {
309 case 0:
310 break;
311 case KRB5_LIBOS_PWDINTR :
312 /* XXX */
313 return 1;
314 case KRB5KRB_AP_ERR_BAD_INTEGRITY :
315 case KRB5KRB_AP_ERR_MODIFIED :
316 fprintf(stderr, "Password incorrect\n");
317 return 1;
318 break;
319 default:
320 warnx("failed to get credentials: %s",
321 krb5_get_err_text(context, ret));
322 return 1;
323 }
324 krb5_data_zero (&result_code_string);
325 krb5_data_zero (&result_string);
326
327 /* XXX use getpass? It has a broken interface. */
328 if(UI_UTIL_read_pw_string(pwbuf, sizeof(pwbuf), "New password: ", 1) != 0)
329 return 1;
330
331 ret = krb5_set_password (context, &cred, pwbuf, NULL,
332 &result_code,
333 &result_code_string,
334 &result_string);
335 if (ret)
336 krb5_err (context, 1, ret, "krb5_set_password");
337
338 printf ("%s%s%.*s\n", krb5_passwd_result_to_string(context, result_code),
339 result_string.length > 0 ? " : " : "",
340 (int)result_string.length,
341 result_string.length > 0 ? (char *)result_string.data : "");
342
343 krb5_data_free (&result_code_string);
344 krb5_data_free (&result_string);
345
346 krb5_free_cred_contents (context, &cred);
347 krb5_free_context (context);
348 return result_code;
349 }
350
351 #endif /* USE_PAM */
352