dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / krb5 / kadm5 / srv / server_kdb.c
blob5157ff83b27ea8a50e88d36a7f6f4db57f1c5602
1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /*
7 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
9 * Openvision retains the copyright to derivative works of
10 * this source code. Do *NOT* create a derivative of this
11 * source code before consulting with your legal department.
12 * Do *NOT* integrate *ANY* of this source code into another
13 * product before consulting with your legal department.
15 * For further information, read the top-level Openvision
16 * copyright which is contained in the top-level MIT Kerberos
17 * copyright.
19 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
25 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
27 * $Header$
30 static char *rcsid = "$Header$";
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include "k5-int.h"
35 #include <kadm5/admin.h>
36 #include "server_internal.h"
38 extern caddr_t xdralloc_getdata(XDR *xdrs);
39 extern void xdralloc_create(XDR *xdrs, enum xdr_op op);
41 krb5_principal master_princ;
42 krb5_db_entry master_db;
44 krb5_principal hist_princ;
45 krb5_keyblock hist_key;
46 krb5_db_entry hist_db;
47 krb5_kvno hist_kvno;
49 /* much of this code is stolen from the kdc. there should be some
50 library code to deal with this. */
52 krb5_error_code kdb_init_master(kadm5_server_handle_t handle,
53 char *r, int from_keyboard)
55 int ret = 0;
56 char *realm;
57 krb5_boolean from_kbd = FALSE;
59 if (from_keyboard)
60 from_kbd = TRUE;
62 if (r == NULL) {
63 if ((ret = krb5_get_default_realm(handle->context, &realm)))
64 return ret;
65 } else {
66 realm = r;
69 if ((ret = krb5_db_setup_mkey_name(handle->context,
70 handle->params.mkey_name,
71 realm, NULL, &master_princ)))
72 goto done;
73 /* Solaris Kerberos */
74 #if 0
75 master_keyblock.enctype = handle->params.enctype;
76 #endif
78 /* Solaris Kerberos */
79 ret = krb5_db_fetch_mkey(handle->context, master_princ,
80 handle->params.enctype, from_kbd,
81 FALSE /* only prompt once */,
82 handle->params.stash_file,
83 NULL /* I'm not sure about this,
84 but it's what the kdc does --marc */,
85 &handle->master_keyblock);
86 if (ret)
87 goto done;
89 /* Solaris Kerberos */
90 if ((ret = krb5_db_verify_master_key(handle->context, master_princ,
91 &handle->master_keyblock))) {
92 krb5_db_fini(handle->context);
93 return ret;
96 done:
97 if (r == NULL)
98 free(realm);
100 return(ret);
104 * Function: kdb_init_hist
106 * Purpose: Initializes the global history variables.
108 * Arguments:
110 * handle (r) kadm5 api server handle
111 * r (r) realm of history principal to use, or NULL
113 * Effects: This function sets the value of the following global
114 * variables:
116 * hist_princ krb5_principal holding the history principal
117 * hist_db krb5_db_entry of the history principal
118 * hist_key krb5_keyblock holding the history principal's key
119 * hist_encblock krb5_encrypt_block holding the procssed hist_key
120 * hist_kvno the version number of the history key
122 * If the history principal does not already exist, this function
123 * attempts to create it with kadm5_create_principal. WARNING!
124 * If the history principal is deleted and this function is executed
125 * (by kadmind, or kadmin.local, or anything else with permission),
126 * the principal will be assigned a new random key and all existing
127 * password history information will become useless.
129 krb5_error_code kdb_init_hist(kadm5_server_handle_t handle, char *r)
131 int ret = 0;
132 char *realm, *hist_name;
133 krb5_key_data *key_data;
134 krb5_key_salt_tuple ks[1];
136 if (r == NULL) {
137 if ((ret = krb5_get_default_realm(handle->context, &realm)))
138 return ret;
139 } else {
140 realm = r;
143 if ((hist_name = (char *) malloc(strlen(KADM5_HIST_PRINCIPAL) +
144 strlen(realm) + 2)) == NULL)
145 goto done;
147 (void) sprintf(hist_name, "%s@%s", KADM5_HIST_PRINCIPAL, realm);
149 if ((ret = krb5_parse_name(handle->context, hist_name, &hist_princ)))
150 goto done;
152 if ((ret = kdb_get_entry(handle, hist_princ, &hist_db, NULL))) {
153 kadm5_principal_ent_rec ent;
155 if (ret != KADM5_UNK_PRINC)
156 goto done;
158 /* try to create the principal */
160 memset(&ent, 0, sizeof(ent));
162 ent.principal = hist_princ;
163 ent.max_life = KRB5_KDB_DISALLOW_ALL_TIX;
164 ent.attributes = 0;
166 /* this uses hist_kvno. So we set it to 2, which will be the
167 correct value once the principal is created and randomized.
168 Of course, it doesn't make sense to keep a history for the
169 history principal, anyway. */
171 hist_kvno = 2;
172 ks[0].ks_enctype = handle->params.enctype;
173 ks[0].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL;
174 ret = kadm5_create_principal_3(handle, &ent,
175 (KADM5_PRINCIPAL | KADM5_MAX_LIFE |
176 KADM5_ATTRIBUTES),
177 1, ks,
178 "to-be-random");
179 if (ret)
180 goto done;
182 /* this won't let us randomize the hist_princ. So we cheat. */
184 hist_princ = NULL;
186 ret = kadm5_randkey_principal_3(handle, ent.principal, 0, 1, ks,
187 NULL, NULL);
189 hist_princ = ent.principal;
191 if (ret)
192 goto done;
194 /* now read the newly-created kdb record out of the
195 database. */
197 if ((ret = kdb_get_entry(handle, hist_princ, &hist_db, NULL)))
198 goto done;
202 ret = krb5_dbe_find_enctype(handle->context, &hist_db,
203 handle->params.enctype, -1, -1, &key_data);
204 if (ret)
205 goto done;
207 /* Solaris Kerberos */
208 ret = krb5_dbekd_decrypt_key_data(handle->context,
209 &handle->master_keyblock, key_data, &hist_key, NULL);
210 if (ret)
211 goto done;
213 hist_kvno = key_data->key_data_kvno;
215 done:
216 free(hist_name);
217 if (r == NULL)
218 free(realm);
219 return ret;
223 * Function: kdb_get_entry
225 * Purpose: Gets an entry from the kerberos database and breaks
226 * it out into a krb5_db_entry and an osa_princ_ent_t.
228 * Arguments:
230 * handle (r) the server_handle
231 * principal (r) the principal to get
232 * kdb (w) krb5_db_entry to fill in
233 * adb (w) osa_princ_ent_rec to fill in
235 * when the caller is done with kdb and adb, kdb_free_entry must be
236 * called to release them. The adb record is filled in with the
237 * contents of the KRB5_TL_KADM_DATA record; if that record doesn't
238 * exist, an empty but valid adb record is returned.
240 krb5_error_code
241 kdb_get_entry(kadm5_server_handle_t handle,
242 krb5_principal principal, krb5_db_entry *kdb,
243 osa_princ_ent_rec *adb)
245 krb5_error_code ret;
246 int nprincs;
247 krb5_boolean more;
248 krb5_tl_data tl_data;
249 XDR xdrs;
251 ret = krb5_db_get_principal(handle->context, principal, kdb, &nprincs,
252 &more);
253 if (ret)
254 return(ret);
256 if (more) {
257 krb5_db_free_principal(handle->context, kdb, nprincs);
258 return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
259 } else if (nprincs != 1) {
260 krb5_db_free_principal(handle->context, kdb, nprincs);
261 return(KADM5_UNK_PRINC);
264 if (adb) {
265 memset(adb, 0, sizeof(*adb));
267 tl_data.tl_data_type = KRB5_TL_KADM_DATA;
269 * XXX Currently, lookup_tl_data always returns zero; it sets
270 * tl_data->tl_data_length to zero if the type isn't found.
271 * This should be fixed...
273 if ((ret = krb5_dbe_lookup_tl_data(handle->context, kdb, &tl_data))
274 || (tl_data.tl_data_length == 0)) {
275 /* there's no admin data. this can happen, if the admin
276 server is put into production after some principals
277 are created. In this case, return valid admin
278 data (which is all zeros with the hist_kvno filled
279 in), and when the entry is written, the admin
280 data will get stored correctly. */
282 adb->admin_history_kvno = hist_kvno;
284 return(ret);
287 /* Solaris Kerberos */
288 xdrmem_create(&xdrs, (caddr_t)tl_data.tl_data_contents,
289 tl_data.tl_data_length, XDR_DECODE);
290 if (! xdr_osa_princ_ent_rec(&xdrs, adb)) {
291 xdr_destroy(&xdrs);
292 krb5_db_free_principal(handle->context, kdb, 1);
293 return(KADM5_XDR_FAILURE);
295 xdr_destroy(&xdrs);
298 return(0);
302 * Function: kdb_free_entry
304 * Purpose: frees the resources allocated by kdb_get_entry
306 * Arguments:
308 * handle (r) the server_handle
309 * kdb (w) krb5_db_entry to fill in
310 * adb (w) osa_princ_ent_rec to fill in
312 * when the caller is done with kdb and adb, kdb_free_entry must be
313 * called to release them.
316 krb5_error_code
317 kdb_free_entry(kadm5_server_handle_t handle,
318 krb5_db_entry *kdb, osa_princ_ent_rec *adb)
320 XDR xdrs;
323 if (kdb)
324 krb5_db_free_principal(handle->context, kdb, 1);
326 if (adb) {
327 xdrmem_create(&xdrs, NULL, 0, XDR_FREE);
328 xdr_osa_princ_ent_rec(&xdrs, adb);
329 xdr_destroy(&xdrs);
332 return(0);
336 * Function: kdb_put_entry
338 * Purpose: Stores the osa_princ_ent_t and krb5_db_entry into to
339 * database.
341 * Arguments:
343 * handle (r) the server_handle
344 * kdb (r/w) the krb5_db_entry to store
345 * adb (r) the osa_princ_db_ent to store
347 * Effects:
349 * The last modifier field of the kdb is set to the caller at now.
350 * adb is encoded with xdr_osa_princ_ent_ret and stored in kbd as
351 * KRB5_TL_KADM_DATA. kdb is then written to the database.
353 krb5_error_code
354 kdb_put_entry(kadm5_server_handle_t handle,
355 krb5_db_entry *kdb, osa_princ_ent_rec *adb)
357 krb5_error_code ret;
358 krb5_int32 now;
359 XDR xdrs;
360 krb5_tl_data tl_data;
361 int one;
363 ret = krb5_timeofday(handle->context, &now);
364 if (ret)
365 return(ret);
367 ret = krb5_dbe_update_mod_princ_data(handle->context, kdb, now,
368 handle->current_caller);
369 if (ret)
370 return(ret);
372 xdralloc_create(&xdrs, XDR_ENCODE);
373 if(! xdr_osa_princ_ent_rec(&xdrs, adb)) {
374 xdr_destroy(&xdrs);
375 return(KADM5_XDR_FAILURE);
377 tl_data.tl_data_type = KRB5_TL_KADM_DATA;
378 tl_data.tl_data_length = xdr_getpos(&xdrs);
379 /* Solaris Kerberos */
380 tl_data.tl_data_contents = (unsigned char *) xdralloc_getdata(&xdrs);
382 ret = krb5_dbe_update_tl_data(handle->context, kdb, &tl_data);
384 xdr_destroy(&xdrs);
386 if (ret)
387 return(ret);
389 one = 1;
391 ret = krb5_db_put_principal(handle->context, kdb, &one);
392 if (ret)
393 return(ret);
395 return(0);
398 krb5_error_code
399 kdb_delete_entry(kadm5_server_handle_t handle, krb5_principal name)
401 int one = 1;
402 krb5_error_code ret;
404 ret = krb5_db_delete_principal(handle->context, name, &one);
406 return ret;
409 typedef struct _iter_data {
410 void (*func)(void *, krb5_principal);
411 void *data;
412 } iter_data;
414 static krb5_error_code
415 kdb_iter_func(krb5_pointer data, krb5_db_entry *kdb)
417 iter_data *id = (iter_data *) data;
419 (*(id->func))(id->data, kdb->princ);
421 return(0);
424 krb5_error_code
425 kdb_iter_entry(kadm5_server_handle_t handle, char *match_entry,
426 void (*iter_fct)(void *, krb5_principal), void *data)
428 iter_data id;
429 krb5_error_code ret;
431 id.func = iter_fct;
432 id.data = data;
434 /* Solaris Kerberos: added support for db_args */
435 ret = krb5_db_iterate(handle->context, match_entry, kdb_iter_func, &id, NULL);
436 if (ret)
437 return(ret);
439 return(0);