1 /* $NetBSD: ank.c,v 1.2 2017/01/28 21:31:44 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 43 static krb5_error_code 44 get_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 67 static krb5_error_code 68 add_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, 1); 143 free (prompt); 144 if (ret) { 145 ret = KRB5_LIBOS_BADPWDMATCH; 146 krb5_set_error_message(context, ret, "failed to verify password"); 147 goto out; 148 } 149 password = pwbuf; 150 } 151 152 ret = kadm5_create_principal(kadm_handle, &princ, mask, password); 153 if(ret) { 154 krb5_warn(context, ret, "kadm5_create_principal"); 155 goto out; 156 } 157 if(rand_key) { 158 krb5_keyblock *new_keys; 159 int n_keys, i; 160 ret = kadm5_randkey_principal(kadm_handle, princ_ent, 161 &new_keys, &n_keys); 162 if(ret){ 163 krb5_warn(context, ret, "kadm5_randkey_principal"); 164 n_keys = 0; 165 } 166 for(i = 0; i < n_keys; i++) 167 krb5_free_keyblock_contents(context, &new_keys[i]); 168 if (n_keys > 0) 169 free(new_keys); 170 kadm5_get_principal(kadm_handle, princ_ent, &princ, 171 KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES); 172 krb5_free_principal(context, princ_ent); 173 princ_ent = princ.principal; 174 princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX); 175 /* 176 * Updating kvno w/o key data and vice-versa gives _kadm5_setup_entry() 177 * and _kadm5_set_keys2() headaches. But we used to, so we handle 178 * this in in those two functions. Might as well leave this code as 179 * it was then. 180 */ 181 princ.kvno = 1; 182 kadm5_modify_principal(kadm_handle, &princ, 183 KADM5_ATTRIBUTES | KADM5_KVNO); 184 } else if (key_data) { 185 ret = kadm5_chpass_principal_with_key (kadm_handle, princ_ent, 186 3, key_data); 187 if (ret) { 188 krb5_warn(context, ret, "kadm5_chpass_principal_with_key"); 189 } 190 kadm5_get_principal(kadm_handle, princ_ent, &princ, 191 KADM5_PRINCIPAL | KADM5_ATTRIBUTES); 192 krb5_free_principal(context, princ_ent); 193 princ_ent = princ.principal; 194 princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX); 195 kadm5_modify_principal(kadm_handle, &princ, KADM5_ATTRIBUTES); 196 } else if (rand_password) { 197 char *princ_name; 198 199 krb5_unparse_name(context, princ_ent, &princ_name); 200 printf ("added %s with password \"%s\"\n", princ_name, password); 201 free (princ_name); 202 } 203 out: 204 kadm5_free_principal_ent(kadm_handle, &princ); /* frees princ_ent */ 205 if(default_ent) 206 kadm5_free_principal_ent (kadm_handle, default_ent); 207 if (password != NULL) 208 memset (password, 0, strlen(password)); 209 return ret; 210 } 211 212 /* 213 * parse the string `key_string' into `key', returning 0 iff succesful. 214 */ 215 216 /* 217 * the ank command 218 */ 219 220 /* 221 * Parse arguments and add all the principals. 222 */ 223 224 int 225 add_new_key(struct add_options *opt, int argc, char **argv) 226 { 227 krb5_error_code ret = 0; 228 int i; 229 int num; 230 krb5_key_data key_data[3]; 231 krb5_key_data *kdp = NULL; 232 233 num = 0; 234 if (opt->random_key_flag) 235 ++num; 236 if (opt->random_password_flag) 237 ++num; 238 if (opt->password_string) 239 ++num; 240 if (opt->key_string) 241 ++num; 242 243 if (num > 1) { 244 fprintf (stderr, "give only one of " 245 "--random-key, --random-password, --password, --key\n"); 246 return 1; 247 } 248 249 if (opt->key_string) { 250 const char *error; 251 252 if (parse_des_key (opt->key_string, key_data, &error)) { 253 fprintf (stderr, "failed parsing key \"%s\": %s\n", 254 opt->key_string, error); 255 return 1; 256 } 257 kdp = key_data; 258 } 259 260 for(i = 0; i < argc; i++) { 261 ret = add_one_principal (argv[i], 262 opt->random_key_flag, 263 opt->random_password_flag, 264 opt->use_defaults_flag, 265 opt->password_string, 266 opt->policy_string, 267 kdp, 268 opt->max_ticket_life_string, 269 opt->max_renewable_life_string, 270 opt->attributes_string, 271 opt->expiration_time_string, 272 opt->pw_expiration_time_string); 273 if (ret) { 274 krb5_warn (context, ret, "adding %s", argv[i]); 275 break; 276 } 277 } 278 if (kdp) { 279 int16_t dummy = 3; 280 kadm5_free_key_data (kadm_handle, &dummy, key_data); 281 } 282 return ret != 0; 283 } 284