192108Sphk/*
292108Sphk * Copyright (c) 1997-2004 Kungliga Tekniska H��gskolan
392108Sphk * (Royal Institute of Technology, Stockholm, Sweden).
492108Sphk * All rights reserved.
592108Sphk *
692108Sphk * Redistribution and use in source and binary forms, with or without
792108Sphk * modification, are permitted provided that the following conditions
892108Sphk * are met:
992108Sphk *
1092108Sphk * 1. Redistributions of source code must retain the above copyright
1192108Sphk *    notice, this list of conditions and the following disclaimer.
1292108Sphk *
1392108Sphk * 2. Redistributions in binary form must reproduce the above copyright
1492108Sphk *    notice, this list of conditions and the following disclaimer in the
1592108Sphk *    documentation and/or other materials provided with the distribution.
1692108Sphk *
1792108Sphk * 3. Neither the name of the Institute nor the names of its contributors
1892108Sphk *    may be used to endorse or promote products derived from this software
1992108Sphk *    without specific prior written permission.
2092108Sphk *
2192108Sphk * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2292108Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2392108Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2492108Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2592108Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2692108Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2792108Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2892108Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2992108Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3092108Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3192108Sphk * SUCH DAMAGE.
3292108Sphk */
3392108Sphk
3492108Sphk#include "kpasswd_locl.h"
3592108SphkRCSID("$Id$");
36116196Sobrien
37116196Sobrienstatic int version_flag;
3892108Sphkstatic int help_flag;
3992108Sphkstatic char *admin_principal_str;
4092108Sphkstatic char *cred_cache_str;
4192108Sphk
4292108Sphkstatic struct getargs args[] = {
4392108Sphk    { "admin-principal",	0,   arg_string, &admin_principal_str, NULL,
4492108Sphk   	 NULL },
4592108Sphk    { "cache",			'c', arg_string, &cred_cache_str, NULL, NULL },
4692108Sphk    { "version", 		0,   arg_flag, &version_flag, NULL, NULL },
4792108Sphk    { "help",			0,   arg_flag, &help_flag, NULL, NULL }
4892108Sphk};
4992108Sphk
5092108Sphkstatic void
5192108Sphkusage (int ret, struct getargs *a, int num_args)
5292108Sphk{
5392108Sphk    arg_printusage (a, num_args, NULL, "[principal ...]");
5492108Sphk    exit (ret);
5593776Sphk}
5693776Sphk
5793776Sphkstatic int
5895321Sphkchange_password(krb5_context context,
59114493Sphk		krb5_principal principal,
6092108Sphk		krb5_ccache id)
6192108Sphk{
6292108Sphk    krb5_data result_code_string, result_string;
63111119Simp    int result_code;
64131046Spjd    krb5_error_code ret;
65131046Spjd    char pwbuf[BUFSIZ];
66131046Spjd    char *msg, *name;
67131046Spjd
68104057Sphk    krb5_data_zero (&result_code_string);
69111119Simp    krb5_data_zero (&result_string);
7092108Sphk
7192108Sphk    name = msg = NULL;
7292108Sphk    if (principal == NULL)
7392108Sphk	asprintf(&msg, "New password: ");
74114493Sphk    else {
75114493Sphk	ret = krb5_unparse_name(context, principal, &name);
76114493Sphk	if (ret)
77114493Sphk	    krb5_err(context, 1, ret, "krb5_unparse_name");
78132631Sle
79132631Sle	asprintf(&msg, "New password for %s: ", name);
80114493Sphk    }
81114493Sphk
82114493Sphk    if (msg == NULL)
83131408Spjd	krb5_errx (context, 1, "out of memory");
84131408Spjd
85114493Sphk    ret = UI_UTIL_read_pw_string (pwbuf, sizeof(pwbuf), msg, 1);
86114493Sphk    free(msg);
87114493Sphk    if (name)
8893776Sphk	free(name);
8992108Sphk    if (ret != 0) {
9092108Sphk	return 1;
91107953Sphk    }
92107953Sphk
9392108Sphk    ret = krb5_set_password_using_ccache (context, id, pwbuf,
9492108Sphk					  principal,
9592108Sphk					  &result_code,
9692108Sphk					  &result_code_string,
9792108Sphk					  &result_string);
9892108Sphk    if (ret) {
9992108Sphk	krb5_warn (context, ret, "krb5_set_password_using_ccache");
10092108Sphk	return 1;
10192108Sphk    }
10292108Sphk
103131568Sphk    printf ("%s%s%.*s\n", krb5_passwd_result_to_string(context, result_code),
104131568Sphk	    result_string.length > 0 ? " : " : "",
105131568Sphk	    (int)result_string.length,
106131568Sphk	    result_string.length > 0 ? (char *)result_string.data : "");
107131568Sphk
108131568Sphk    krb5_data_free (&result_code_string);
109131568Sphk    krb5_data_free (&result_string);
110131568Sphk
111131568Sphk    return ret != 0;
112131568Sphk}
113131568Sphk
114131568Sphk
115131568Sphkint
116131568Sphkmain (int argc, char **argv)
117131568Sphk{
118131568Sphk    krb5_error_code ret;
119131568Sphk    krb5_context context;
120131568Sphk    krb5_principal principal;
121131568Sphk    krb5_get_init_creds_opt *opt;
12292108Sphk    krb5_ccache id = NULL;
12392108Sphk    int exit_value;
12492108Sphk    int optidx = 0;
12592108Sphk
12692108Sphk    setprogname(argv[0]);
12792108Sphk
12892108Sphk    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
129125755Sphk	usage(1, args, sizeof(args) / sizeof(args[0]));
13092108Sphk    if (help_flag)
13192108Sphk	usage(0, args, sizeof(args) / sizeof(args[0]));
13292108Sphk    if (version_flag) {
133113713Sphk	print_version(NULL);
134113713Sphk	return 0;
135113713Sphk    }
136113713Sphk    argc -= optidx;
137113713Sphk    argv += optidx;
138113713Sphk
139113713Sphk    ret = krb5_init_context (&context);
140107522Sphk    if (ret)
141107522Sphk	errx (1, "krb5_init_context failed: %d", ret);
142107522Sphk
143107522Sphk    ret = krb5_get_init_creds_opt_alloc (context, &opt);
144107522Sphk    if (ret)
145107522Sphk	krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");
146107522Sphk
147107522Sphk    krb5_get_init_creds_opt_set_tkt_life (opt, 300);
148107953Sphk    krb5_get_init_creds_opt_set_forwardable (opt, FALSE);
149107522Sphk    krb5_get_init_creds_opt_set_proxiable (opt, FALSE);
150113713Sphk
151113713Sphk    if (cred_cache_str) {
152113713Sphk	ret = krb5_cc_resolve(context, cred_cache_str, &id);
153113713Sphk	if (ret)
154107522Sphk	    krb5_err (context, 1, ret, "krb5_cc_resolve");
155107522Sphk    } else {
156107522Sphk	ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id);
157107522Sphk	if (ret)
158107953Sphk	    krb5_err (context, 1, ret, "krb5_cc_new_unique");
159107953Sphk    }
160107522Sphk
161107522Sphk    if (cred_cache_str == NULL) {
162107522Sphk	krb5_principal admin_principal = NULL;
163107522Sphk	krb5_creds cred;
164107522Sphk
165107522Sphk	if (admin_principal_str) {
166107522Sphk	    ret = krb5_parse_name (context, admin_principal_str,
167107522Sphk				   &admin_principal);
168107522Sphk	    if (ret)
169107522Sphk		krb5_err (context, 1, ret, "krb5_parse_name");
170107522Sphk	} else if (argc == 1) {
171107522Sphk	    ret = krb5_parse_name (context, argv[0], &admin_principal);
172107522Sphk	    if (ret)
173107522Sphk		krb5_err (context, 1, ret, "krb5_parse_name");
17493776Sphk	} else {
175169288Spjd	    ret = krb5_get_default_principal (context, &admin_principal);
176169288Spjd	    if (ret)
177169288Spjd		krb5_err (context, 1, ret, "krb5_get_default_principal");
178169288Spjd	}
179169288Spjd
180169288Spjd	ret = krb5_get_init_creds_password (context,
181169288Spjd					    &cred,
182169288Spjd					    admin_principal,
183169288Spjd					    NULL,
184169288Spjd					    krb5_prompter_posix,
185169288Spjd					    NULL,
186169288Spjd					    0,
187169288Spjd					    "kadmin/changepw",
188169288Spjd					    opt);
189169288Spjd	switch (ret) {
190169288Spjd	case 0:
191169288Spjd	    break;
192169288Spjd	case KRB5_LIBOS_PWDINTR :
193169288Spjd	    return 1;
194169288Spjd	case KRB5KRB_AP_ERR_BAD_INTEGRITY :
195169288Spjd	case KRB5KRB_AP_ERR_MODIFIED :
196169288Spjd	    krb5_errx(context, 1, "Password incorrect");
19792108Sphk	    break;
19892108Sphk	default:
19992108Sphk	    krb5_err(context, 1, ret, "krb5_get_init_creds");
20092108Sphk	}
20192108Sphk
20292108Sphk	krb5_get_init_creds_opt_free(context, opt);
20392108Sphk
204113712Sphk	ret = krb5_cc_initialize(context, id, admin_principal);
205113713Sphk	krb5_free_principal(context, admin_principal);
206107953Sphk	if (ret)
207107522Sphk	    krb5_err(context, 1, ret, "krb5_cc_initialize");
20894287Sphk
20992108Sphk	ret = krb5_cc_store_cred(context, id, &cred);
21092108Sphk	if (ret)
21192108Sphk	    krb5_err(context, 1, ret, "krb5_cc_store_cred");
21292108Sphk
21392108Sphk	krb5_free_cred_contents (context, &cred);
214107953Sphk    }
215107953Sphk
21692108Sphk    if (argc == 0) {
21792108Sphk	exit_value = change_password(context, NULL, id);
21892108Sphk    } else {
21992108Sphk	exit_value = 0;
22092108Sphk
221104195Sphk	while (argc-- > 0) {
22292108Sphk
22392108Sphk	    ret = krb5_parse_name (context, argv[0], &principal);
224107522Sphk	    if (ret)
225107522Sphk		krb5_err (context, 1, ret, "krb5_parse_name");
226107522Sphk
227107522Sphk	    ret = change_password(context, principal, id);
228107832Sphk	    if (ret)
229113712Sphk		exit_value = 1;
230113713Sphk	    krb5_free_principal(context, principal);
231113713Sphk	    argv++;
232107522Sphk	}
233113713Sphk    }
234107522Sphk
235113713Sphk    if (cred_cache_str == NULL) {
236113713Sphk	ret = krb5_cc_destroy(context, id);
237113713Sphk	if (ret)
238113713Sphk	    krb5_err (context, 1, ret, "krb5_cc_destroy");
239113713Sphk    } else {
240113713Sphk	ret = krb5_cc_close(context, id);
241113713Sphk	if (ret)
242113713Sphk	    krb5_err (context, 1, ret, "krb5_cc_close");
243113713Sphk    }
244113713Sphk
245113713Sphk    krb5_free_context (context);
246107522Sphk    return exit_value;
247113713Sphk}
248113713Sphk