2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
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
19 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
25 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
30 #if !defined(lint) && !defined(__CODECENTER__)
31 static char *rcsid
= "$Header$";
37 #include <kadm5/admin.h>
38 #include "server_internal.h"
40 extern caddr_t
xdralloc_getdata(XDR
*xdrs
);
41 extern void xdralloc_create(XDR
*xdrs
, enum xdr_op op
);
43 krb5_principal master_princ
;
44 krb5_db_entry master_db
;
46 krb5_principal hist_princ
;
47 krb5_keyblock hist_key
;
48 krb5_db_entry hist_db
;
51 /* much of this code is stolen from the kdc. there should be some
52 library code to deal with this. */
54 krb5_error_code
kdb_init_master(kadm5_server_handle_t handle
,
55 char *r
, int from_keyboard
)
59 krb5_boolean from_kbd
= FALSE
;
65 if ((ret
= krb5_get_default_realm(handle
->context
, &realm
)))
71 if ((ret
= krb5_db_setup_mkey_name(handle
->context
,
72 handle
->params
.mkey_name
,
73 realm
, NULL
, &master_princ
)))
75 /* Solaris Kerberos */
77 master_keyblock
.enctype
= handle
->params
.enctype
;
80 /* Solaris Kerberos */
81 ret
= krb5_db_fetch_mkey(handle
->context
, master_princ
,
82 handle
->params
.enctype
, from_kbd
,
83 FALSE
/* only prompt once */,
84 handle
->params
.stash_file
,
85 NULL
/* I'm not sure about this,
86 but it's what the kdc does --marc */,
87 &handle
->master_keyblock
);
91 /* Solaris Kerberos */
92 if ((ret
= krb5_db_verify_master_key(handle
->context
, master_princ
,
93 &handle
->master_keyblock
))) {
94 krb5_db_fini(handle
->context
);
106 * Function: kdb_init_hist
108 * Purpose: Initializes the global history variables.
112 * handle (r) kadm5 api server handle
113 * r (r) realm of history principal to use, or NULL
115 * Effects: This function sets the value of the following global
118 * hist_princ krb5_principal holding the history principal
119 * hist_db krb5_db_entry of the history principal
120 * hist_key krb5_keyblock holding the history principal's key
121 * hist_encblock krb5_encrypt_block holding the procssed hist_key
122 * hist_kvno the version number of the history key
124 * If the history principal does not already exist, this function
125 * attempts to create it with kadm5_create_principal. WARNING!
126 * If the history principal is deleted and this function is executed
127 * (by kadmind, or kadmin.local, or anything else with permission),
128 * the principal will be assigned a new random key and all existing
129 * password history information will become useless.
131 krb5_error_code
kdb_init_hist(kadm5_server_handle_t handle
, char *r
)
134 char *realm
, *hist_name
;
135 krb5_key_data
*key_data
;
136 krb5_key_salt_tuple ks
[1];
139 if ((ret
= krb5_get_default_realm(handle
->context
, &realm
)))
145 if ((hist_name
= (char *) malloc(strlen(KADM5_HIST_PRINCIPAL
) +
146 strlen(realm
) + 2)) == NULL
)
149 (void) sprintf(hist_name
, "%s@%s", KADM5_HIST_PRINCIPAL
, realm
);
151 if ((ret
= krb5_parse_name(handle
->context
, hist_name
, &hist_princ
)))
154 if ((ret
= kdb_get_entry(handle
, hist_princ
, &hist_db
, NULL
))) {
155 kadm5_principal_ent_rec ent
;
157 if (ret
!= KADM5_UNK_PRINC
)
160 /* try to create the principal */
162 memset(&ent
, 0, sizeof(ent
));
164 ent
.principal
= hist_princ
;
165 ent
.max_life
= KRB5_KDB_DISALLOW_ALL_TIX
;
168 /* this uses hist_kvno. So we set it to 2, which will be the
169 correct value once the principal is created and randomized.
170 Of course, it doesn't make sense to keep a history for the
171 history principal, anyway. */
174 ks
[0].ks_enctype
= handle
->params
.enctype
;
175 ks
[0].ks_salttype
= KRB5_KDB_SALTTYPE_NORMAL
;
176 ret
= kadm5_create_principal_3(handle
, &ent
,
177 (KADM5_PRINCIPAL
| KADM5_MAX_LIFE
|
184 /* this won't let us randomize the hist_princ. So we cheat. */
188 ret
= kadm5_randkey_principal_3(handle
, ent
.principal
, 0, 1, ks
,
191 hist_princ
= ent
.principal
;
196 /* now read the newly-created kdb record out of the
199 if ((ret
= kdb_get_entry(handle
, hist_princ
, &hist_db
, NULL
)))
204 ret
= krb5_dbe_find_enctype(handle
->context
, &hist_db
,
205 handle
->params
.enctype
, -1, -1, &key_data
);
209 /* Solaris Kerberos */
210 ret
= krb5_dbekd_decrypt_key_data(handle
->context
,
211 &handle
->master_keyblock
, key_data
, &hist_key
, NULL
);
215 hist_kvno
= key_data
->key_data_kvno
;
225 * Function: kdb_get_entry
227 * Purpose: Gets an entry from the kerberos database and breaks
228 * it out into a krb5_db_entry and an osa_princ_ent_t.
232 * handle (r) the server_handle
233 * principal (r) the principal to get
234 * kdb (w) krb5_db_entry to fill in
235 * adb (w) osa_princ_ent_rec to fill in
237 * when the caller is done with kdb and adb, kdb_free_entry must be
238 * called to release them. The adb record is filled in with the
239 * contents of the KRB5_TL_KADM_DATA record; if that record doesn't
240 * exist, an empty but valid adb record is returned.
243 kdb_get_entry(kadm5_server_handle_t handle
,
244 krb5_principal principal
, krb5_db_entry
*kdb
,
245 osa_princ_ent_rec
*adb
)
250 krb5_tl_data tl_data
;
253 ret
= krb5_db_get_principal(handle
->context
, principal
, kdb
, &nprincs
,
259 krb5_db_free_principal(handle
->context
, kdb
, nprincs
);
260 return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE
);
261 } else if (nprincs
!= 1) {
262 krb5_db_free_principal(handle
->context
, kdb
, nprincs
);
263 return(KADM5_UNK_PRINC
);
267 memset(adb
, 0, sizeof(*adb
));
269 tl_data
.tl_data_type
= KRB5_TL_KADM_DATA
;
271 * XXX Currently, lookup_tl_data always returns zero; it sets
272 * tl_data->tl_data_length to zero if the type isn't found.
273 * This should be fixed...
275 if ((ret
= krb5_dbe_lookup_tl_data(handle
->context
, kdb
, &tl_data
))
276 || (tl_data
.tl_data_length
== 0)) {
277 /* there's no admin data. this can happen, if the admin
278 server is put into production after some principals
279 are created. In this case, return valid admin
280 data (which is all zeros with the hist_kvno filled
281 in), and when the entry is written, the admin
282 data will get stored correctly. */
284 adb
->admin_history_kvno
= hist_kvno
;
289 /* Solaris Kerberos */
290 xdrmem_create(&xdrs
, (caddr_t
)tl_data
.tl_data_contents
,
291 tl_data
.tl_data_length
, XDR_DECODE
);
292 if (! xdr_osa_princ_ent_rec(&xdrs
, adb
)) {
294 krb5_db_free_principal(handle
->context
, kdb
, 1);
295 return(KADM5_XDR_FAILURE
);
304 * Function: kdb_free_entry
306 * Purpose: frees the resources allocated by kdb_get_entry
310 * handle (r) the server_handle
311 * kdb (w) krb5_db_entry to fill in
312 * adb (w) osa_princ_ent_rec to fill in
314 * when the caller is done with kdb and adb, kdb_free_entry must be
315 * called to release them.
319 kdb_free_entry(kadm5_server_handle_t handle
,
320 krb5_db_entry
*kdb
, osa_princ_ent_rec
*adb
)
326 krb5_db_free_principal(handle
->context
, kdb
, 1);
329 xdrmem_create(&xdrs
, NULL
, 0, XDR_FREE
);
330 xdr_osa_princ_ent_rec(&xdrs
, adb
);
338 * Function: kdb_put_entry
340 * Purpose: Stores the osa_princ_ent_t and krb5_db_entry into to
345 * handle (r) the server_handle
346 * kdb (r/w) the krb5_db_entry to store
347 * adb (r) the osa_princ_db_ent to store
351 * The last modifier field of the kdb is set to the caller at now.
352 * adb is encoded with xdr_osa_princ_ent_ret and stored in kbd as
353 * KRB5_TL_KADM_DATA. kdb is then written to the database.
356 kdb_put_entry(kadm5_server_handle_t handle
,
357 krb5_db_entry
*kdb
, osa_princ_ent_rec
*adb
)
362 krb5_tl_data tl_data
;
365 ret
= krb5_timeofday(handle
->context
, &now
);
369 ret
= krb5_dbe_update_mod_princ_data(handle
->context
, kdb
, now
,
370 handle
->current_caller
);
374 xdralloc_create(&xdrs
, XDR_ENCODE
);
375 if(! xdr_osa_princ_ent_rec(&xdrs
, adb
)) {
377 return(KADM5_XDR_FAILURE
);
379 tl_data
.tl_data_type
= KRB5_TL_KADM_DATA
;
380 tl_data
.tl_data_length
= xdr_getpos(&xdrs
);
381 /* Solaris Kerberos */
382 tl_data
.tl_data_contents
= (unsigned char *) xdralloc_getdata(&xdrs
);
384 ret
= krb5_dbe_update_tl_data(handle
->context
, kdb
, &tl_data
);
393 ret
= krb5_db_put_principal(handle
->context
, kdb
, &one
);
401 kdb_delete_entry(kadm5_server_handle_t handle
, krb5_principal name
)
406 ret
= krb5_db_delete_principal(handle
->context
, name
, &one
);
411 typedef struct _iter_data
{
412 void (*func
)(void *, krb5_principal
);
416 static krb5_error_code
417 kdb_iter_func(krb5_pointer data
, krb5_db_entry
*kdb
)
419 iter_data
*id
= (iter_data
*) data
;
421 (*(id
->func
))(id
->data
, kdb
->princ
);
427 kdb_iter_entry(kadm5_server_handle_t handle
, char *match_entry
,
428 void (*iter_fct
)(void *, krb5_principal
), void *data
)
436 /* Solaris Kerberos: added support for db_args */
437 ret
= krb5_db_iterate(handle
->context
, match_entry
, kdb_iter_func
, &id
, NULL
);