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