krb5: Fix display_status() incorrect major status
[metze/heimdal/wip.git] / kpasswd / kpasswd.c
1 /*
2  * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "kpasswd_locl.h"
35 RCSID("$Id$");
36
37 static int version_flag;
38 static int help_flag;
39 static char *admin_principal_str;
40 static char *cred_cache_str;
41
42 static struct getargs args[] = {
43     { "admin-principal",        0,   arg_string, &admin_principal_str, NULL,
44          NULL },
45     { "cache",                  'c', arg_string, &cred_cache_str, NULL, NULL },
46     { "version",                0,   arg_flag, &version_flag, NULL, NULL },
47     { "help",                   0,   arg_flag, &help_flag, NULL, NULL }
48 };
49
50 static void
51 usage (int ret, struct getargs *a, int num_args)
52 {
53     arg_printusage (a, num_args, NULL, "[principal ...]");
54     exit (ret);
55 }
56
57 static int
58 change_password(krb5_context context,
59                 krb5_principal principal,
60                 krb5_ccache id)
61 {
62     krb5_data result_code_string, result_string;
63     int result_code;
64     krb5_error_code ret;
65     char pwbuf[BUFSIZ];
66     char *msg, *name;
67     int aret;
68
69     krb5_data_zero (&result_code_string);
70     krb5_data_zero (&result_string);
71
72     name = msg = NULL;
73     if (principal == NULL)
74         aret = asprintf(&msg, "New password: ");
75     else {
76         ret = krb5_unparse_name(context, principal, &name);
77         if (ret)
78             krb5_err(context, 1, ret, "krb5_unparse_name");
79
80         aret = asprintf(&msg, "New password for %s: ", name);
81     }
82
83     if (aret == -1 || msg == NULL)
84         krb5_errx (context, 1, "out of memory");
85
86     ret = UI_UTIL_read_pw_string (pwbuf, sizeof(pwbuf), msg,
87                                   UI_UTIL_FLAG_VERIFY);
88     free(msg);
89     if (name)
90         free(name);
91     if (ret != 0) {
92         return 1;
93     }
94
95     ret = krb5_set_password_using_ccache (context, id, pwbuf,
96                                           principal,
97                                           &result_code,
98                                           &result_code_string,
99                                           &result_string);
100     if (ret) {
101         krb5_warn (context, ret, "krb5_set_password_using_ccache");
102         return 1;
103     }
104
105     printf ("%s%s%.*s\n", krb5_passwd_result_to_string(context, result_code),
106             result_string.length > 0 ? " : " : "",
107             (int)result_string.length,
108             result_string.length > 0 ? (char *)result_string.data : "");
109
110     krb5_data_free (&result_code_string);
111     krb5_data_free (&result_string);
112
113     return ret != 0;
114 }
115
116
117 int
118 main (int argc, char **argv)
119 {
120     krb5_error_code ret;
121     krb5_context context;
122     krb5_principal principal;
123     krb5_get_init_creds_opt *opt;
124     krb5_ccache id = NULL;
125     int exit_value;
126     int optidx = 0;
127
128     setprogname(argv[0]);
129
130     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
131         usage(1, args, sizeof(args) / sizeof(args[0]));
132     if (help_flag)
133         usage(0, args, sizeof(args) / sizeof(args[0]));
134     if (version_flag) {
135         print_version(NULL);
136         return 0;
137     }
138     argc -= optidx;
139     argv += optidx;
140
141     ret = krb5_init_context (&context);
142     if (ret)
143         errx (1, "krb5_init_context failed: %d", ret);
144
145     ret = krb5_get_init_creds_opt_alloc (context, &opt);
146     if (ret)
147         krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");
148
149     krb5_get_init_creds_opt_set_tkt_life (opt, 300);
150     krb5_get_init_creds_opt_set_forwardable (opt, FALSE);
151     krb5_get_init_creds_opt_set_proxiable (opt, FALSE);
152
153     if (cred_cache_str) {
154         ret = krb5_cc_resolve(context, cred_cache_str, &id);
155         if (ret)
156             krb5_err (context, 1, ret, "krb5_cc_resolve");
157     } else {
158         ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id);
159         if (ret)
160             krb5_err (context, 1, ret, "krb5_cc_new_unique");
161     }
162
163     if (cred_cache_str == NULL) {
164         krb5_principal admin_principal = NULL;
165         krb5_creds cred;
166
167         if (admin_principal_str) {
168             ret = krb5_parse_name (context, admin_principal_str,
169                                    &admin_principal);
170             if (ret)
171                 krb5_err (context, 1, ret, "krb5_parse_name");
172         } else if (argc == 1) {
173             ret = krb5_parse_name (context, argv[0], &admin_principal);
174             if (ret)
175                 krb5_err (context, 1, ret, "krb5_parse_name");
176         } else {
177             ret = krb5_get_default_principal (context, &admin_principal);
178             if (ret)
179                 krb5_err (context, 1, ret, "krb5_get_default_principal");
180         }
181
182         ret = krb5_get_init_creds_password (context,
183                                             &cred,
184                                             admin_principal,
185                                             NULL,
186                                             krb5_prompter_posix,
187                                             NULL,
188                                             0,
189                                             "kadmin/changepw",
190                                             opt);
191         switch (ret) {
192         case 0:
193             break;
194         case KRB5_LIBOS_PWDINTR :
195             return 1;
196         case KRB5KRB_AP_ERR_BAD_INTEGRITY :
197         case KRB5KRB_AP_ERR_MODIFIED :
198             krb5_errx(context, 1, "Password incorrect");
199             break;
200         default:
201             krb5_err(context, 1, ret, "krb5_get_init_creds");
202         }
203
204         krb5_get_init_creds_opt_free(context, opt);
205
206         ret = krb5_cc_initialize(context, id, admin_principal);
207         krb5_free_principal(context, admin_principal);
208         if (ret)
209             krb5_err(context, 1, ret, "krb5_cc_initialize");
210
211         ret = krb5_cc_store_cred(context, id, &cred);
212         if (ret)
213             krb5_err(context, 1, ret, "krb5_cc_store_cred");
214
215         krb5_free_cred_contents (context, &cred);
216     }
217
218     if (argc == 0) {
219         exit_value = change_password(context, NULL, id);
220     } else {
221         exit_value = 0;
222
223         while (argc-- > 0) {
224
225             ret = krb5_parse_name (context, argv[0], &principal);
226             if (ret)
227                 krb5_err (context, 1, ret, "krb5_parse_name");
228
229             ret = change_password(context, principal, id);
230             if (ret)
231                 exit_value = 1;
232             krb5_free_principal(context, principal);
233             argv++;
234         }
235     }
236
237     if (cred_cache_str == NULL) {
238         ret = krb5_cc_destroy(context, id);
239         if (ret)
240             krb5_err (context, 1, ret, "krb5_cc_destroy");
241     } else {
242         ret = krb5_cc_close(context, id);
243         if (ret)
244             krb5_err (context, 1, ret, "krb5_cc_close");
245     }
246
247     krb5_free_context (context);
248     return exit_value;
249 }