1/* $NetBSD: ank.c,v 1.3 2023/06/19 21:41:41 christos Exp $ */ 2 3/* 4 * Copyright (c) 1997-2006 Kungliga Tekniska H��gskolan 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 "kadmin_locl.h" 37#include "kadmin-commands.h" 38 39/* 40 * fetch the default principal corresponding to `princ' 41 */ 42 43static krb5_error_code 44get_default (kadm5_server_context *contextp, 45 krb5_principal princ, 46 kadm5_principal_ent_t default_ent) 47{ 48 krb5_error_code ret; 49 krb5_principal def_principal; 50 krb5_const_realm realm = krb5_principal_get_realm(contextp->context, princ); 51 52 ret = krb5_make_principal (contextp->context, &def_principal, 53 realm, "default", NULL); 54 if (ret) 55 return ret; 56 ret = kadm5_get_principal (contextp, def_principal, default_ent, 57 KADM5_PRINCIPAL_NORMAL_MASK); 58 krb5_free_principal (contextp->context, def_principal); 59 return ret; 60} 61 62/* 63 * Add the principal `name' to the database. 64 * Prompt for all data not given by the input parameters. 65 */ 66 67static krb5_error_code 68add_one_principal (const char *name, 69 int rand_key, 70 int rand_password, 71 int use_defaults, 72 char *password, 73 char *policy, 74 krb5_key_data *key_data, 75 const char *max_ticket_life, 76 const char *max_renewable_life, 77 const char *attributes, 78 const char *expiration, 79 const char *pw_expiration) 80{ 81 krb5_error_code ret; 82 kadm5_principal_ent_rec princ, defrec; 83 kadm5_principal_ent_rec *default_ent = NULL; 84 krb5_principal princ_ent = NULL; 85 int mask = 0; 86 int default_mask = 0; 87 char pwbuf[1024]; 88 89 memset(&princ, 0, sizeof(princ)); 90 ret = krb5_parse_name(context, name, &princ_ent); 91 if (ret) { 92 krb5_warn(context, ret, "krb5_parse_name"); 93 return ret; 94 } 95 princ.principal = princ_ent; 96 mask |= KADM5_PRINCIPAL; 97 98 ret = set_entry(context, &princ, &mask, 99 max_ticket_life, max_renewable_life, 100 expiration, pw_expiration, attributes, policy); 101 if (ret) 102 goto out; 103 104 default_ent = &defrec; 105 ret = get_default (kadm_handle, princ_ent, default_ent); 106 if (ret) { 107 default_ent = NULL; 108 default_mask = 0; 109 } else { 110 default_mask = KADM5_ATTRIBUTES | KADM5_MAX_LIFE | KADM5_MAX_RLIFE | 111 KADM5_PRINC_EXPIRE_TIME | KADM5_PW_EXPIRATION; 112 } 113 114 if(use_defaults) 115 set_defaults(&princ, &mask, default_ent, default_mask); 116 else 117 if(edit_entry(&princ, &mask, default_ent, default_mask)) 118 goto out; 119 if(rand_key || key_data) { 120 princ.attributes |= KRB5_KDB_DISALLOW_ALL_TIX; 121 mask |= KADM5_ATTRIBUTES; 122 random_password (pwbuf, sizeof(pwbuf)); 123 password = pwbuf; 124 } else if (rand_password) { 125 random_password (pwbuf, sizeof(pwbuf)); 126 password = pwbuf; 127 } else if(password == NULL) { 128 char *princ_name; 129 char *prompt; 130 int aret; 131 132 ret = krb5_unparse_name(context, princ_ent, &princ_name); 133 if (ret) 134 goto out; 135 aret = asprintf (&prompt, "%s's Password: ", princ_name); 136 free (princ_name); 137 if (aret == -1) { 138 ret = ENOMEM; 139 krb5_set_error_message(context, ret, "out of memory"); 140 goto out; 141 } 142 ret = UI_UTIL_read_pw_string (pwbuf, sizeof(pwbuf), prompt, 143 UI_UTIL_FLAG_VERIFY | 144 UI_UTIL_FLAG_VERIFY_SILENT); 145 free (prompt); 146 if (ret) { 147 ret = KRB5_LIBOS_BADPWDMATCH; 148 krb5_set_error_message(context, ret, "failed to verify password"); 149 goto out; 150 } 151 password = pwbuf; 152 } 153 154 ret = kadm5_create_principal(kadm_handle, &princ, mask, password); 155 if(ret) { 156 krb5_warn(context, ret, "kadm5_create_principal"); 157 goto out; 158 } 159 if(rand_key) { 160 krb5_keyblock *new_keys; 161 int n_keys, i; 162 ret = kadm5_randkey_principal(kadm_handle, princ_ent, 163 &new_keys, &n_keys); 164 if(ret){ 165 krb5_warn(context, ret, "kadm5_randkey_principal"); 166 n_keys = 0; 167 } 168 for(i = 0; i < n_keys; i++) 169 krb5_free_keyblock_contents(context, &new_keys[i]); 170 if (n_keys > 0) 171 free(new_keys); 172 kadm5_get_principal(kadm_handle, princ_ent, &princ, 173 KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES); 174 krb5_free_principal(context, princ_ent); 175 princ_ent = princ.principal; 176 princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX); 177 /* 178 * Updating kvno w/o key data and vice-versa gives _kadm5_setup_entry() 179 * and _kadm5_set_keys2() headaches. But we used to, so we handle 180 * this in in those two functions. Might as well leave this code as 181 * it was then. 182 */ 183 princ.kvno = 1; 184 kadm5_modify_principal(kadm_handle, &princ, 185 KADM5_ATTRIBUTES | KADM5_KVNO); 186 } else if (key_data) { 187 ret = kadm5_chpass_principal_with_key (kadm_handle, princ_ent, 188 3, key_data); 189 if (ret) { 190 krb5_warn(context, ret, "kadm5_chpass_principal_with_key"); 191 } 192 kadm5_get_principal(kadm_handle, princ_ent, &princ, 193 KADM5_PRINCIPAL | KADM5_ATTRIBUTES); 194 krb5_free_principal(context, princ_ent); 195 princ_ent = princ.principal; 196 princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX); 197 kadm5_modify_principal(kadm_handle, &princ, KADM5_ATTRIBUTES); 198 } else if (rand_password) { 199 char *princ_name; 200 201 krb5_unparse_name(context, princ_ent, &princ_name); 202 printf ("added %s with password \"%s\"\n", princ_name, password); 203 free (princ_name); 204 } 205out: 206 kadm5_free_principal_ent(kadm_handle, &princ); /* frees princ_ent */ 207 if(default_ent) 208 kadm5_free_principal_ent (kadm_handle, default_ent); 209 if (password != NULL) 210 memset (password, 0, strlen(password)); 211 return ret; 212} 213 214/* 215 * parse the string `key_string' into `key', returning 0 iff succesful. 216 */ 217 218/* 219 * the ank command 220 */ 221 222/* 223 * Parse arguments and add all the principals. 224 */ 225 226int 227add_new_key(struct add_options *opt, int argc, char **argv) 228{ 229 krb5_error_code ret = 0; 230 int i; 231 int num; 232 krb5_key_data key_data[3]; 233 krb5_key_data *kdp = NULL; 234 235 num = 0; 236 if (opt->random_key_flag) 237 ++num; 238 if (opt->random_password_flag) 239 ++num; 240 if (opt->password_string) 241 ++num; 242 if (opt->key_string) 243 ++num; 244 245 if (num > 1) { 246 fprintf (stderr, "give only one of " 247 "--random-key, --random-password, --password, --key\n"); 248 return 1; 249 } 250 251 if (opt->key_string) { 252 const char *error; 253 254 if (parse_des_key (opt->key_string, key_data, &error)) { 255 fprintf (stderr, "failed parsing key \"%s\": %s\n", 256 opt->key_string, error); 257 return 1; 258 } 259 kdp = key_data; 260 } 261 262 for(i = 0; i < argc; i++) { 263 ret = add_one_principal (argv[i], 264 opt->random_key_flag, 265 opt->random_password_flag, 266 opt->use_defaults_flag, 267 opt->password_string, 268 opt->policy_string, 269 kdp, 270 opt->max_ticket_life_string, 271 opt->max_renewable_life_string, 272 opt->attributes_string, 273 opt->expiration_time_string, 274 opt->pw_expiration_time_string); 275 if (ret) { 276 krb5_warn (context, ret, "adding %s", argv[i]); 277 break; 278 } 279 } 280 if (kdp) { 281 int16_t dummy = 3; 282 kadm5_free_key_data (kadm_handle, &dummy, key_data); 283 } 284 return ret != 0; 285} 286