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