1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 #pragma ident "%Z%%M% %I% %E% SMI" 6 7 /* 8 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 9 * 10 * Openvision retains the copyright to derivative works of 11 * this source code. Do *NOT* create a derivative of this 12 * source code before consulting with your legal department. 13 * Do *NOT* integrate *ANY* of this source code into another 14 * product before consulting with your legal department. 15 * 16 * For further information, read the top-level Openvision 17 * copyright which is contained in the top-level MIT Kerberos 18 * copyright. 19 * 20 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 21 * 22 */ 23 24 25 /* 26 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved 27 * 28 * $Header: /cvs/krbdev/krb5/src/lib/kadm5/srv/server_kdb.c,v 1.2 1998/10/30 02:54:39 marc Exp $ 29 */ 30 31 #if !defined(lint) && !defined(__CODECENTER__) 32 static char *rcsid = "$Header: /cvs/krbdev/krb5/src/lib/kadm5/srv/server_kdb.c,v 1.2 1998/10/30 02:54:39 marc Exp $"; 33 #endif 34 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <com_err.h> 38 #include <kadm5/admin.h> 39 #include <krb5.h> 40 #include "server_internal.h" 41 42 extern caddr_t xdralloc_getdata(XDR *xdrs); 43 extern void xdralloc_create(XDR *xdrs, enum xdr_op op); 44 45 krb5_principal master_princ; 46 krb5_db_entry master_db; 47 48 krb5_principal hist_princ; 49 krb5_encrypt_block hist_encblock; 50 krb5_keyblock hist_key; 51 krb5_db_entry hist_db; 52 krb5_kvno hist_kvno; 53 54 /* much of this code is stolen from the kdc. there should be some 55 library code to deal with this. */ 56 57 krb5_error_code kdb_init_master(kadm5_server_handle_t handle, 58 char *r, int from_keyboard) 59 { 60 int ret = 0; 61 char *realm; 62 krb5_keyblock tmk; 63 64 if (r == NULL) { 65 if ((ret = krb5_get_default_realm(handle->context, &realm))) 66 return ret; 67 } else { 68 realm = r; 69 } 70 71 if ((ret = krb5_db_setup_mkey_name(handle->context, 72 handle->params.mkey_name, 73 realm, NULL, &master_princ))) 74 goto done; 75 76 if (ret = krb5_db_fetch_mkey(handle->context, master_princ, 77 handle->params.enctype, 78 from_keyboard, 79 FALSE /* only prompt once */, 80 handle->params.stash_file, 81 NULL /* I'm not sure about this, 82 but it's what the kdc does --marc */, 83 &handle->master_keyblock)) 84 goto done; 85 86 if ((ret = krb5_db_init(handle->context)) != KSUCCESS) 87 goto done; 88 89 if ((ret = krb5_db_verify_master_key(handle->context, master_princ, 90 &handle->master_keyblock))) { 91 krb5_db_fini(handle->context); 92 return ret; 93 } 94 95 done: 96 if (r == NULL) 97 free(realm); 98 99 return(ret); 100 } 101 102 /* 103 * Function: kdb_init_hist 104 * 105 * Purpose: Initializes the global history variables. 106 * 107 * Arguments: 108 * 109 * handle (r) kadm5 api server handle 110 * r (r) realm of history principal to use, or NULL 111 * 112 * Effects: This function sets the value of the following global 113 * variables: 114 * 115 * hist_princ krb5_principal holding the history principal 116 * hist_db krb5_db_entry of the history principal 117 * hist_key krb5_keyblock holding the history principal's key 118 * hist_encblock krb5_encrypt_block holding the procssed hist_key 119 * hist_kvno the version number of the history key 120 * 121 * If the history principal does not already exist, this function 122 * attempts to create it with kadm5_create_principal. WARNING! 123 * If the history principal is deleted and this function is executed 124 * (by kadmind, or kadmin.local, or anything else with permission), 125 * the principal will be assigned a new random key and all existing 126 * password history information will become useless. 127 */ 128 krb5_error_code kdb_init_hist(kadm5_server_handle_t handle, char *r) 129 { 130 int ret = 0; 131 char *realm, *hist_name; 132 krb5_key_data *key_data; 133 krb5_key_salt_tuple ks[1]; 134 135 if (r == NULL) { 136 if ((ret = krb5_get_default_realm(handle->context, &realm))) 137 return ret; 138 } else { 139 realm = r; 140 } 141 142 if ((hist_name = (char *) malloc(strlen(KADM5_HIST_PRINCIPAL) + 143 strlen(realm) + 2)) == NULL) 144 goto done; 145 146 (void) sprintf(hist_name, "%s@%s", KADM5_HIST_PRINCIPAL, realm); 147 148 if ((ret = krb5_parse_name(handle->context, hist_name, &hist_princ))) 149 goto done; 150 151 if ((ret = kdb_get_entry(handle, hist_princ, &hist_db, NULL))) { 152 kadm5_principal_ent_rec ent; 153 154 if (ret != KADM5_UNK_PRINC) 155 goto done; 156 157 /* try to create the principal */ 158 159 memset(&ent, 0, sizeof(ent)); 160 161 ent.principal = hist_princ; 162 ent.max_life = KRB5_KDB_DISALLOW_ALL_TIX; 163 ent.attributes = 0; 164 165 /* this uses hist_kvno. So we set it to 2, which will be the 166 correct value once the principal is created and randomized. 167 Of course, it doesn't make sense to keep a history for the 168 history principal, anyway. */ 169 170 hist_kvno = 2; 171 ks[0].ks_enctype = handle->params.enctype; 172 ks[0].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; 173 ret = kadm5_create_principal_3(handle, &ent, 174 (KADM5_PRINCIPAL | 175 KADM5_MAX_LIFE | 176 KADM5_ATTRIBUTES), 177 1, ks, 178 "to-be-random"); 179 if (ret) 180 goto done; 181 182 /* this won't let us randomize the hist_princ. So we cheat. */ 183 184 hist_princ = NULL; 185 186 ret = kadm5_randkey_principal_3(handle, ent.principal, 0, 1, ks, 187 NULL, NULL); 188 189 hist_princ = ent.principal; 190 191 if (ret) 192 goto done; 193 194 /* now read the newly-created kdb record out of the 195 database. */ 196 197 if ((ret = kdb_get_entry(handle, hist_princ, &hist_db, NULL))) 198 goto done; 199 200 } 201 202 ret = krb5_dbe_find_enctype(handle->context, &hist_db, 203 handle->params.enctype, -1, -1, &key_data); 204 if (ret) 205 goto done; 206 207 ret = krb5_dbekd_decrypt_key_data(handle->context, 208 &handle->master_keyblock, key_data, &hist_key, NULL); 209 if (ret) 210 goto done; 211 212 hist_kvno = key_data->key_data_kvno; 213 214 done: 215 free(hist_name); 216 if (r == NULL) 217 free(realm); 218 return ret; 219 } 220 221 /* 222 * Function: kdb_get_entry 223 * 224 * Purpose: Gets an entry from the kerberos database and breaks 225 * it out into a krb5_db_entry and an osa_princ_ent_t. 226 * 227 * Arguments: 228 * 229 * handle (r) the server_handle 230 * principal (r) the principal to get 231 * kdb (w) krb5_db_entry to fill in 232 * adb (w) osa_princ_ent_rec to fill in 233 * 234 * when the caller is done with kdb and adb, kdb_free_entry must be 235 * called to release them. The adb record is filled in with the 236 * contents of the KRB5_TL_KADM_DATA record; if that record doesn't 237 * exist, an empty but valid adb record is returned. 238 */ 239 krb5_error_code 240 kdb_get_entry(kadm5_server_handle_t handle, 241 krb5_principal principal, krb5_db_entry *kdb, 242 osa_princ_ent_rec *adb) 243 { 244 krb5_error_code ret; 245 int nprincs; 246 krb5_boolean more; 247 krb5_tl_data tl_data; 248 XDR xdrs; 249 250 if (ret = krb5_db_get_principal(handle->context, principal, kdb, &nprincs, 251 &more)) 252 return(ret); 253 254 if (more) { 255 krb5_db_free_principal(handle->context, kdb, nprincs); 256 return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE); 257 } else if (nprincs != 1) { 258 krb5_db_free_principal(handle->context, kdb, nprincs); 259 return(KADM5_UNK_PRINC); 260 } 261 262 if (adb) { 263 memset(adb, 0, sizeof(*adb)); 264 265 tl_data.tl_data_type = KRB5_TL_KADM_DATA; 266 /* 267 * XXX Currently, lookup_tl_data always returns zero; it sets 268 * tl_data->tl_data_length to zero if the type isn't found. 269 * This should be fixed... 270 */ 271 if ((ret = krb5_dbe_lookup_tl_data(handle->context, kdb, &tl_data)) 272 || (tl_data.tl_data_length == 0)) { 273 /* there's no admin data. this can happen, if the admin 274 server is put into production after some principals 275 are created. In this case, return valid admin 276 data (which is all zeros with the hist_kvno filled 277 in), and when the entry is written, the admin 278 data will get stored correctly. */ 279 280 adb->admin_history_kvno = hist_kvno; 281 282 return(ret); 283 } 284 285 xdrmem_create(&xdrs, (caddr_t)tl_data.tl_data_contents, 286 tl_data.tl_data_length, XDR_DECODE); 287 if (! xdr_osa_princ_ent_rec(&xdrs, adb)) { 288 xdr_destroy(&xdrs); 289 krb5_db_free_principal(handle->context, kdb, 1); 290 return(OSA_ADB_XDR_FAILURE); 291 } 292 xdr_destroy(&xdrs); 293 } 294 295 return(0); 296 } 297 298 /* 299 * Function: kdb_free_entry 300 * 301 * Purpose: frees the resources allocated by kdb_get_entry 302 * 303 * Arguments: 304 * 305 * handle (r) the server_handle 306 * kdb (w) krb5_db_entry to fill in 307 * adb (w) osa_princ_ent_rec to fill in 308 * 309 * when the caller is done with kdb and adb, kdb_free_entry must be 310 * called to release them. 311 */ 312 313 krb5_error_code 314 kdb_free_entry(kadm5_server_handle_t handle, 315 krb5_db_entry *kdb, osa_princ_ent_rec *adb) 316 { 317 XDR xdrs; 318 319 320 if (kdb) 321 krb5_db_free_principal(handle->context, kdb, 1); 322 323 if (adb) { 324 xdrmem_create(&xdrs, NULL, 0, XDR_FREE); 325 xdr_osa_princ_ent_rec(&xdrs, adb); 326 xdr_destroy(&xdrs); 327 } 328 329 return(0); 330 } 331 332 /* 333 * Function: kdb_put_entry 334 * 335 * Purpose: Stores the osa_princ_ent_t and krb5_db_entry into to 336 * database. 337 * 338 * Arguments: 339 * 340 * handle (r) the server_handle 341 * kdb (r/w) the krb5_db_entry to store 342 * adb (r) the osa_princ_db_ent to store 343 * 344 * Effects: 345 * 346 * The last modifier field of the kdb is set to the caller at now. 347 * adb is encoded with xdr_osa_princ_ent_ret and stored in kbd as 348 * KRB5_TL_KADM_DATA. kdb is then written to the database. 349 */ 350 krb5_error_code 351 kdb_put_entry(kadm5_server_handle_t handle, 352 krb5_db_entry *kdb, osa_princ_ent_rec *adb) 353 { 354 krb5_error_code ret; 355 krb5_int32 now; 356 XDR xdrs; 357 krb5_tl_data tl_data; 358 int one; 359 360 if (ret = krb5_timeofday(handle->context, &now)) 361 return(ret); 362 363 if (ret = krb5_dbe_update_mod_princ_data(handle->context, kdb, now, 364 handle->current_caller)) 365 return(ret); 366 367 xdralloc_create(&xdrs, XDR_ENCODE); 368 if(! xdr_osa_princ_ent_rec(&xdrs, adb)) { 369 xdr_destroy(&xdrs); 370 return(OSA_ADB_XDR_FAILURE); 371 } 372 tl_data.tl_data_type = KRB5_TL_KADM_DATA; 373 tl_data.tl_data_length = xdr_getpos(&xdrs); 374 tl_data.tl_data_contents = (unsigned char *) xdralloc_getdata(&xdrs); 375 376 ret = krb5_dbe_update_tl_data(handle->context, kdb, &tl_data); 377 378 xdr_destroy(&xdrs); 379 380 if (ret) 381 return(ret); 382 383 one = 1; 384 385 if (ret = krb5_db_put_principal(handle->context, kdb, &one)) 386 return(ret); 387 388 return(0); 389 } 390 391 krb5_error_code 392 kdb_delete_entry(kadm5_server_handle_t handle, krb5_principal name) 393 { 394 int one = 1; 395 krb5_error_code ret; 396 397 ret = krb5_db_delete_principal(handle->context, name, &one); 398 399 return ret; 400 } 401 402 typedef struct _iter_data { 403 void (*func)(void *, krb5_principal); 404 void *data; 405 } iter_data; 406 407 static krb5_error_code 408 kdb_iter_func(krb5_pointer data, krb5_db_entry *kdb) 409 { 410 iter_data *id = (iter_data *) data; 411 412 (*(id->func))(id->data, kdb->princ); 413 414 return(0); 415 } 416 417 krb5_error_code 418 kdb_iter_entry(kadm5_server_handle_t handle, 419 void (*iter_fct)(void *, krb5_principal), void *data) 420 { 421 iter_data id; 422 krb5_error_code ret; 423 424 id.func = iter_fct; 425 id.data = data; 426 427 if (ret = krb5_db_iterate(handle->context, kdb_iter_func, &id)) 428 return(ret); 429 430 return(0); 431 } 432 433