1/* 2 * Copyright (c) 1997 - 2001, 2003 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 "kadm5_locl.h" 35 36RCSID("$Id$"); 37 38/* 39 * Set the keys of `ent' to the string-to-key of `password' 40 */ 41 42kadm5_ret_t 43_kadm5_set_keys(kadm5_server_context *context, 44 hdb_entry *ent, 45 const char *password, 46 uint32_t n_ks_tuple, krb5_key_salt_tuple *ks_tuple) 47{ 48 Key *keys; 49 size_t num_keys; 50 kadm5_ret_t ret; 51 52 ret = hdb_generate_key_set_password(context->context, 53 ent->principal, 54 password, n_ks_tuple, ks_tuple, 55 &keys, &num_keys); 56 if (ret) 57 return ret; 58 59 60 _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val); 61 ent->keys.val = keys; 62 ent->keys.len = (int)num_keys; 63 64 ret = hdb_entry_set_srp_verifiers(context->context, ent, password, 0); 65 if (ret) 66 return ret; 67 68 hdb_entry_set_pw_change_time(context->context, ent, 0); 69 70 if (krb5_config_get_bool_default(context->context, NULL, FALSE, 71 "kadmin", "save-password", NULL)) 72 { 73 ret = hdb_entry_set_password(context->context, context->db, 74 ent, password); 75 if (ret) 76 return ret; 77 } 78 79 return 0; 80} 81 82static void 83setup_Key(Key *k, Salt *s, krb5_key_data *kd, size_t kd_offset) 84{ 85 memset(k, 0, sizeof (*k)); /* sets mkvno and salt */ 86 k->key.keytype = kd[kd_offset].key_data_type[0]; 87 k->key.keyvalue.length = kd[kd_offset].key_data_length[0]; 88 k->key.keyvalue.data = kd[kd_offset].key_data_contents[0]; 89 90 if(kd[kd_offset].key_data_ver == 2) { 91 memset(s, 0, sizeof (*s)); 92 s->type = kd[kd_offset].key_data_type[1]; 93 s->salt.length = kd[kd_offset].key_data_length[1]; 94 s->salt.data = kd[kd_offset].key_data_contents[1]; 95 k->salt = s; 96 } 97} 98 99/* 100 * Set the keys of `ent' to (`n_key_data', `key_data') 101 */ 102 103kadm5_ret_t 104_kadm5_set_keys2(kadm5_server_context *context, 105 hdb_entry *ent, 106 int16_t n_key_data, 107 krb5_key_data *key_data) 108{ 109 krb5_error_code ret; 110 size_t i, k; 111 HDB_extension ext; 112 HDB_extension *extp = NULL; 113 HDB_Ext_KeySet *hist_keys = &ext.data.u.hist_keys; 114 Key key; 115 Salt salt; 116 Keys keys; 117 hdb_keyset hkset; 118 krb5_kvno kvno = -1; 119 int one_key_set = 1; 120 int replace_hist_keys = 0; 121 122 assert(n_key_data >= 0); 123 124 if (n_key_data == 0) { 125 /* Clear all keys! */ 126 ret = hdb_clear_extension(context->context, ent, 127 choice_HDB_extension_data_hist_keys); 128 if (ret) 129 return ret; 130 free_Keys(&ent->keys); 131 return 0; 132 } 133 134 memset(&keys, 0, sizeof (keys)); 135 memset(&hkset, 0, sizeof (hkset)); /* set set_time */ 136 ext.data.element = choice_HDB_extension_data_hist_keys; 137 memset(hist_keys, 0, sizeof (*hist_keys)); 138 139 for (i = 0; i < (size_t)n_key_data; i++) { 140 if (kvno != -1 && kvno != key_data[i].key_data_kvno) { 141 one_key_set = 0; 142 break; 143 } 144 kvno = key_data[i].key_data_kvno; 145 } 146 if (one_key_set) { 147 /* 148 * If we're updating KADM5_KEY_DATA with a single keyset then we 149 * assume we must be setting the principal's kvno as well! 150 * 151 * Just have to be careful about old clients that might have 152 * sent 0 as the kvno... This may seem ugly, but it's the price 153 * of backwards compatibility with pre-multi-kvno kadmin clients 154 * (besides, who's to say that updating KADM5_KEY_DATA requires 155 * updating the entry's kvno?) 156 * 157 * Note that we do nothing special for the case where multiple 158 * keysets are given but the entry's kvno is not set and not in 159 * the given set of keysets. If this happens we'll just update 160 * the key history only and leave the current keyset alone. 161 */ 162 if (kvno == 0) { 163 /* Force kvno to 1 if it was 0; (ank would do this anyways) */ 164 if (ent->kvno == 0) 165 ent->kvno = 1; 166 /* Below we need key_data[*].kvno to be reasonable */ 167 for (i = 0; i < (size_t)n_key_data; i++) 168 key_data[i].key_data_kvno = ent->kvno; 169 } else { 170 /* 171 * Or force the entry's kvno to match the one from the new, 172 * singular keyset 173 */ 174 ent->kvno = kvno; 175 } 176 } 177 178 for (i = 0; i < (size_t)n_key_data; i++) { 179 if (key_data[i].key_data_kvno == ent->kvno) { 180 /* A current key; add to current key set */ 181 setup_Key(&key, &salt, key_data, i); 182 ret = add_Keys(&keys, &key); 183 continue; 184 } 185 186 /* 187 * This kvno is historical. Build an hdb_keyset for keys of 188 * this enctype and add them to the new key history. 189 */ 190 for (k = 0; k < hist_keys->len; k++) { 191 if (hist_keys->val[k].kvno == key_data[i].key_data_kvno) 192 break; 193 } 194 if (hist_keys->len > k && 195 hist_keys->val[k].kvno == key_data[i].key_data_kvno) 196 /* We've added all keys of this kvno already (see below) */ 197 continue; 198 199 memset(&hkset, 0, sizeof (hkset)); /* set set_time */ 200 hkset.kvno = key_data[i].key_data_kvno; 201 for (k = 0; k < (size_t)n_key_data; k++) { 202 /* Find all keys of this kvno and add them to the new keyset */ 203 if (key_data[k].key_data_kvno != hkset.kvno) 204 continue; 205 206 setup_Key(&key, &salt, key_data, k); 207 ret = add_Keys(&hkset.keys, &key); 208 if (ret) 209 goto out; 210 } 211 ret = add_HDB_Ext_KeySet(hist_keys, &hkset); 212 if (ret) 213 goto out; 214 replace_hist_keys = 1; 215 } 216 217 if (replace_hist_keys) 218 /* No key history given -> leave it alone */ 219 extp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); 220 if (extp != NULL) { 221 HDB_Ext_KeySet *old_hist_keys; 222 223 /* 224 * Try to keep the very useful set_time values from the old hist 225 * keys. kadm5 loses this info, so this heuristic is the best we 226 * can do. 227 */ 228 old_hist_keys = &extp->data.u.hist_keys; 229 for (i = 0; i < old_hist_keys->len; i++) { 230 if (old_hist_keys->val[i].set_time == NULL) 231 continue; 232 for (k = 0; k < hist_keys->len; k++) { 233 if (hist_keys->val[k].kvno != old_hist_keys->val[k].kvno) 234 continue; 235 hist_keys->val[k].set_time = old_hist_keys->val[k].set_time; 236 old_hist_keys->val[k].set_time = NULL; 237 } 238 } 239 } 240 241 if (replace_hist_keys) { 242 /* If hist keys not given in key_data then don't blow away hist_keys */ 243 ret = hdb_replace_extension(context->context, ent, &ext); 244 if (ret) 245 goto out; 246 } 247 248 /* 249 * A structure copy is more efficient here than this would be: 250 * 251 * copy_Keys(&keys, &ent->keys); 252 * free_Keys(&keys); 253 * 254 * Of course, the above hdb_replace_extension() is not at all efficient... 255 */ 256 free_Keys(&ent->keys); 257 ent->keys = keys; 258 hdb_entry_set_pw_change_time(context->context, ent, 0); 259 hdb_entry_clear_password(context->context, ent); 260 261 return 0; 262 263out: 264 free_Keys(&keys); 265 free_hdb_keyset(&hkset); 266 free_HDB_extension(&ext); 267 return ret; 268} 269 270/* 271 * Set the keys of `ent' to `n_keys, keys' 272 */ 273 274kadm5_ret_t 275_kadm5_set_keys3(kadm5_server_context *context, 276 hdb_entry *ent, 277 int n_keys, 278 krb5_keyblock *keyblocks) 279{ 280 krb5_error_code ret; 281 int i; 282 unsigned len; 283 Key *keys; 284 285 len = n_keys; 286 keys = malloc (len * sizeof(*keys)); 287 if (keys == NULL && len != 0) 288 return ENOMEM; 289 290 _kadm5_init_keys (keys, len); 291 292 for(i = 0; i < n_keys; i++) { 293 keys[i].mkvno = NULL; 294 ret = krb5_copy_keyblock_contents (context->context, 295 &keyblocks[i], 296 &keys[i].key); 297 if(ret) 298 goto out; 299 keys[i].salt = NULL; 300 } 301 _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val); 302 ent->keys.len = len; 303 ent->keys.val = keys; 304 305 hdb_entry_set_pw_change_time(context->context, ent, 0); 306 hdb_entry_clear_password(context->context, ent); 307 308 return 0; 309 out: 310 _kadm5_free_keys (context->context, len, keys); 311 return ret; 312} 313 314/* 315 * 316 */ 317 318static int 319is_des_key_p(int keytype) 320{ 321 return keytype == ETYPE_DES_CBC_CRC || 322 keytype == ETYPE_DES_CBC_MD4 || 323 keytype == ETYPE_DES_CBC_MD5; 324} 325 326 327/* 328 * Set the keys of `ent' to random keys and return them in `n_keys' 329 * and `new_keys'. 330 */ 331 332kadm5_ret_t 333_kadm5_set_keys_randomly (kadm5_server_context *context, 334 hdb_entry *ent, 335 int n_ks_tuple, 336 krb5_key_salt_tuple *ks_tuple, 337 krb5_keyblock **new_keys, 338 int *n_keys) 339{ 340 krb5_keyblock *kblock = NULL; 341 kadm5_ret_t ret = 0; 342 ssize_t des_keyblock; 343 size_t i, num_keys; 344 Key *keys; 345 346 ret = hdb_generate_key_set(context->context, ent->principal, 347 n_ks_tuple, ks_tuple, 348 &keys, &num_keys, 1); 349 if (ret) 350 return ret; 351 352 kblock = malloc(num_keys * sizeof(kblock[0])); 353 if (kblock == NULL) { 354 ret = ENOMEM; 355 _kadm5_free_keys (context->context, (int)num_keys, keys); 356 return ret; 357 } 358 memset(kblock, 0, num_keys * sizeof(kblock[0])); 359 360 des_keyblock = -1; 361 for (i = 0; i < num_keys; i++) { 362 363 /* 364 * To make sure all des keys are the the same we generate only 365 * the first one and then copy key to all other des keys. 366 */ 367 368 if (des_keyblock != -1 && is_des_key_p(keys[i].key.keytype)) { 369 ret = krb5_copy_keyblock_contents (context->context, 370 &kblock[des_keyblock], 371 &kblock[i]); 372 if (ret) 373 goto out; 374 kblock[i].keytype = keys[i].key.keytype; 375 } else { 376 ret = krb5_generate_random_keyblock (context->context, 377 keys[i].key.keytype, 378 &kblock[i]); 379 if (ret) 380 goto out; 381 382 if (is_des_key_p(keys[i].key.keytype)) 383 des_keyblock = i; 384 } 385 386 ret = krb5_copy_keyblock_contents (context->context, 387 &kblock[i], 388 &keys[i].key); 389 if (ret) 390 goto out; 391 } 392 393out: 394 if(ret) { 395 for (i = 0; i < num_keys; ++i) 396 krb5_free_keyblock_contents (context->context, &kblock[i]); 397 free(kblock); 398 _kadm5_free_keys (context->context, (int)num_keys, keys); 399 return ret; 400 } 401 402 _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val); 403 ent->keys.val = keys; 404 ent->keys.len = (int)num_keys; 405 if (n_keys && new_keys) { 406 *new_keys = kblock; 407 *n_keys = (int)num_keys; 408 } 409 410 hdb_entry_set_pw_change_time(context->context, ent, 0); 411 hdb_entry_clear_password(context->context, ent); 412 413 return 0; 414} 415