1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /*
3*7f2fe78bSCy Schubert * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
4*7f2fe78bSCy Schubert *
5*7f2fe78bSCy Schubert * $Header$
6*7f2fe78bSCy Schubert */
7*7f2fe78bSCy Schubert #include "k5-int.h"
8*7f2fe78bSCy Schubert #include <sys/time.h>
9*7f2fe78bSCy Schubert #include <kadm5/admin.h>
10*7f2fe78bSCy Schubert #include <kdb.h>
11*7f2fe78bSCy Schubert #include "server_internal.h"
12*7f2fe78bSCy Schubert
13*7f2fe78bSCy Schubert #include <krb5/kadm5_hook_plugin.h>
14*7f2fe78bSCy Schubert
15*7f2fe78bSCy Schubert #ifdef USE_VALGRIND
16*7f2fe78bSCy Schubert #include <valgrind/memcheck.h>
17*7f2fe78bSCy Schubert #else
18*7f2fe78bSCy Schubert #define VALGRIND_CHECK_DEFINED(LVALUE) ((void)0)
19*7f2fe78bSCy Schubert #endif
20*7f2fe78bSCy Schubert
21*7f2fe78bSCy Schubert extern krb5_principal master_princ;
22*7f2fe78bSCy Schubert extern krb5_principal hist_princ;
23*7f2fe78bSCy Schubert extern krb5_keyblock master_keyblock;
24*7f2fe78bSCy Schubert extern krb5_db_entry master_db;
25*7f2fe78bSCy Schubert
26*7f2fe78bSCy Schubert static int decrypt_key_data(krb5_context context,
27*7f2fe78bSCy Schubert int n_key_data, krb5_key_data *key_data,
28*7f2fe78bSCy Schubert krb5_keyblock **keyblocks, int *n_keys);
29*7f2fe78bSCy Schubert
30*7f2fe78bSCy Schubert /*
31*7f2fe78bSCy Schubert * XXX Functions that ought to be in libkrb5.a, but aren't.
32*7f2fe78bSCy Schubert */
krb5_copy_key_data_contents(context,from,to)33*7f2fe78bSCy Schubert kadm5_ret_t krb5_copy_key_data_contents(context, from, to)
34*7f2fe78bSCy Schubert krb5_context context;
35*7f2fe78bSCy Schubert krb5_key_data *from, *to;
36*7f2fe78bSCy Schubert {
37*7f2fe78bSCy Schubert int i, idx;
38*7f2fe78bSCy Schubert
39*7f2fe78bSCy Schubert *to = *from;
40*7f2fe78bSCy Schubert
41*7f2fe78bSCy Schubert idx = (from->key_data_ver == 1 ? 1 : 2);
42*7f2fe78bSCy Schubert
43*7f2fe78bSCy Schubert for (i = 0; i < idx; i++) {
44*7f2fe78bSCy Schubert if ( from->key_data_length[i] ) {
45*7f2fe78bSCy Schubert to->key_data_contents[i] = malloc(from->key_data_length[i]);
46*7f2fe78bSCy Schubert if (to->key_data_contents[i] == NULL) {
47*7f2fe78bSCy Schubert for (i = 0; i < idx; i++)
48*7f2fe78bSCy Schubert zapfree(to->key_data_contents[i], to->key_data_length[i]);
49*7f2fe78bSCy Schubert return ENOMEM;
50*7f2fe78bSCy Schubert }
51*7f2fe78bSCy Schubert memcpy(to->key_data_contents[i], from->key_data_contents[i],
52*7f2fe78bSCy Schubert from->key_data_length[i]);
53*7f2fe78bSCy Schubert }
54*7f2fe78bSCy Schubert }
55*7f2fe78bSCy Schubert return 0;
56*7f2fe78bSCy Schubert }
57*7f2fe78bSCy Schubert
dup_tl_data(krb5_tl_data * tl)58*7f2fe78bSCy Schubert static krb5_tl_data *dup_tl_data(krb5_tl_data *tl)
59*7f2fe78bSCy Schubert {
60*7f2fe78bSCy Schubert krb5_tl_data *n;
61*7f2fe78bSCy Schubert
62*7f2fe78bSCy Schubert n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data));
63*7f2fe78bSCy Schubert if (n == NULL)
64*7f2fe78bSCy Schubert return NULL;
65*7f2fe78bSCy Schubert n->tl_data_contents = malloc(tl->tl_data_length);
66*7f2fe78bSCy Schubert if (n->tl_data_contents == NULL) {
67*7f2fe78bSCy Schubert free(n);
68*7f2fe78bSCy Schubert return NULL;
69*7f2fe78bSCy Schubert }
70*7f2fe78bSCy Schubert memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length);
71*7f2fe78bSCy Schubert n->tl_data_type = tl->tl_data_type;
72*7f2fe78bSCy Schubert n->tl_data_length = tl->tl_data_length;
73*7f2fe78bSCy Schubert n->tl_data_next = NULL;
74*7f2fe78bSCy Schubert return n;
75*7f2fe78bSCy Schubert }
76*7f2fe78bSCy Schubert
77*7f2fe78bSCy Schubert /* This is in lib/kdb/kdb_cpw.c, but is static */
cleanup_key_data(context,count,data)78*7f2fe78bSCy Schubert static void cleanup_key_data(context, count, data)
79*7f2fe78bSCy Schubert krb5_context context;
80*7f2fe78bSCy Schubert int count;
81*7f2fe78bSCy Schubert krb5_key_data * data;
82*7f2fe78bSCy Schubert {
83*7f2fe78bSCy Schubert int i;
84*7f2fe78bSCy Schubert
85*7f2fe78bSCy Schubert for (i = 0; i < count; i++)
86*7f2fe78bSCy Schubert krb5_free_key_data_contents(context, &data[i]);
87*7f2fe78bSCy Schubert free(data);
88*7f2fe78bSCy Schubert }
89*7f2fe78bSCy Schubert
90*7f2fe78bSCy Schubert /* Check whether a ks_tuple is present in an array of ks_tuples. */
91*7f2fe78bSCy Schubert static krb5_boolean
ks_tuple_present(int n_ks_tuple,krb5_key_salt_tuple * ks_tuple,krb5_key_salt_tuple * looking_for)92*7f2fe78bSCy Schubert ks_tuple_present(int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
93*7f2fe78bSCy Schubert krb5_key_salt_tuple *looking_for)
94*7f2fe78bSCy Schubert {
95*7f2fe78bSCy Schubert int i;
96*7f2fe78bSCy Schubert
97*7f2fe78bSCy Schubert for (i = 0; i < n_ks_tuple; i++) {
98*7f2fe78bSCy Schubert if (ks_tuple[i].ks_enctype == looking_for->ks_enctype &&
99*7f2fe78bSCy Schubert ks_tuple[i].ks_salttype == looking_for->ks_salttype)
100*7f2fe78bSCy Schubert return TRUE;
101*7f2fe78bSCy Schubert }
102*7f2fe78bSCy Schubert return FALSE;
103*7f2fe78bSCy Schubert }
104*7f2fe78bSCy Schubert
105*7f2fe78bSCy Schubert /* Fetch a policy if it exists; set *have_pol_out appropriately. Return
106*7f2fe78bSCy Schubert * success whether or not the policy exists. */
107*7f2fe78bSCy Schubert static kadm5_ret_t
get_policy(kadm5_server_handle_t handle,const char * name,kadm5_policy_ent_t policy_out,krb5_boolean * have_pol_out)108*7f2fe78bSCy Schubert get_policy(kadm5_server_handle_t handle, const char *name,
109*7f2fe78bSCy Schubert kadm5_policy_ent_t policy_out, krb5_boolean *have_pol_out)
110*7f2fe78bSCy Schubert {
111*7f2fe78bSCy Schubert kadm5_ret_t ret;
112*7f2fe78bSCy Schubert
113*7f2fe78bSCy Schubert *have_pol_out = FALSE;
114*7f2fe78bSCy Schubert if (name == NULL)
115*7f2fe78bSCy Schubert return 0;
116*7f2fe78bSCy Schubert ret = kadm5_get_policy(handle->lhandle, (char *)name, policy_out);
117*7f2fe78bSCy Schubert if (ret == 0)
118*7f2fe78bSCy Schubert *have_pol_out = TRUE;
119*7f2fe78bSCy Schubert return (ret == KADM5_UNK_POLICY) ? 0 : ret;
120*7f2fe78bSCy Schubert }
121*7f2fe78bSCy Schubert
122*7f2fe78bSCy Schubert /*
123*7f2fe78bSCy Schubert * Apply the -allowedkeysalts policy (see kadmin(1)'s addpol/modpol
124*7f2fe78bSCy Schubert * commands). We use the allowed key/salt tuple list as a default if
125*7f2fe78bSCy Schubert * no ks tuples as provided by the caller. We reject lists that include
126*7f2fe78bSCy Schubert * key/salts outside the policy. We re-order the requested ks tuples
127*7f2fe78bSCy Schubert * (which may be a subset of the policy) to reflect the policy order.
128*7f2fe78bSCy Schubert */
129*7f2fe78bSCy Schubert static kadm5_ret_t
apply_keysalt_policy(kadm5_server_handle_t handle,const char * policy,int n_ks_tuple,krb5_key_salt_tuple * ks_tuple,int * new_n_kstp,krb5_key_salt_tuple ** new_kstp)130*7f2fe78bSCy Schubert apply_keysalt_policy(kadm5_server_handle_t handle, const char *policy,
131*7f2fe78bSCy Schubert int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
132*7f2fe78bSCy Schubert int *new_n_kstp, krb5_key_salt_tuple **new_kstp)
133*7f2fe78bSCy Schubert {
134*7f2fe78bSCy Schubert kadm5_ret_t ret;
135*7f2fe78bSCy Schubert kadm5_policy_ent_rec polent;
136*7f2fe78bSCy Schubert krb5_boolean have_polent;
137*7f2fe78bSCy Schubert int ak_n_ks_tuple = 0;
138*7f2fe78bSCy Schubert int new_n_ks_tuple = 0;
139*7f2fe78bSCy Schubert krb5_key_salt_tuple *ak_ks_tuple = NULL;
140*7f2fe78bSCy Schubert krb5_key_salt_tuple *new_ks_tuple = NULL;
141*7f2fe78bSCy Schubert krb5_key_salt_tuple *subset;
142*7f2fe78bSCy Schubert int i, m;
143*7f2fe78bSCy Schubert
144*7f2fe78bSCy Schubert if (new_n_kstp != NULL) {
145*7f2fe78bSCy Schubert *new_n_kstp = 0;
146*7f2fe78bSCy Schubert *new_kstp = NULL;
147*7f2fe78bSCy Schubert }
148*7f2fe78bSCy Schubert
149*7f2fe78bSCy Schubert memset(&polent, 0, sizeof(polent));
150*7f2fe78bSCy Schubert ret = get_policy(handle, policy, &polent, &have_polent);
151*7f2fe78bSCy Schubert if (ret)
152*7f2fe78bSCy Schubert goto cleanup;
153*7f2fe78bSCy Schubert
154*7f2fe78bSCy Schubert if (polent.allowed_keysalts == NULL) {
155*7f2fe78bSCy Schubert /* Requested keysalts allowed or default to supported_enctypes. */
156*7f2fe78bSCy Schubert if (n_ks_tuple == 0) {
157*7f2fe78bSCy Schubert /* Default to supported_enctypes. */
158*7f2fe78bSCy Schubert n_ks_tuple = handle->params.num_keysalts;
159*7f2fe78bSCy Schubert ks_tuple = handle->params.keysalts;
160*7f2fe78bSCy Schubert }
161*7f2fe78bSCy Schubert /* Dup the requested or defaulted keysalt tuples. */
162*7f2fe78bSCy Schubert new_ks_tuple = malloc(n_ks_tuple * sizeof(*new_ks_tuple));
163*7f2fe78bSCy Schubert if (new_ks_tuple == NULL) {
164*7f2fe78bSCy Schubert ret = ENOMEM;
165*7f2fe78bSCy Schubert goto cleanup;
166*7f2fe78bSCy Schubert }
167*7f2fe78bSCy Schubert memcpy(new_ks_tuple, ks_tuple, n_ks_tuple * sizeof(*new_ks_tuple));
168*7f2fe78bSCy Schubert new_n_ks_tuple = n_ks_tuple;
169*7f2fe78bSCy Schubert ret = 0;
170*7f2fe78bSCy Schubert goto cleanup;
171*7f2fe78bSCy Schubert }
172*7f2fe78bSCy Schubert
173*7f2fe78bSCy Schubert ret = krb5_string_to_keysalts(polent.allowed_keysalts,
174*7f2fe78bSCy Schubert ",", /* Tuple separators */
175*7f2fe78bSCy Schubert NULL, /* Key/salt separators */
176*7f2fe78bSCy Schubert 0, /* No duplicates */
177*7f2fe78bSCy Schubert &ak_ks_tuple,
178*7f2fe78bSCy Schubert &ak_n_ks_tuple);
179*7f2fe78bSCy Schubert /*
180*7f2fe78bSCy Schubert * Malformed policy? Shouldn't happen, but it's remotely possible
181*7f2fe78bSCy Schubert * someday, so we don't assert, just bail.
182*7f2fe78bSCy Schubert */
183*7f2fe78bSCy Schubert if (ret)
184*7f2fe78bSCy Schubert goto cleanup;
185*7f2fe78bSCy Schubert
186*7f2fe78bSCy Schubert /* Check that the requested ks_tuples are within policy, if we have one. */
187*7f2fe78bSCy Schubert for (i = 0; i < n_ks_tuple; i++) {
188*7f2fe78bSCy Schubert if (!ks_tuple_present(ak_n_ks_tuple, ak_ks_tuple, &ks_tuple[i])) {
189*7f2fe78bSCy Schubert ret = KADM5_BAD_KEYSALTS;
190*7f2fe78bSCy Schubert goto cleanup;
191*7f2fe78bSCy Schubert }
192*7f2fe78bSCy Schubert }
193*7f2fe78bSCy Schubert
194*7f2fe78bSCy Schubert /* Have policy but no ks_tuple input? Output the policy. */
195*7f2fe78bSCy Schubert if (n_ks_tuple == 0) {
196*7f2fe78bSCy Schubert new_n_ks_tuple = ak_n_ks_tuple;
197*7f2fe78bSCy Schubert new_ks_tuple = ak_ks_tuple;
198*7f2fe78bSCy Schubert ak_ks_tuple = NULL;
199*7f2fe78bSCy Schubert goto cleanup;
200*7f2fe78bSCy Schubert }
201*7f2fe78bSCy Schubert
202*7f2fe78bSCy Schubert /*
203*7f2fe78bSCy Schubert * Now filter the policy ks tuples by the requested ones so as to
204*7f2fe78bSCy Schubert * preserve in the requested sub-set the relative ordering from the
205*7f2fe78bSCy Schubert * policy. We could optimize this (if (n_ks_tuple == ak_n_ks_tuple)
206*7f2fe78bSCy Schubert * then skip this), but we don't bother.
207*7f2fe78bSCy Schubert */
208*7f2fe78bSCy Schubert subset = calloc(n_ks_tuple, sizeof(*subset));
209*7f2fe78bSCy Schubert if (subset == NULL) {
210*7f2fe78bSCy Schubert ret = ENOMEM;
211*7f2fe78bSCy Schubert goto cleanup;
212*7f2fe78bSCy Schubert }
213*7f2fe78bSCy Schubert for (m = 0, i = 0; i < ak_n_ks_tuple && m < n_ks_tuple; i++) {
214*7f2fe78bSCy Schubert if (ks_tuple_present(n_ks_tuple, ks_tuple, &ak_ks_tuple[i]))
215*7f2fe78bSCy Schubert subset[m++] = ak_ks_tuple[i];
216*7f2fe78bSCy Schubert }
217*7f2fe78bSCy Schubert new_ks_tuple = subset;
218*7f2fe78bSCy Schubert new_n_ks_tuple = m;
219*7f2fe78bSCy Schubert ret = 0;
220*7f2fe78bSCy Schubert
221*7f2fe78bSCy Schubert cleanup:
222*7f2fe78bSCy Schubert if (have_polent)
223*7f2fe78bSCy Schubert kadm5_free_policy_ent(handle->lhandle, &polent);
224*7f2fe78bSCy Schubert free(ak_ks_tuple);
225*7f2fe78bSCy Schubert
226*7f2fe78bSCy Schubert if (new_n_kstp != NULL) {
227*7f2fe78bSCy Schubert *new_n_kstp = new_n_ks_tuple;
228*7f2fe78bSCy Schubert *new_kstp = new_ks_tuple;
229*7f2fe78bSCy Schubert } else {
230*7f2fe78bSCy Schubert free(new_ks_tuple);
231*7f2fe78bSCy Schubert }
232*7f2fe78bSCy Schubert return ret;
233*7f2fe78bSCy Schubert }
234*7f2fe78bSCy Schubert
235*7f2fe78bSCy Schubert
236*7f2fe78bSCy Schubert /*
237*7f2fe78bSCy Schubert * Set *passptr to NULL if the request looks like the first part of a krb5 1.6
238*7f2fe78bSCy Schubert * addprinc -randkey operation. The krb5 1.6 dummy password for these requests
239*7f2fe78bSCy Schubert * was invalid UTF-8, which runs afoul of the arcfour string-to-key.
240*7f2fe78bSCy Schubert */
241*7f2fe78bSCy Schubert static void
check_1_6_dummy(kadm5_principal_ent_t entry,long mask,int n_ks_tuple,krb5_key_salt_tuple * ks_tuple,char ** passptr)242*7f2fe78bSCy Schubert check_1_6_dummy(kadm5_principal_ent_t entry, long mask,
243*7f2fe78bSCy Schubert int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char **passptr)
244*7f2fe78bSCy Schubert {
245*7f2fe78bSCy Schubert int i;
246*7f2fe78bSCy Schubert char *password = *passptr;
247*7f2fe78bSCy Schubert
248*7f2fe78bSCy Schubert /* Old-style randkey operations disallowed tickets to start. */
249*7f2fe78bSCy Schubert if (password == NULL || !(mask & KADM5_ATTRIBUTES) ||
250*7f2fe78bSCy Schubert !(entry->attributes & KRB5_KDB_DISALLOW_ALL_TIX))
251*7f2fe78bSCy Schubert return;
252*7f2fe78bSCy Schubert
253*7f2fe78bSCy Schubert /* The 1.6 dummy password was the octets 1..255. */
254*7f2fe78bSCy Schubert for (i = 0; (unsigned char) password[i] == i + 1; i++);
255*7f2fe78bSCy Schubert if (password[i] != '\0' || i != 255)
256*7f2fe78bSCy Schubert return;
257*7f2fe78bSCy Schubert
258*7f2fe78bSCy Schubert /* This will make the caller use a random password instead. */
259*7f2fe78bSCy Schubert *passptr = NULL;
260*7f2fe78bSCy Schubert }
261*7f2fe78bSCy Schubert
262*7f2fe78bSCy Schubert /* Return the number of keys with the newest kvno. Assumes that all key data
263*7f2fe78bSCy Schubert * with the newest kvno are at the front of the key data array. */
264*7f2fe78bSCy Schubert static int
count_new_keys(int n_key_data,krb5_key_data * key_data)265*7f2fe78bSCy Schubert count_new_keys(int n_key_data, krb5_key_data *key_data)
266*7f2fe78bSCy Schubert {
267*7f2fe78bSCy Schubert int n;
268*7f2fe78bSCy Schubert
269*7f2fe78bSCy Schubert for (n = 1; n < n_key_data; n++) {
270*7f2fe78bSCy Schubert if (key_data[n - 1].key_data_kvno != key_data[n].key_data_kvno)
271*7f2fe78bSCy Schubert return n;
272*7f2fe78bSCy Schubert }
273*7f2fe78bSCy Schubert return n_key_data;
274*7f2fe78bSCy Schubert }
275*7f2fe78bSCy Schubert
276*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_create_principal(void * server_handle,kadm5_principal_ent_t entry,long mask,char * password)277*7f2fe78bSCy Schubert kadm5_create_principal(void *server_handle,
278*7f2fe78bSCy Schubert kadm5_principal_ent_t entry, long mask,
279*7f2fe78bSCy Schubert char *password)
280*7f2fe78bSCy Schubert {
281*7f2fe78bSCy Schubert return
282*7f2fe78bSCy Schubert kadm5_create_principal_3(server_handle, entry, mask,
283*7f2fe78bSCy Schubert 0, NULL, password);
284*7f2fe78bSCy Schubert }
285*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_create_principal_3(void * server_handle,kadm5_principal_ent_t entry,long mask,int n_ks_tuple,krb5_key_salt_tuple * ks_tuple,char * password)286*7f2fe78bSCy Schubert kadm5_create_principal_3(void *server_handle,
287*7f2fe78bSCy Schubert kadm5_principal_ent_t entry, long mask,
288*7f2fe78bSCy Schubert int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
289*7f2fe78bSCy Schubert char *password)
290*7f2fe78bSCy Schubert {
291*7f2fe78bSCy Schubert krb5_db_entry *kdb;
292*7f2fe78bSCy Schubert osa_princ_ent_rec adb;
293*7f2fe78bSCy Schubert kadm5_policy_ent_rec polent;
294*7f2fe78bSCy Schubert krb5_boolean have_polent = FALSE;
295*7f2fe78bSCy Schubert krb5_timestamp now;
296*7f2fe78bSCy Schubert krb5_tl_data *tl_data_tail;
297*7f2fe78bSCy Schubert unsigned int ret;
298*7f2fe78bSCy Schubert kadm5_server_handle_t handle = server_handle;
299*7f2fe78bSCy Schubert krb5_keyblock *act_mkey;
300*7f2fe78bSCy Schubert krb5_kvno act_kvno;
301*7f2fe78bSCy Schubert int new_n_ks_tuple = 0, i;
302*7f2fe78bSCy Schubert krb5_key_salt_tuple *new_ks_tuple = NULL;
303*7f2fe78bSCy Schubert
304*7f2fe78bSCy Schubert CHECK_HANDLE(server_handle);
305*7f2fe78bSCy Schubert
306*7f2fe78bSCy Schubert krb5_clear_error_message(handle->context);
307*7f2fe78bSCy Schubert
308*7f2fe78bSCy Schubert check_1_6_dummy(entry, mask, n_ks_tuple, ks_tuple, &password);
309*7f2fe78bSCy Schubert
310*7f2fe78bSCy Schubert /*
311*7f2fe78bSCy Schubert * Argument sanity checking, and opening up the DB
312*7f2fe78bSCy Schubert */
313*7f2fe78bSCy Schubert if (entry == NULL)
314*7f2fe78bSCy Schubert return EINVAL;
315*7f2fe78bSCy Schubert if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) ||
316*7f2fe78bSCy Schubert (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) ||
317*7f2fe78bSCy Schubert (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
318*7f2fe78bSCy Schubert (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) ||
319*7f2fe78bSCy Schubert (mask & KADM5_FAIL_AUTH_COUNT))
320*7f2fe78bSCy Schubert return KADM5_BAD_MASK;
321*7f2fe78bSCy Schubert if ((mask & KADM5_KEY_DATA) && entry->n_key_data != 0)
322*7f2fe78bSCy Schubert return KADM5_BAD_MASK;
323*7f2fe78bSCy Schubert if((mask & KADM5_POLICY) && entry->policy == NULL)
324*7f2fe78bSCy Schubert return KADM5_BAD_MASK;
325*7f2fe78bSCy Schubert if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR))
326*7f2fe78bSCy Schubert return KADM5_BAD_MASK;
327*7f2fe78bSCy Schubert if((mask & ~ALL_PRINC_MASK))
328*7f2fe78bSCy Schubert return KADM5_BAD_MASK;
329*7f2fe78bSCy Schubert if (mask & KADM5_TL_DATA) {
330*7f2fe78bSCy Schubert for (tl_data_tail = entry->tl_data; tl_data_tail != NULL;
331*7f2fe78bSCy Schubert tl_data_tail = tl_data_tail->tl_data_next) {
332*7f2fe78bSCy Schubert if (tl_data_tail->tl_data_type < 256)
333*7f2fe78bSCy Schubert return KADM5_BAD_TL_TYPE;
334*7f2fe78bSCy Schubert }
335*7f2fe78bSCy Schubert }
336*7f2fe78bSCy Schubert
337*7f2fe78bSCy Schubert /*
338*7f2fe78bSCy Schubert * Check to see if the principal exists
339*7f2fe78bSCy Schubert */
340*7f2fe78bSCy Schubert ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
341*7f2fe78bSCy Schubert
342*7f2fe78bSCy Schubert switch(ret) {
343*7f2fe78bSCy Schubert case KADM5_UNK_PRINC:
344*7f2fe78bSCy Schubert break;
345*7f2fe78bSCy Schubert case 0:
346*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, &adb);
347*7f2fe78bSCy Schubert return KADM5_DUP;
348*7f2fe78bSCy Schubert default:
349*7f2fe78bSCy Schubert return ret;
350*7f2fe78bSCy Schubert }
351*7f2fe78bSCy Schubert
352*7f2fe78bSCy Schubert kdb = calloc(1, sizeof(*kdb));
353*7f2fe78bSCy Schubert if (kdb == NULL)
354*7f2fe78bSCy Schubert return ENOMEM;
355*7f2fe78bSCy Schubert
356*7f2fe78bSCy Schubert /* In all cases the principal entry is new and key data is set; let the
357*7f2fe78bSCy Schubert * database provider know. */
358*7f2fe78bSCy Schubert kdb->mask = mask | KADM5_KEY_DATA | KADM5_PRINCIPAL;
359*7f2fe78bSCy Schubert
360*7f2fe78bSCy Schubert memset(&adb, 0, sizeof(osa_princ_ent_rec));
361*7f2fe78bSCy Schubert
362*7f2fe78bSCy Schubert /*
363*7f2fe78bSCy Schubert * If a policy was specified, load it.
364*7f2fe78bSCy Schubert * If we can not find the one specified return an error
365*7f2fe78bSCy Schubert */
366*7f2fe78bSCy Schubert if ((mask & KADM5_POLICY)) {
367*7f2fe78bSCy Schubert ret = get_policy(handle, entry->policy, &polent, &have_polent);
368*7f2fe78bSCy Schubert if (ret)
369*7f2fe78bSCy Schubert goto cleanup;
370*7f2fe78bSCy Schubert }
371*7f2fe78bSCy Schubert if (password) {
372*7f2fe78bSCy Schubert ret = passwd_check(handle, password, have_polent ? &polent : NULL,
373*7f2fe78bSCy Schubert entry->principal);
374*7f2fe78bSCy Schubert if (ret)
375*7f2fe78bSCy Schubert goto cleanup;
376*7f2fe78bSCy Schubert }
377*7f2fe78bSCy Schubert /*
378*7f2fe78bSCy Schubert * Start populating the various DB fields, using the
379*7f2fe78bSCy Schubert * "defaults" for fields that were not specified by the
380*7f2fe78bSCy Schubert * mask.
381*7f2fe78bSCy Schubert */
382*7f2fe78bSCy Schubert if ((ret = krb5_timeofday(handle->context, &now)))
383*7f2fe78bSCy Schubert goto cleanup;
384*7f2fe78bSCy Schubert
385*7f2fe78bSCy Schubert kdb->magic = KRB5_KDB_MAGIC_NUMBER;
386*7f2fe78bSCy Schubert kdb->len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */
387*7f2fe78bSCy Schubert
388*7f2fe78bSCy Schubert if ((mask & KADM5_ATTRIBUTES))
389*7f2fe78bSCy Schubert kdb->attributes = entry->attributes;
390*7f2fe78bSCy Schubert else
391*7f2fe78bSCy Schubert kdb->attributes = handle->params.flags;
392*7f2fe78bSCy Schubert
393*7f2fe78bSCy Schubert if ((mask & KADM5_MAX_LIFE))
394*7f2fe78bSCy Schubert kdb->max_life = entry->max_life;
395*7f2fe78bSCy Schubert else
396*7f2fe78bSCy Schubert kdb->max_life = handle->params.max_life;
397*7f2fe78bSCy Schubert
398*7f2fe78bSCy Schubert if (mask & KADM5_MAX_RLIFE)
399*7f2fe78bSCy Schubert kdb->max_renewable_life = entry->max_renewable_life;
400*7f2fe78bSCy Schubert else
401*7f2fe78bSCy Schubert kdb->max_renewable_life = handle->params.max_rlife;
402*7f2fe78bSCy Schubert
403*7f2fe78bSCy Schubert if ((mask & KADM5_PRINC_EXPIRE_TIME))
404*7f2fe78bSCy Schubert kdb->expiration = entry->princ_expire_time;
405*7f2fe78bSCy Schubert else
406*7f2fe78bSCy Schubert kdb->expiration = handle->params.expiration;
407*7f2fe78bSCy Schubert
408*7f2fe78bSCy Schubert kdb->pw_expiration = 0;
409*7f2fe78bSCy Schubert if (mask & KADM5_PW_EXPIRATION) {
410*7f2fe78bSCy Schubert kdb->pw_expiration = entry->pw_expiration;
411*7f2fe78bSCy Schubert } else if (have_polent && polent.pw_max_life) {
412*7f2fe78bSCy Schubert kdb->mask |= KADM5_PW_EXPIRATION;
413*7f2fe78bSCy Schubert kdb->pw_expiration = ts_incr(now, polent.pw_max_life);
414*7f2fe78bSCy Schubert }
415*7f2fe78bSCy Schubert
416*7f2fe78bSCy Schubert kdb->last_success = 0;
417*7f2fe78bSCy Schubert kdb->last_failed = 0;
418*7f2fe78bSCy Schubert kdb->fail_auth_count = 0;
419*7f2fe78bSCy Schubert
420*7f2fe78bSCy Schubert /* this is kind of gross, but in order to free the tl data, I need
421*7f2fe78bSCy Schubert to free the entire kdb entry, and that will try to free the
422*7f2fe78bSCy Schubert principal. */
423*7f2fe78bSCy Schubert
424*7f2fe78bSCy Schubert ret = krb5_copy_principal(handle->context, entry->principal, &kdb->princ);
425*7f2fe78bSCy Schubert if (ret)
426*7f2fe78bSCy Schubert goto cleanup;
427*7f2fe78bSCy Schubert
428*7f2fe78bSCy Schubert if ((ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now)))
429*7f2fe78bSCy Schubert goto cleanup;
430*7f2fe78bSCy Schubert
431*7f2fe78bSCy Schubert if (mask & KADM5_TL_DATA) {
432*7f2fe78bSCy Schubert /* splice entry->tl_data onto the front of kdb->tl_data */
433*7f2fe78bSCy Schubert for (tl_data_tail = entry->tl_data; tl_data_tail;
434*7f2fe78bSCy Schubert tl_data_tail = tl_data_tail->tl_data_next)
435*7f2fe78bSCy Schubert {
436*7f2fe78bSCy Schubert ret = krb5_dbe_update_tl_data(handle->context, kdb, tl_data_tail);
437*7f2fe78bSCy Schubert if( ret )
438*7f2fe78bSCy Schubert goto cleanup;
439*7f2fe78bSCy Schubert }
440*7f2fe78bSCy Schubert }
441*7f2fe78bSCy Schubert
442*7f2fe78bSCy Schubert /*
443*7f2fe78bSCy Schubert * We need to have setup the TL data, so we have strings, so we can
444*7f2fe78bSCy Schubert * check enctype policy, which is why we check/initialize ks_tuple
445*7f2fe78bSCy Schubert * this late.
446*7f2fe78bSCy Schubert */
447*7f2fe78bSCy Schubert ret = apply_keysalt_policy(handle, entry->policy, n_ks_tuple, ks_tuple,
448*7f2fe78bSCy Schubert &new_n_ks_tuple, &new_ks_tuple);
449*7f2fe78bSCy Schubert if (ret)
450*7f2fe78bSCy Schubert goto cleanup;
451*7f2fe78bSCy Schubert
452*7f2fe78bSCy Schubert /* initialize the keys */
453*7f2fe78bSCy Schubert
454*7f2fe78bSCy Schubert ret = kdb_get_active_mkey(handle, &act_kvno, &act_mkey);
455*7f2fe78bSCy Schubert if (ret)
456*7f2fe78bSCy Schubert goto cleanup;
457*7f2fe78bSCy Schubert
458*7f2fe78bSCy Schubert if (mask & KADM5_KEY_DATA) {
459*7f2fe78bSCy Schubert /* The client requested no keys for this principal. */
460*7f2fe78bSCy Schubert assert(entry->n_key_data == 0);
461*7f2fe78bSCy Schubert } else if (password) {
462*7f2fe78bSCy Schubert ret = krb5_dbe_cpw(handle->context, act_mkey, new_ks_tuple,
463*7f2fe78bSCy Schubert new_n_ks_tuple, password,
464*7f2fe78bSCy Schubert (mask & KADM5_KVNO)?entry->kvno:1,
465*7f2fe78bSCy Schubert FALSE, kdb);
466*7f2fe78bSCy Schubert } else {
467*7f2fe78bSCy Schubert /* Null password means create with random key (new in 1.8). */
468*7f2fe78bSCy Schubert ret = krb5_dbe_crk(handle->context, &master_keyblock,
469*7f2fe78bSCy Schubert new_ks_tuple, new_n_ks_tuple, FALSE, kdb);
470*7f2fe78bSCy Schubert if (mask & KADM5_KVNO) {
471*7f2fe78bSCy Schubert for (i = 0; i < kdb->n_key_data; i++)
472*7f2fe78bSCy Schubert kdb->key_data[i].key_data_kvno = entry->kvno;
473*7f2fe78bSCy Schubert }
474*7f2fe78bSCy Schubert }
475*7f2fe78bSCy Schubert if (ret)
476*7f2fe78bSCy Schubert goto cleanup;
477*7f2fe78bSCy Schubert
478*7f2fe78bSCy Schubert /* Record the master key VNO used to encrypt this entry's keys */
479*7f2fe78bSCy Schubert ret = krb5_dbe_update_mkvno(handle->context, kdb, act_kvno);
480*7f2fe78bSCy Schubert if (ret)
481*7f2fe78bSCy Schubert goto cleanup;
482*7f2fe78bSCy Schubert
483*7f2fe78bSCy Schubert ret = k5_kadm5_hook_create(handle->context, handle->hook_handles,
484*7f2fe78bSCy Schubert KADM5_HOOK_STAGE_PRECOMMIT, entry, mask,
485*7f2fe78bSCy Schubert new_n_ks_tuple, new_ks_tuple, password);
486*7f2fe78bSCy Schubert if (ret)
487*7f2fe78bSCy Schubert goto cleanup;
488*7f2fe78bSCy Schubert
489*7f2fe78bSCy Schubert /* populate the admin-server-specific fields. In the OV server,
490*7f2fe78bSCy Schubert this used to be in a separate database. Since there's already
491*7f2fe78bSCy Schubert marshalling code for the admin fields, to keep things simple,
492*7f2fe78bSCy Schubert I'm going to keep it, and make all the admin stuff occupy a
493*7f2fe78bSCy Schubert single tl_data record, */
494*7f2fe78bSCy Schubert
495*7f2fe78bSCy Schubert adb.admin_history_kvno = INITIAL_HIST_KVNO;
496*7f2fe78bSCy Schubert if (mask & KADM5_POLICY) {
497*7f2fe78bSCy Schubert adb.aux_attributes = KADM5_POLICY;
498*7f2fe78bSCy Schubert
499*7f2fe78bSCy Schubert /* this does *not* need to be strdup'ed, because adb is xdr */
500*7f2fe78bSCy Schubert /* encoded in osa_adb_create_princ, and not ever freed */
501*7f2fe78bSCy Schubert
502*7f2fe78bSCy Schubert adb.policy = entry->policy;
503*7f2fe78bSCy Schubert }
504*7f2fe78bSCy Schubert
505*7f2fe78bSCy Schubert /* store the new db entry */
506*7f2fe78bSCy Schubert ret = kdb_put_entry(handle, kdb, &adb);
507*7f2fe78bSCy Schubert
508*7f2fe78bSCy Schubert (void) k5_kadm5_hook_create(handle->context, handle->hook_handles,
509*7f2fe78bSCy Schubert KADM5_HOOK_STAGE_POSTCOMMIT, entry, mask,
510*7f2fe78bSCy Schubert new_n_ks_tuple, new_ks_tuple, password);
511*7f2fe78bSCy Schubert
512*7f2fe78bSCy Schubert cleanup:
513*7f2fe78bSCy Schubert free(new_ks_tuple);
514*7f2fe78bSCy Schubert krb5_db_free_principal(handle->context, kdb);
515*7f2fe78bSCy Schubert if (have_polent)
516*7f2fe78bSCy Schubert (void) kadm5_free_policy_ent(handle->lhandle, &polent);
517*7f2fe78bSCy Schubert return ret;
518*7f2fe78bSCy Schubert }
519*7f2fe78bSCy Schubert
520*7f2fe78bSCy Schubert
521*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_delete_principal(void * server_handle,krb5_principal principal)522*7f2fe78bSCy Schubert kadm5_delete_principal(void *server_handle, krb5_principal principal)
523*7f2fe78bSCy Schubert {
524*7f2fe78bSCy Schubert unsigned int ret;
525*7f2fe78bSCy Schubert krb5_db_entry *kdb;
526*7f2fe78bSCy Schubert osa_princ_ent_rec adb;
527*7f2fe78bSCy Schubert kadm5_server_handle_t handle = server_handle;
528*7f2fe78bSCy Schubert
529*7f2fe78bSCy Schubert CHECK_HANDLE(server_handle);
530*7f2fe78bSCy Schubert
531*7f2fe78bSCy Schubert krb5_clear_error_message(handle->context);
532*7f2fe78bSCy Schubert
533*7f2fe78bSCy Schubert if (principal == NULL)
534*7f2fe78bSCy Schubert return EINVAL;
535*7f2fe78bSCy Schubert
536*7f2fe78bSCy Schubert /* Deleting K/M is mostly unrecoverable, so don't allow it. */
537*7f2fe78bSCy Schubert if (krb5_principal_compare(handle->context, principal, master_princ))
538*7f2fe78bSCy Schubert return KADM5_PROTECT_PRINCIPAL;
539*7f2fe78bSCy Schubert
540*7f2fe78bSCy Schubert if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
541*7f2fe78bSCy Schubert return(ret);
542*7f2fe78bSCy Schubert ret = k5_kadm5_hook_remove(handle->context, handle->hook_handles,
543*7f2fe78bSCy Schubert KADM5_HOOK_STAGE_PRECOMMIT, principal);
544*7f2fe78bSCy Schubert if (ret) {
545*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, &adb);
546*7f2fe78bSCy Schubert return ret;
547*7f2fe78bSCy Schubert }
548*7f2fe78bSCy Schubert
549*7f2fe78bSCy Schubert ret = kdb_delete_entry(handle, principal);
550*7f2fe78bSCy Schubert
551*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, &adb);
552*7f2fe78bSCy Schubert
553*7f2fe78bSCy Schubert if (ret == 0)
554*7f2fe78bSCy Schubert (void) k5_kadm5_hook_remove(handle->context,
555*7f2fe78bSCy Schubert handle->hook_handles,
556*7f2fe78bSCy Schubert KADM5_HOOK_STAGE_POSTCOMMIT, principal);
557*7f2fe78bSCy Schubert
558*7f2fe78bSCy Schubert return ret;
559*7f2fe78bSCy Schubert }
560*7f2fe78bSCy Schubert
561*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_modify_principal(void * server_handle,kadm5_principal_ent_t entry,long mask)562*7f2fe78bSCy Schubert kadm5_modify_principal(void *server_handle,
563*7f2fe78bSCy Schubert kadm5_principal_ent_t entry, long mask)
564*7f2fe78bSCy Schubert {
565*7f2fe78bSCy Schubert int ret, ret2, i;
566*7f2fe78bSCy Schubert kadm5_policy_ent_rec pol;
567*7f2fe78bSCy Schubert krb5_boolean have_pol = FALSE;
568*7f2fe78bSCy Schubert krb5_db_entry *kdb;
569*7f2fe78bSCy Schubert krb5_tl_data *tl_data_orig;
570*7f2fe78bSCy Schubert osa_princ_ent_rec adb;
571*7f2fe78bSCy Schubert kadm5_server_handle_t handle = server_handle;
572*7f2fe78bSCy Schubert
573*7f2fe78bSCy Schubert CHECK_HANDLE(server_handle);
574*7f2fe78bSCy Schubert
575*7f2fe78bSCy Schubert krb5_clear_error_message(handle->context);
576*7f2fe78bSCy Schubert
577*7f2fe78bSCy Schubert if(entry == NULL)
578*7f2fe78bSCy Schubert return EINVAL;
579*7f2fe78bSCy Schubert if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) ||
580*7f2fe78bSCy Schubert (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) ||
581*7f2fe78bSCy Schubert (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
582*7f2fe78bSCy Schubert (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) ||
583*7f2fe78bSCy Schubert (mask & KADM5_LAST_FAILED))
584*7f2fe78bSCy Schubert return KADM5_BAD_MASK;
585*7f2fe78bSCy Schubert if((mask & ~ALL_PRINC_MASK))
586*7f2fe78bSCy Schubert return KADM5_BAD_MASK;
587*7f2fe78bSCy Schubert if((mask & KADM5_POLICY) && entry->policy == NULL)
588*7f2fe78bSCy Schubert return KADM5_BAD_MASK;
589*7f2fe78bSCy Schubert if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR))
590*7f2fe78bSCy Schubert return KADM5_BAD_MASK;
591*7f2fe78bSCy Schubert if (mask & KADM5_TL_DATA) {
592*7f2fe78bSCy Schubert tl_data_orig = entry->tl_data;
593*7f2fe78bSCy Schubert while (tl_data_orig) {
594*7f2fe78bSCy Schubert if (tl_data_orig->tl_data_type < 256)
595*7f2fe78bSCy Schubert return KADM5_BAD_TL_TYPE;
596*7f2fe78bSCy Schubert tl_data_orig = tl_data_orig->tl_data_next;
597*7f2fe78bSCy Schubert }
598*7f2fe78bSCy Schubert }
599*7f2fe78bSCy Schubert
600*7f2fe78bSCy Schubert ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
601*7f2fe78bSCy Schubert if (ret)
602*7f2fe78bSCy Schubert return(ret);
603*7f2fe78bSCy Schubert
604*7f2fe78bSCy Schubert /* Let the mask propagate to the database provider. */
605*7f2fe78bSCy Schubert kdb->mask = mask;
606*7f2fe78bSCy Schubert
607*7f2fe78bSCy Schubert /*
608*7f2fe78bSCy Schubert * This is pretty much the same as create ...
609*7f2fe78bSCy Schubert */
610*7f2fe78bSCy Schubert
611*7f2fe78bSCy Schubert if ((mask & KADM5_POLICY)) {
612*7f2fe78bSCy Schubert ret = get_policy(handle, entry->policy, &pol, &have_pol);
613*7f2fe78bSCy Schubert if (ret)
614*7f2fe78bSCy Schubert goto done;
615*7f2fe78bSCy Schubert
616*7f2fe78bSCy Schubert /* set us up to use the new policy */
617*7f2fe78bSCy Schubert adb.aux_attributes |= KADM5_POLICY;
618*7f2fe78bSCy Schubert if (adb.policy)
619*7f2fe78bSCy Schubert free(adb.policy);
620*7f2fe78bSCy Schubert adb.policy = strdup(entry->policy);
621*7f2fe78bSCy Schubert }
622*7f2fe78bSCy Schubert
623*7f2fe78bSCy Schubert if (mask & KADM5_PW_EXPIRATION) {
624*7f2fe78bSCy Schubert kdb->pw_expiration = entry->pw_expiration;
625*7f2fe78bSCy Schubert } else if (have_pol) {
626*7f2fe78bSCy Schubert /* set pw_max_life based on new policy */
627*7f2fe78bSCy Schubert kdb->mask |= KADM5_PW_EXPIRATION;
628*7f2fe78bSCy Schubert if (pol.pw_max_life) {
629*7f2fe78bSCy Schubert ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb,
630*7f2fe78bSCy Schubert &kdb->pw_expiration);
631*7f2fe78bSCy Schubert if (ret)
632*7f2fe78bSCy Schubert goto done;
633*7f2fe78bSCy Schubert kdb->pw_expiration = ts_incr(kdb->pw_expiration, pol.pw_max_life);
634*7f2fe78bSCy Schubert } else {
635*7f2fe78bSCy Schubert kdb->pw_expiration = 0;
636*7f2fe78bSCy Schubert }
637*7f2fe78bSCy Schubert }
638*7f2fe78bSCy Schubert
639*7f2fe78bSCy Schubert if ((mask & KADM5_POLICY_CLR) && (adb.aux_attributes & KADM5_POLICY)) {
640*7f2fe78bSCy Schubert free(adb.policy);
641*7f2fe78bSCy Schubert adb.policy = NULL;
642*7f2fe78bSCy Schubert adb.aux_attributes &= ~KADM5_POLICY;
643*7f2fe78bSCy Schubert kdb->pw_expiration = 0;
644*7f2fe78bSCy Schubert }
645*7f2fe78bSCy Schubert
646*7f2fe78bSCy Schubert if ((mask & KADM5_ATTRIBUTES))
647*7f2fe78bSCy Schubert kdb->attributes = entry->attributes;
648*7f2fe78bSCy Schubert if ((mask & KADM5_MAX_LIFE))
649*7f2fe78bSCy Schubert kdb->max_life = entry->max_life;
650*7f2fe78bSCy Schubert if ((mask & KADM5_PRINC_EXPIRE_TIME))
651*7f2fe78bSCy Schubert kdb->expiration = entry->princ_expire_time;
652*7f2fe78bSCy Schubert if (mask & KADM5_MAX_RLIFE)
653*7f2fe78bSCy Schubert kdb->max_renewable_life = entry->max_renewable_life;
654*7f2fe78bSCy Schubert
655*7f2fe78bSCy Schubert if((mask & KADM5_KVNO)) {
656*7f2fe78bSCy Schubert for (i = 0; i < kdb->n_key_data; i++)
657*7f2fe78bSCy Schubert kdb->key_data[i].key_data_kvno = entry->kvno;
658*7f2fe78bSCy Schubert }
659*7f2fe78bSCy Schubert
660*7f2fe78bSCy Schubert if (mask & KADM5_TL_DATA) {
661*7f2fe78bSCy Schubert krb5_tl_data *tl;
662*7f2fe78bSCy Schubert
663*7f2fe78bSCy Schubert /* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writing */
664*7f2fe78bSCy Schubert
665*7f2fe78bSCy Schubert for (tl = entry->tl_data; tl;
666*7f2fe78bSCy Schubert tl = tl->tl_data_next)
667*7f2fe78bSCy Schubert {
668*7f2fe78bSCy Schubert ret = krb5_dbe_update_tl_data(handle->context, kdb, tl);
669*7f2fe78bSCy Schubert if( ret )
670*7f2fe78bSCy Schubert {
671*7f2fe78bSCy Schubert goto done;
672*7f2fe78bSCy Schubert }
673*7f2fe78bSCy Schubert }
674*7f2fe78bSCy Schubert }
675*7f2fe78bSCy Schubert
676*7f2fe78bSCy Schubert /*
677*7f2fe78bSCy Schubert * Setting entry->fail_auth_count to 0 can be used to manually unlock
678*7f2fe78bSCy Schubert * an account. It is not possible to set fail_auth_count to any other
679*7f2fe78bSCy Schubert * value using kadmin.
680*7f2fe78bSCy Schubert */
681*7f2fe78bSCy Schubert if (mask & KADM5_FAIL_AUTH_COUNT) {
682*7f2fe78bSCy Schubert if (entry->fail_auth_count != 0) {
683*7f2fe78bSCy Schubert ret = KADM5_BAD_SERVER_PARAMS;
684*7f2fe78bSCy Schubert goto done;
685*7f2fe78bSCy Schubert }
686*7f2fe78bSCy Schubert
687*7f2fe78bSCy Schubert kdb->fail_auth_count = 0;
688*7f2fe78bSCy Schubert }
689*7f2fe78bSCy Schubert
690*7f2fe78bSCy Schubert ret = k5_kadm5_hook_modify(handle->context, handle->hook_handles,
691*7f2fe78bSCy Schubert KADM5_HOOK_STAGE_PRECOMMIT, entry, mask);
692*7f2fe78bSCy Schubert if (ret)
693*7f2fe78bSCy Schubert goto done;
694*7f2fe78bSCy Schubert
695*7f2fe78bSCy Schubert ret = kdb_put_entry(handle, kdb, &adb);
696*7f2fe78bSCy Schubert if (ret) goto done;
697*7f2fe78bSCy Schubert (void) k5_kadm5_hook_modify(handle->context, handle->hook_handles,
698*7f2fe78bSCy Schubert KADM5_HOOK_STAGE_POSTCOMMIT, entry, mask);
699*7f2fe78bSCy Schubert
700*7f2fe78bSCy Schubert ret = KADM5_OK;
701*7f2fe78bSCy Schubert done:
702*7f2fe78bSCy Schubert if (have_pol) {
703*7f2fe78bSCy Schubert ret2 = kadm5_free_policy_ent(handle->lhandle, &pol);
704*7f2fe78bSCy Schubert ret = ret ? ret : ret2;
705*7f2fe78bSCy Schubert }
706*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, &adb);
707*7f2fe78bSCy Schubert return ret;
708*7f2fe78bSCy Schubert }
709*7f2fe78bSCy Schubert
710*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_rename_principal(void * server_handle,krb5_principal source,krb5_principal target)711*7f2fe78bSCy Schubert kadm5_rename_principal(void *server_handle,
712*7f2fe78bSCy Schubert krb5_principal source, krb5_principal target)
713*7f2fe78bSCy Schubert {
714*7f2fe78bSCy Schubert krb5_db_entry *kdb;
715*7f2fe78bSCy Schubert osa_princ_ent_rec adb;
716*7f2fe78bSCy Schubert krb5_error_code ret;
717*7f2fe78bSCy Schubert kadm5_server_handle_t handle = server_handle;
718*7f2fe78bSCy Schubert
719*7f2fe78bSCy Schubert CHECK_HANDLE(server_handle);
720*7f2fe78bSCy Schubert
721*7f2fe78bSCy Schubert krb5_clear_error_message(handle->context);
722*7f2fe78bSCy Schubert
723*7f2fe78bSCy Schubert if (source == NULL || target == NULL)
724*7f2fe78bSCy Schubert return EINVAL;
725*7f2fe78bSCy Schubert
726*7f2fe78bSCy Schubert if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) {
727*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, &adb);
728*7f2fe78bSCy Schubert return(KADM5_DUP);
729*7f2fe78bSCy Schubert }
730*7f2fe78bSCy Schubert
731*7f2fe78bSCy Schubert ret = k5_kadm5_hook_rename(handle->context, handle->hook_handles,
732*7f2fe78bSCy Schubert KADM5_HOOK_STAGE_PRECOMMIT, source, target);
733*7f2fe78bSCy Schubert if (ret)
734*7f2fe78bSCy Schubert return ret;
735*7f2fe78bSCy Schubert
736*7f2fe78bSCy Schubert ret = krb5_db_rename_principal(handle->context, source, target);
737*7f2fe78bSCy Schubert if (ret)
738*7f2fe78bSCy Schubert return ret;
739*7f2fe78bSCy Schubert
740*7f2fe78bSCy Schubert /* Update the principal mod data. */
741*7f2fe78bSCy Schubert ret = kdb_get_entry(handle, target, &kdb, &adb);
742*7f2fe78bSCy Schubert if (ret)
743*7f2fe78bSCy Schubert return ret;
744*7f2fe78bSCy Schubert kdb->mask = 0;
745*7f2fe78bSCy Schubert ret = kdb_put_entry(handle, kdb, &adb);
746*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, &adb);
747*7f2fe78bSCy Schubert if (ret)
748*7f2fe78bSCy Schubert return ret;
749*7f2fe78bSCy Schubert
750*7f2fe78bSCy Schubert (void) k5_kadm5_hook_rename(handle->context, handle->hook_handles,
751*7f2fe78bSCy Schubert KADM5_HOOK_STAGE_POSTCOMMIT, source, target);
752*7f2fe78bSCy Schubert return 0;
753*7f2fe78bSCy Schubert }
754*7f2fe78bSCy Schubert
755*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_get_principal(void * server_handle,krb5_principal principal,kadm5_principal_ent_t entry,long in_mask)756*7f2fe78bSCy Schubert kadm5_get_principal(void *server_handle, krb5_principal principal,
757*7f2fe78bSCy Schubert kadm5_principal_ent_t entry,
758*7f2fe78bSCy Schubert long in_mask)
759*7f2fe78bSCy Schubert {
760*7f2fe78bSCy Schubert krb5_db_entry *kdb;
761*7f2fe78bSCy Schubert osa_princ_ent_rec adb;
762*7f2fe78bSCy Schubert krb5_error_code ret = 0;
763*7f2fe78bSCy Schubert long mask;
764*7f2fe78bSCy Schubert int i;
765*7f2fe78bSCy Schubert kadm5_server_handle_t handle = server_handle;
766*7f2fe78bSCy Schubert
767*7f2fe78bSCy Schubert CHECK_HANDLE(server_handle);
768*7f2fe78bSCy Schubert
769*7f2fe78bSCy Schubert krb5_clear_error_message(handle->context);
770*7f2fe78bSCy Schubert
771*7f2fe78bSCy Schubert /*
772*7f2fe78bSCy Schubert * In version 1, all the defined fields are always returned.
773*7f2fe78bSCy Schubert * entry is a pointer to a kadm5_principal_ent_t_v1 that should be
774*7f2fe78bSCy Schubert * filled with allocated memory.
775*7f2fe78bSCy Schubert */
776*7f2fe78bSCy Schubert mask = in_mask;
777*7f2fe78bSCy Schubert
778*7f2fe78bSCy Schubert memset(entry, 0, sizeof(*entry));
779*7f2fe78bSCy Schubert
780*7f2fe78bSCy Schubert if (principal == NULL)
781*7f2fe78bSCy Schubert return EINVAL;
782*7f2fe78bSCy Schubert
783*7f2fe78bSCy Schubert if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
784*7f2fe78bSCy Schubert return ret;
785*7f2fe78bSCy Schubert
786*7f2fe78bSCy Schubert if ((mask & KADM5_POLICY) &&
787*7f2fe78bSCy Schubert adb.policy && (adb.aux_attributes & KADM5_POLICY)) {
788*7f2fe78bSCy Schubert if ((entry->policy = strdup(adb.policy)) == NULL) {
789*7f2fe78bSCy Schubert ret = ENOMEM;
790*7f2fe78bSCy Schubert goto done;
791*7f2fe78bSCy Schubert }
792*7f2fe78bSCy Schubert }
793*7f2fe78bSCy Schubert
794*7f2fe78bSCy Schubert if (mask & KADM5_AUX_ATTRIBUTES)
795*7f2fe78bSCy Schubert entry->aux_attributes = adb.aux_attributes;
796*7f2fe78bSCy Schubert
797*7f2fe78bSCy Schubert if ((mask & KADM5_PRINCIPAL) &&
798*7f2fe78bSCy Schubert (ret = krb5_copy_principal(handle->context, kdb->princ,
799*7f2fe78bSCy Schubert &entry->principal))) {
800*7f2fe78bSCy Schubert goto done;
801*7f2fe78bSCy Schubert }
802*7f2fe78bSCy Schubert
803*7f2fe78bSCy Schubert if (mask & KADM5_PRINC_EXPIRE_TIME)
804*7f2fe78bSCy Schubert entry->princ_expire_time = kdb->expiration;
805*7f2fe78bSCy Schubert
806*7f2fe78bSCy Schubert if ((mask & KADM5_LAST_PWD_CHANGE) &&
807*7f2fe78bSCy Schubert (ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb,
808*7f2fe78bSCy Schubert &(entry->last_pwd_change)))) {
809*7f2fe78bSCy Schubert goto done;
810*7f2fe78bSCy Schubert }
811*7f2fe78bSCy Schubert
812*7f2fe78bSCy Schubert if (mask & KADM5_PW_EXPIRATION)
813*7f2fe78bSCy Schubert entry->pw_expiration = kdb->pw_expiration;
814*7f2fe78bSCy Schubert if (mask & KADM5_MAX_LIFE)
815*7f2fe78bSCy Schubert entry->max_life = kdb->max_life;
816*7f2fe78bSCy Schubert
817*7f2fe78bSCy Schubert /* this is a little non-sensical because the function returns two */
818*7f2fe78bSCy Schubert /* values that must be checked separately against the mask */
819*7f2fe78bSCy Schubert if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) {
820*7f2fe78bSCy Schubert ret = krb5_dbe_lookup_mod_princ_data(handle->context, kdb,
821*7f2fe78bSCy Schubert &(entry->mod_date),
822*7f2fe78bSCy Schubert &(entry->mod_name));
823*7f2fe78bSCy Schubert if (ret) {
824*7f2fe78bSCy Schubert goto done;
825*7f2fe78bSCy Schubert }
826*7f2fe78bSCy Schubert
827*7f2fe78bSCy Schubert if (! (mask & KADM5_MOD_TIME))
828*7f2fe78bSCy Schubert entry->mod_date = 0;
829*7f2fe78bSCy Schubert if (! (mask & KADM5_MOD_NAME)) {
830*7f2fe78bSCy Schubert krb5_free_principal(handle->context, entry->mod_name);
831*7f2fe78bSCy Schubert entry->mod_name = NULL;
832*7f2fe78bSCy Schubert }
833*7f2fe78bSCy Schubert }
834*7f2fe78bSCy Schubert
835*7f2fe78bSCy Schubert if (mask & KADM5_ATTRIBUTES)
836*7f2fe78bSCy Schubert entry->attributes = kdb->attributes;
837*7f2fe78bSCy Schubert
838*7f2fe78bSCy Schubert if (mask & KADM5_KVNO)
839*7f2fe78bSCy Schubert for (entry->kvno = 0, i=0; i<kdb->n_key_data; i++)
840*7f2fe78bSCy Schubert if ((krb5_kvno) kdb->key_data[i].key_data_kvno > entry->kvno)
841*7f2fe78bSCy Schubert entry->kvno = kdb->key_data[i].key_data_kvno;
842*7f2fe78bSCy Schubert
843*7f2fe78bSCy Schubert if (mask & KADM5_MKVNO) {
844*7f2fe78bSCy Schubert ret = krb5_dbe_get_mkvno(handle->context, kdb, &entry->mkvno);
845*7f2fe78bSCy Schubert if (ret)
846*7f2fe78bSCy Schubert goto done;
847*7f2fe78bSCy Schubert }
848*7f2fe78bSCy Schubert
849*7f2fe78bSCy Schubert if (mask & KADM5_MAX_RLIFE)
850*7f2fe78bSCy Schubert entry->max_renewable_life = kdb->max_renewable_life;
851*7f2fe78bSCy Schubert if (mask & KADM5_LAST_SUCCESS)
852*7f2fe78bSCy Schubert entry->last_success = kdb->last_success;
853*7f2fe78bSCy Schubert if (mask & KADM5_LAST_FAILED)
854*7f2fe78bSCy Schubert entry->last_failed = kdb->last_failed;
855*7f2fe78bSCy Schubert if (mask & KADM5_FAIL_AUTH_COUNT)
856*7f2fe78bSCy Schubert entry->fail_auth_count = kdb->fail_auth_count;
857*7f2fe78bSCy Schubert if (mask & KADM5_TL_DATA) {
858*7f2fe78bSCy Schubert krb5_tl_data *tl, *tl2;
859*7f2fe78bSCy Schubert
860*7f2fe78bSCy Schubert entry->tl_data = NULL;
861*7f2fe78bSCy Schubert
862*7f2fe78bSCy Schubert tl = kdb->tl_data;
863*7f2fe78bSCy Schubert while (tl) {
864*7f2fe78bSCy Schubert if (tl->tl_data_type > 255) {
865*7f2fe78bSCy Schubert if ((tl2 = dup_tl_data(tl)) == NULL) {
866*7f2fe78bSCy Schubert ret = ENOMEM;
867*7f2fe78bSCy Schubert goto done;
868*7f2fe78bSCy Schubert }
869*7f2fe78bSCy Schubert tl2->tl_data_next = entry->tl_data;
870*7f2fe78bSCy Schubert entry->tl_data = tl2;
871*7f2fe78bSCy Schubert entry->n_tl_data++;
872*7f2fe78bSCy Schubert }
873*7f2fe78bSCy Schubert
874*7f2fe78bSCy Schubert tl = tl->tl_data_next;
875*7f2fe78bSCy Schubert }
876*7f2fe78bSCy Schubert }
877*7f2fe78bSCy Schubert if (mask & KADM5_KEY_DATA) {
878*7f2fe78bSCy Schubert entry->n_key_data = kdb->n_key_data;
879*7f2fe78bSCy Schubert if(entry->n_key_data) {
880*7f2fe78bSCy Schubert entry->key_data = k5calloc(entry->n_key_data,
881*7f2fe78bSCy Schubert sizeof(krb5_key_data), &ret);
882*7f2fe78bSCy Schubert if (entry->key_data == NULL)
883*7f2fe78bSCy Schubert goto done;
884*7f2fe78bSCy Schubert } else
885*7f2fe78bSCy Schubert entry->key_data = NULL;
886*7f2fe78bSCy Schubert
887*7f2fe78bSCy Schubert for (i = 0; i < entry->n_key_data; i++)
888*7f2fe78bSCy Schubert ret = krb5_copy_key_data_contents(handle->context,
889*7f2fe78bSCy Schubert &kdb->key_data[i],
890*7f2fe78bSCy Schubert &entry->key_data[i]);
891*7f2fe78bSCy Schubert if (ret)
892*7f2fe78bSCy Schubert goto done;
893*7f2fe78bSCy Schubert }
894*7f2fe78bSCy Schubert
895*7f2fe78bSCy Schubert ret = KADM5_OK;
896*7f2fe78bSCy Schubert
897*7f2fe78bSCy Schubert done:
898*7f2fe78bSCy Schubert if (ret && entry->principal) {
899*7f2fe78bSCy Schubert krb5_free_principal(handle->context, entry->principal);
900*7f2fe78bSCy Schubert entry->principal = NULL;
901*7f2fe78bSCy Schubert }
902*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, &adb);
903*7f2fe78bSCy Schubert
904*7f2fe78bSCy Schubert return ret;
905*7f2fe78bSCy Schubert }
906*7f2fe78bSCy Schubert
907*7f2fe78bSCy Schubert /*
908*7f2fe78bSCy Schubert * Function: check_pw_reuse
909*7f2fe78bSCy Schubert *
910*7f2fe78bSCy Schubert * Purpose: Check if a key appears in a list of keys, in order to
911*7f2fe78bSCy Schubert * enforce password history.
912*7f2fe78bSCy Schubert *
913*7f2fe78bSCy Schubert * Arguments:
914*7f2fe78bSCy Schubert *
915*7f2fe78bSCy Schubert * context (r) the krb5 context
916*7f2fe78bSCy Schubert * hist_keyblock (r) the key that hist_key_data is
917*7f2fe78bSCy Schubert * encrypted in
918*7f2fe78bSCy Schubert * n_new_key_data (r) length of new_key_data
919*7f2fe78bSCy Schubert * new_key_data (r) keys to check against
920*7f2fe78bSCy Schubert * pw_hist_data, encrypted in hist_keyblock
921*7f2fe78bSCy Schubert * n_pw_hist_data (r) length of pw_hist_data
922*7f2fe78bSCy Schubert * pw_hist_data (r) passwords to check new_key_data against
923*7f2fe78bSCy Schubert *
924*7f2fe78bSCy Schubert * Effects:
925*7f2fe78bSCy Schubert * For each new_key in new_key_data:
926*7f2fe78bSCy Schubert * decrypt new_key with the master_keyblock
927*7f2fe78bSCy Schubert * for each password in pw_hist_data:
928*7f2fe78bSCy Schubert * for each hist_key in password:
929*7f2fe78bSCy Schubert * decrypt hist_key with hist_keyblock
930*7f2fe78bSCy Schubert * compare the new_key and hist_key
931*7f2fe78bSCy Schubert *
932*7f2fe78bSCy Schubert * Returns krb5 errors, KADM5_PASS_RESUSE if a key in
933*7f2fe78bSCy Schubert * new_key_data is the same as a key in pw_hist_data, or 0.
934*7f2fe78bSCy Schubert */
935*7f2fe78bSCy Schubert static kadm5_ret_t
check_pw_reuse(krb5_context context,krb5_keyblock * hist_keyblocks,int n_new_key_data,krb5_key_data * new_key_data,unsigned int n_pw_hist_data,osa_pw_hist_ent * pw_hist_data)936*7f2fe78bSCy Schubert check_pw_reuse(krb5_context context,
937*7f2fe78bSCy Schubert krb5_keyblock *hist_keyblocks,
938*7f2fe78bSCy Schubert int n_new_key_data, krb5_key_data *new_key_data,
939*7f2fe78bSCy Schubert unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
940*7f2fe78bSCy Schubert {
941*7f2fe78bSCy Schubert unsigned int x, y, z;
942*7f2fe78bSCy Schubert krb5_keyblock newkey, histkey, *kb;
943*7f2fe78bSCy Schubert krb5_key_data *key_data;
944*7f2fe78bSCy Schubert krb5_error_code ret;
945*7f2fe78bSCy Schubert
946*7f2fe78bSCy Schubert assert (n_new_key_data >= 0);
947*7f2fe78bSCy Schubert for (x = 0; x < (unsigned) n_new_key_data; x++) {
948*7f2fe78bSCy Schubert /* Check only entries with the most recent kvno. */
949*7f2fe78bSCy Schubert if (new_key_data[x].key_data_kvno != new_key_data[0].key_data_kvno)
950*7f2fe78bSCy Schubert break;
951*7f2fe78bSCy Schubert ret = krb5_dbe_decrypt_key_data(context, NULL, &(new_key_data[x]),
952*7f2fe78bSCy Schubert &newkey, NULL);
953*7f2fe78bSCy Schubert if (ret)
954*7f2fe78bSCy Schubert return(ret);
955*7f2fe78bSCy Schubert for (y = 0; y < n_pw_hist_data; y++) {
956*7f2fe78bSCy Schubert for (z = 0; z < (unsigned int) pw_hist_data[y].n_key_data; z++) {
957*7f2fe78bSCy Schubert for (kb = hist_keyblocks; kb->enctype != 0; kb++) {
958*7f2fe78bSCy Schubert key_data = &pw_hist_data[y].key_data[z];
959*7f2fe78bSCy Schubert ret = krb5_dbe_decrypt_key_data(context, kb, key_data,
960*7f2fe78bSCy Schubert &histkey, NULL);
961*7f2fe78bSCy Schubert if (ret)
962*7f2fe78bSCy Schubert continue;
963*7f2fe78bSCy Schubert if (newkey.length == histkey.length &&
964*7f2fe78bSCy Schubert newkey.enctype == histkey.enctype &&
965*7f2fe78bSCy Schubert memcmp(newkey.contents, histkey.contents,
966*7f2fe78bSCy Schubert histkey.length) == 0) {
967*7f2fe78bSCy Schubert krb5_free_keyblock_contents(context, &histkey);
968*7f2fe78bSCy Schubert krb5_free_keyblock_contents(context, &newkey);
969*7f2fe78bSCy Schubert return KADM5_PASS_REUSE;
970*7f2fe78bSCy Schubert }
971*7f2fe78bSCy Schubert krb5_free_keyblock_contents(context, &histkey);
972*7f2fe78bSCy Schubert }
973*7f2fe78bSCy Schubert }
974*7f2fe78bSCy Schubert }
975*7f2fe78bSCy Schubert krb5_free_keyblock_contents(context, &newkey);
976*7f2fe78bSCy Schubert }
977*7f2fe78bSCy Schubert
978*7f2fe78bSCy Schubert return(0);
979*7f2fe78bSCy Schubert }
980*7f2fe78bSCy Schubert
981*7f2fe78bSCy Schubert static void
free_history_entry(krb5_context context,osa_pw_hist_ent * hist)982*7f2fe78bSCy Schubert free_history_entry(krb5_context context, osa_pw_hist_ent *hist)
983*7f2fe78bSCy Schubert {
984*7f2fe78bSCy Schubert int i;
985*7f2fe78bSCy Schubert
986*7f2fe78bSCy Schubert for (i = 0; i < hist->n_key_data; i++)
987*7f2fe78bSCy Schubert krb5_free_key_data_contents(context, &hist->key_data[i]);
988*7f2fe78bSCy Schubert free(hist->key_data);
989*7f2fe78bSCy Schubert }
990*7f2fe78bSCy Schubert
991*7f2fe78bSCy Schubert /*
992*7f2fe78bSCy Schubert * Function: create_history_entry
993*7f2fe78bSCy Schubert *
994*7f2fe78bSCy Schubert * Purpose: Creates a password history entry from an array of
995*7f2fe78bSCy Schubert * key_data.
996*7f2fe78bSCy Schubert *
997*7f2fe78bSCy Schubert * Arguments:
998*7f2fe78bSCy Schubert *
999*7f2fe78bSCy Schubert * context (r) krb5_context to use
1000*7f2fe78bSCy Schubert * mkey (r) master keyblock to decrypt key data with
1001*7f2fe78bSCy Schubert * hist_key (r) history keyblock to encrypt key data with
1002*7f2fe78bSCy Schubert * n_key_data (r) number of elements in key_data
1003*7f2fe78bSCy Schubert * key_data (r) keys to add to the history entry
1004*7f2fe78bSCy Schubert * hist_out (w) history entry to fill in
1005*7f2fe78bSCy Schubert *
1006*7f2fe78bSCy Schubert * Effects:
1007*7f2fe78bSCy Schubert *
1008*7f2fe78bSCy Schubert * hist->key_data is allocated to store n_key_data key_datas. Each
1009*7f2fe78bSCy Schubert * element of key_data is decrypted with master_keyblock, re-encrypted
1010*7f2fe78bSCy Schubert * in hist_key, and added to hist->key_data. hist->n_key_data is
1011*7f2fe78bSCy Schubert * set to n_key_data.
1012*7f2fe78bSCy Schubert */
1013*7f2fe78bSCy Schubert static
create_history_entry(krb5_context context,krb5_keyblock * hist_key,int n_key_data,krb5_key_data * key_data,osa_pw_hist_ent * hist_out)1014*7f2fe78bSCy Schubert int create_history_entry(krb5_context context,
1015*7f2fe78bSCy Schubert krb5_keyblock *hist_key, int n_key_data,
1016*7f2fe78bSCy Schubert krb5_key_data *key_data, osa_pw_hist_ent *hist_out)
1017*7f2fe78bSCy Schubert {
1018*7f2fe78bSCy Schubert int i;
1019*7f2fe78bSCy Schubert krb5_error_code ret = 0;
1020*7f2fe78bSCy Schubert krb5_keyblock key;
1021*7f2fe78bSCy Schubert krb5_keysalt salt;
1022*7f2fe78bSCy Schubert krb5_ui_2 kvno;
1023*7f2fe78bSCy Schubert osa_pw_hist_ent hist;
1024*7f2fe78bSCy Schubert
1025*7f2fe78bSCy Schubert hist_out->key_data = NULL;
1026*7f2fe78bSCy Schubert hist_out->n_key_data = 0;
1027*7f2fe78bSCy Schubert
1028*7f2fe78bSCy Schubert if (n_key_data < 0)
1029*7f2fe78bSCy Schubert return EINVAL;
1030*7f2fe78bSCy Schubert
1031*7f2fe78bSCy Schubert memset(&key, 0, sizeof(key));
1032*7f2fe78bSCy Schubert memset(&hist, 0, sizeof(hist));
1033*7f2fe78bSCy Schubert
1034*7f2fe78bSCy Schubert if (n_key_data == 0)
1035*7f2fe78bSCy Schubert goto cleanup;
1036*7f2fe78bSCy Schubert
1037*7f2fe78bSCy Schubert hist.key_data = k5calloc(n_key_data, sizeof(krb5_key_data), &ret);
1038*7f2fe78bSCy Schubert if (hist.key_data == NULL)
1039*7f2fe78bSCy Schubert goto cleanup;
1040*7f2fe78bSCy Schubert
1041*7f2fe78bSCy Schubert /* We only want to store the most recent kvno, and key_data should already
1042*7f2fe78bSCy Schubert * be sorted in descending order by kvno. */
1043*7f2fe78bSCy Schubert kvno = key_data[0].key_data_kvno;
1044*7f2fe78bSCy Schubert
1045*7f2fe78bSCy Schubert for (i = 0; i < n_key_data; i++) {
1046*7f2fe78bSCy Schubert if (key_data[i].key_data_kvno < kvno)
1047*7f2fe78bSCy Schubert break;
1048*7f2fe78bSCy Schubert ret = krb5_dbe_decrypt_key_data(context, NULL,
1049*7f2fe78bSCy Schubert &key_data[i], &key,
1050*7f2fe78bSCy Schubert &salt);
1051*7f2fe78bSCy Schubert if (ret)
1052*7f2fe78bSCy Schubert goto cleanup;
1053*7f2fe78bSCy Schubert
1054*7f2fe78bSCy Schubert ret = krb5_dbe_encrypt_key_data(context, hist_key, &key, &salt,
1055*7f2fe78bSCy Schubert key_data[i].key_data_kvno,
1056*7f2fe78bSCy Schubert &hist.key_data[hist.n_key_data]);
1057*7f2fe78bSCy Schubert if (ret)
1058*7f2fe78bSCy Schubert goto cleanup;
1059*7f2fe78bSCy Schubert hist.n_key_data++;
1060*7f2fe78bSCy Schubert krb5_free_keyblock_contents(context, &key);
1061*7f2fe78bSCy Schubert /* krb5_free_keysalt(context, &salt); */
1062*7f2fe78bSCy Schubert }
1063*7f2fe78bSCy Schubert
1064*7f2fe78bSCy Schubert *hist_out = hist;
1065*7f2fe78bSCy Schubert hist.n_key_data = 0;
1066*7f2fe78bSCy Schubert hist.key_data = NULL;
1067*7f2fe78bSCy Schubert
1068*7f2fe78bSCy Schubert cleanup:
1069*7f2fe78bSCy Schubert krb5_free_keyblock_contents(context, &key);
1070*7f2fe78bSCy Schubert free_history_entry(context, &hist);
1071*7f2fe78bSCy Schubert return ret;
1072*7f2fe78bSCy Schubert }
1073*7f2fe78bSCy Schubert
1074*7f2fe78bSCy Schubert /*
1075*7f2fe78bSCy Schubert * Function: add_to_history
1076*7f2fe78bSCy Schubert *
1077*7f2fe78bSCy Schubert * Purpose: Adds a password to a principal's password history.
1078*7f2fe78bSCy Schubert *
1079*7f2fe78bSCy Schubert * Arguments:
1080*7f2fe78bSCy Schubert *
1081*7f2fe78bSCy Schubert * context (r) krb5_context to use
1082*7f2fe78bSCy Schubert * hist_kvno (r) kvno of current history key
1083*7f2fe78bSCy Schubert * adb (r/w) admin principal entry to add keys to
1084*7f2fe78bSCy Schubert * pol (r) adb's policy
1085*7f2fe78bSCy Schubert * pw (r) keys for the password to add to adb's key history
1086*7f2fe78bSCy Schubert *
1087*7f2fe78bSCy Schubert * Effects:
1088*7f2fe78bSCy Schubert *
1089*7f2fe78bSCy Schubert * add_to_history adds a single password to adb's password history.
1090*7f2fe78bSCy Schubert * pw contains n_key_data keys in its key_data, in storage should be
1091*7f2fe78bSCy Schubert * allocated but not freed by the caller (XXX blech!).
1092*7f2fe78bSCy Schubert *
1093*7f2fe78bSCy Schubert * This function maintains adb->old_keys as a circular queue. It
1094*7f2fe78bSCy Schubert * starts empty, and grows each time this function is called until it
1095*7f2fe78bSCy Schubert * is pol->pw_history_num items long. adb->old_key_len holds the
1096*7f2fe78bSCy Schubert * number of allocated entries in the array, and must therefore be [0,
1097*7f2fe78bSCy Schubert * pol->pw_history_num). adb->old_key_next is the index into the
1098*7f2fe78bSCy Schubert * array where the next element should be written, and must be [0,
1099*7f2fe78bSCy Schubert * adb->old_key_len).
1100*7f2fe78bSCy Schubert */
add_to_history(krb5_context context,krb5_kvno hist_kvno,osa_princ_ent_t adb,kadm5_policy_ent_t pol,osa_pw_hist_ent * pw)1101*7f2fe78bSCy Schubert static kadm5_ret_t add_to_history(krb5_context context,
1102*7f2fe78bSCy Schubert krb5_kvno hist_kvno,
1103*7f2fe78bSCy Schubert osa_princ_ent_t adb,
1104*7f2fe78bSCy Schubert kadm5_policy_ent_t pol,
1105*7f2fe78bSCy Schubert osa_pw_hist_ent *pw)
1106*7f2fe78bSCy Schubert {
1107*7f2fe78bSCy Schubert osa_pw_hist_ent *histp;
1108*7f2fe78bSCy Schubert uint32_t nhist;
1109*7f2fe78bSCy Schubert unsigned int i, knext, nkeys;
1110*7f2fe78bSCy Schubert
1111*7f2fe78bSCy Schubert nhist = pol->pw_history_num;
1112*7f2fe78bSCy Schubert /* A history of 1 means just check the current password */
1113*7f2fe78bSCy Schubert if (nhist <= 1)
1114*7f2fe78bSCy Schubert return 0;
1115*7f2fe78bSCy Schubert
1116*7f2fe78bSCy Schubert if (adb->admin_history_kvno != hist_kvno) {
1117*7f2fe78bSCy Schubert /* The history key has changed since the last password change, so we
1118*7f2fe78bSCy Schubert * have to reset the password history. */
1119*7f2fe78bSCy Schubert free(adb->old_keys);
1120*7f2fe78bSCy Schubert adb->old_keys = NULL;
1121*7f2fe78bSCy Schubert adb->old_key_len = 0;
1122*7f2fe78bSCy Schubert adb->old_key_next = 0;
1123*7f2fe78bSCy Schubert adb->admin_history_kvno = hist_kvno;
1124*7f2fe78bSCy Schubert }
1125*7f2fe78bSCy Schubert
1126*7f2fe78bSCy Schubert nkeys = adb->old_key_len;
1127*7f2fe78bSCy Schubert knext = adb->old_key_next;
1128*7f2fe78bSCy Schubert /* resize the adb->old_keys array if necessary */
1129*7f2fe78bSCy Schubert if (nkeys + 1 < nhist) {
1130*7f2fe78bSCy Schubert if (adb->old_keys == NULL) {
1131*7f2fe78bSCy Schubert adb->old_keys = (osa_pw_hist_ent *)
1132*7f2fe78bSCy Schubert malloc((nkeys + 1) * sizeof (osa_pw_hist_ent));
1133*7f2fe78bSCy Schubert } else {
1134*7f2fe78bSCy Schubert adb->old_keys = (osa_pw_hist_ent *)
1135*7f2fe78bSCy Schubert realloc(adb->old_keys,
1136*7f2fe78bSCy Schubert (nkeys + 1) * sizeof (osa_pw_hist_ent));
1137*7f2fe78bSCy Schubert }
1138*7f2fe78bSCy Schubert if (adb->old_keys == NULL)
1139*7f2fe78bSCy Schubert return(ENOMEM);
1140*7f2fe78bSCy Schubert
1141*7f2fe78bSCy Schubert memset(&adb->old_keys[nkeys], 0, sizeof(osa_pw_hist_ent));
1142*7f2fe78bSCy Schubert nkeys = ++adb->old_key_len;
1143*7f2fe78bSCy Schubert /*
1144*7f2fe78bSCy Schubert * To avoid losing old keys, shift forward each entry after
1145*7f2fe78bSCy Schubert * knext.
1146*7f2fe78bSCy Schubert */
1147*7f2fe78bSCy Schubert for (i = nkeys - 1; i > knext; i--) {
1148*7f2fe78bSCy Schubert adb->old_keys[i] = adb->old_keys[i - 1];
1149*7f2fe78bSCy Schubert }
1150*7f2fe78bSCy Schubert memset(&adb->old_keys[knext], 0, sizeof(osa_pw_hist_ent));
1151*7f2fe78bSCy Schubert } else if (nkeys + 1 > nhist) {
1152*7f2fe78bSCy Schubert /*
1153*7f2fe78bSCy Schubert * The policy must have changed! Shrink the array.
1154*7f2fe78bSCy Schubert * Can't simply realloc() down, since it might be wrapped.
1155*7f2fe78bSCy Schubert * To understand the arithmetic below, note that we are
1156*7f2fe78bSCy Schubert * copying into new positions 0 .. N-1 from old positions
1157*7f2fe78bSCy Schubert * old_key_next-N .. old_key_next-1, modulo old_key_len,
1158*7f2fe78bSCy Schubert * where N = pw_history_num - 1 is the length of the
1159*7f2fe78bSCy Schubert * shortened list. Matt Crawford, FNAL
1160*7f2fe78bSCy Schubert */
1161*7f2fe78bSCy Schubert /*
1162*7f2fe78bSCy Schubert * M = adb->old_key_len, N = pol->pw_history_num - 1
1163*7f2fe78bSCy Schubert *
1164*7f2fe78bSCy Schubert * tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M]
1165*7f2fe78bSCy Schubert */
1166*7f2fe78bSCy Schubert int j;
1167*7f2fe78bSCy Schubert osa_pw_hist_t tmp;
1168*7f2fe78bSCy Schubert
1169*7f2fe78bSCy Schubert tmp = (osa_pw_hist_ent *)
1170*7f2fe78bSCy Schubert malloc((nhist - 1) * sizeof (osa_pw_hist_ent));
1171*7f2fe78bSCy Schubert if (tmp == NULL)
1172*7f2fe78bSCy Schubert return ENOMEM;
1173*7f2fe78bSCy Schubert for (i = 0; i < nhist - 1; i++) {
1174*7f2fe78bSCy Schubert /*
1175*7f2fe78bSCy Schubert * Add nkeys once before taking remainder to avoid
1176*7f2fe78bSCy Schubert * negative values.
1177*7f2fe78bSCy Schubert */
1178*7f2fe78bSCy Schubert j = (i + nkeys + knext - (nhist - 1)) % nkeys;
1179*7f2fe78bSCy Schubert tmp[i] = adb->old_keys[j];
1180*7f2fe78bSCy Schubert }
1181*7f2fe78bSCy Schubert /* Now free the ones we don't keep (the oldest ones) */
1182*7f2fe78bSCy Schubert for (i = 0; i < nkeys - (nhist - 1); i++) {
1183*7f2fe78bSCy Schubert j = (i + nkeys + knext) % nkeys;
1184*7f2fe78bSCy Schubert histp = &adb->old_keys[j];
1185*7f2fe78bSCy Schubert for (j = 0; j < histp->n_key_data; j++) {
1186*7f2fe78bSCy Schubert krb5_free_key_data_contents(context, &histp->key_data[j]);
1187*7f2fe78bSCy Schubert }
1188*7f2fe78bSCy Schubert free(histp->key_data);
1189*7f2fe78bSCy Schubert }
1190*7f2fe78bSCy Schubert free(adb->old_keys);
1191*7f2fe78bSCy Schubert adb->old_keys = tmp;
1192*7f2fe78bSCy Schubert nkeys = adb->old_key_len = nhist - 1;
1193*7f2fe78bSCy Schubert knext = adb->old_key_next = 0;
1194*7f2fe78bSCy Schubert }
1195*7f2fe78bSCy Schubert
1196*7f2fe78bSCy Schubert /*
1197*7f2fe78bSCy Schubert * If nhist decreased since the last password change, and nkeys+1
1198*7f2fe78bSCy Schubert * is less than the previous nhist, it is possible for knext to
1199*7f2fe78bSCy Schubert * index into unallocated space. This condition would not be
1200*7f2fe78bSCy Schubert * caught by the resizing code above.
1201*7f2fe78bSCy Schubert */
1202*7f2fe78bSCy Schubert if (knext + 1 > nkeys)
1203*7f2fe78bSCy Schubert knext = adb->old_key_next = 0;
1204*7f2fe78bSCy Schubert /* free the old pw history entry if it contains data */
1205*7f2fe78bSCy Schubert histp = &adb->old_keys[knext];
1206*7f2fe78bSCy Schubert for (i = 0; i < (unsigned int) histp->n_key_data; i++)
1207*7f2fe78bSCy Schubert krb5_free_key_data_contents(context, &histp->key_data[i]);
1208*7f2fe78bSCy Schubert free(histp->key_data);
1209*7f2fe78bSCy Schubert
1210*7f2fe78bSCy Schubert /* store the new entry */
1211*7f2fe78bSCy Schubert adb->old_keys[knext] = *pw;
1212*7f2fe78bSCy Schubert
1213*7f2fe78bSCy Schubert /* update the next pointer */
1214*7f2fe78bSCy Schubert if (++adb->old_key_next == nhist - 1)
1215*7f2fe78bSCy Schubert adb->old_key_next = 0;
1216*7f2fe78bSCy Schubert
1217*7f2fe78bSCy Schubert return(0);
1218*7f2fe78bSCy Schubert }
1219*7f2fe78bSCy Schubert
1220*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_chpass_principal(void * server_handle,krb5_principal principal,char * password)1221*7f2fe78bSCy Schubert kadm5_chpass_principal(void *server_handle,
1222*7f2fe78bSCy Schubert krb5_principal principal, char *password)
1223*7f2fe78bSCy Schubert {
1224*7f2fe78bSCy Schubert return
1225*7f2fe78bSCy Schubert kadm5_chpass_principal_3(server_handle, principal, FALSE,
1226*7f2fe78bSCy Schubert 0, NULL, password);
1227*7f2fe78bSCy Schubert }
1228*7f2fe78bSCy Schubert
1229*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_chpass_principal_3(void * server_handle,krb5_principal principal,krb5_boolean keepold,int n_ks_tuple,krb5_key_salt_tuple * ks_tuple,char * password)1230*7f2fe78bSCy Schubert kadm5_chpass_principal_3(void *server_handle,
1231*7f2fe78bSCy Schubert krb5_principal principal, krb5_boolean keepold,
1232*7f2fe78bSCy Schubert int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1233*7f2fe78bSCy Schubert char *password)
1234*7f2fe78bSCy Schubert {
1235*7f2fe78bSCy Schubert krb5_timestamp now;
1236*7f2fe78bSCy Schubert kadm5_policy_ent_rec pol;
1237*7f2fe78bSCy Schubert osa_princ_ent_rec adb;
1238*7f2fe78bSCy Schubert krb5_db_entry *kdb;
1239*7f2fe78bSCy Schubert int ret, ret2, hist_added;
1240*7f2fe78bSCy Schubert krb5_boolean have_pol = FALSE;
1241*7f2fe78bSCy Schubert kadm5_server_handle_t handle = server_handle;
1242*7f2fe78bSCy Schubert osa_pw_hist_ent hist;
1243*7f2fe78bSCy Schubert krb5_keyblock *act_mkey, *hist_keyblocks = NULL;
1244*7f2fe78bSCy Schubert krb5_kvno act_kvno, hist_kvno;
1245*7f2fe78bSCy Schubert int new_n_ks_tuple = 0;
1246*7f2fe78bSCy Schubert krb5_key_salt_tuple *new_ks_tuple = NULL;
1247*7f2fe78bSCy Schubert
1248*7f2fe78bSCy Schubert CHECK_HANDLE(server_handle);
1249*7f2fe78bSCy Schubert
1250*7f2fe78bSCy Schubert krb5_clear_error_message(handle->context);
1251*7f2fe78bSCy Schubert
1252*7f2fe78bSCy Schubert hist_added = 0;
1253*7f2fe78bSCy Schubert memset(&hist, 0, sizeof(hist));
1254*7f2fe78bSCy Schubert
1255*7f2fe78bSCy Schubert if (principal == NULL || password == NULL)
1256*7f2fe78bSCy Schubert return EINVAL;
1257*7f2fe78bSCy Schubert if ((krb5_principal_compare(handle->context,
1258*7f2fe78bSCy Schubert principal, hist_princ)) == TRUE)
1259*7f2fe78bSCy Schubert return KADM5_PROTECT_PRINCIPAL;
1260*7f2fe78bSCy Schubert
1261*7f2fe78bSCy Schubert if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1262*7f2fe78bSCy Schubert return(ret);
1263*7f2fe78bSCy Schubert
1264*7f2fe78bSCy Schubert /* We will always be changing the key data, attributes, auth failure count,
1265*7f2fe78bSCy Schubert * and password expiration time. */
1266*7f2fe78bSCy Schubert kdb->mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES | KADM5_FAIL_AUTH_COUNT |
1267*7f2fe78bSCy Schubert KADM5_PW_EXPIRATION;
1268*7f2fe78bSCy Schubert
1269*7f2fe78bSCy Schubert ret = apply_keysalt_policy(handle, adb.policy, n_ks_tuple, ks_tuple,
1270*7f2fe78bSCy Schubert &new_n_ks_tuple, &new_ks_tuple);
1271*7f2fe78bSCy Schubert if (ret)
1272*7f2fe78bSCy Schubert goto done;
1273*7f2fe78bSCy Schubert
1274*7f2fe78bSCy Schubert if ((adb.aux_attributes & KADM5_POLICY)) {
1275*7f2fe78bSCy Schubert ret = get_policy(handle, adb.policy, &pol, &have_pol);
1276*7f2fe78bSCy Schubert if (ret)
1277*7f2fe78bSCy Schubert goto done;
1278*7f2fe78bSCy Schubert }
1279*7f2fe78bSCy Schubert if (have_pol) {
1280*7f2fe78bSCy Schubert /* Create a password history entry before we change kdb's key_data. */
1281*7f2fe78bSCy Schubert ret = kdb_get_hist_key(handle, &hist_keyblocks, &hist_kvno);
1282*7f2fe78bSCy Schubert if (ret)
1283*7f2fe78bSCy Schubert goto done;
1284*7f2fe78bSCy Schubert ret = create_history_entry(handle->context, &hist_keyblocks[0],
1285*7f2fe78bSCy Schubert kdb->n_key_data, kdb->key_data, &hist);
1286*7f2fe78bSCy Schubert if (ret)
1287*7f2fe78bSCy Schubert goto done;
1288*7f2fe78bSCy Schubert }
1289*7f2fe78bSCy Schubert
1290*7f2fe78bSCy Schubert if ((ret = passwd_check(handle, password, have_pol ? &pol : NULL,
1291*7f2fe78bSCy Schubert principal)))
1292*7f2fe78bSCy Schubert goto done;
1293*7f2fe78bSCy Schubert
1294*7f2fe78bSCy Schubert ret = kdb_get_active_mkey(handle, &act_kvno, &act_mkey);
1295*7f2fe78bSCy Schubert if (ret)
1296*7f2fe78bSCy Schubert goto done;
1297*7f2fe78bSCy Schubert
1298*7f2fe78bSCy Schubert ret = krb5_dbe_cpw(handle->context, act_mkey, new_ks_tuple, new_n_ks_tuple,
1299*7f2fe78bSCy Schubert password, 0 /* increment kvno */,
1300*7f2fe78bSCy Schubert keepold, kdb);
1301*7f2fe78bSCy Schubert if (ret)
1302*7f2fe78bSCy Schubert goto done;
1303*7f2fe78bSCy Schubert
1304*7f2fe78bSCy Schubert ret = krb5_dbe_update_mkvno(handle->context, kdb, act_kvno);
1305*7f2fe78bSCy Schubert if (ret)
1306*7f2fe78bSCy Schubert goto done;
1307*7f2fe78bSCy Schubert
1308*7f2fe78bSCy Schubert kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1309*7f2fe78bSCy Schubert
1310*7f2fe78bSCy Schubert ret = krb5_timeofday(handle->context, &now);
1311*7f2fe78bSCy Schubert if (ret)
1312*7f2fe78bSCy Schubert goto done;
1313*7f2fe78bSCy Schubert
1314*7f2fe78bSCy Schubert kdb->pw_expiration = 0;
1315*7f2fe78bSCy Schubert if ((adb.aux_attributes & KADM5_POLICY)) {
1316*7f2fe78bSCy Schubert /* the policy was loaded before */
1317*7f2fe78bSCy Schubert
1318*7f2fe78bSCy Schubert ret = check_pw_reuse(handle->context, hist_keyblocks,
1319*7f2fe78bSCy Schubert kdb->n_key_data, kdb->key_data,
1320*7f2fe78bSCy Schubert 1, &hist);
1321*7f2fe78bSCy Schubert if (ret)
1322*7f2fe78bSCy Schubert goto done;
1323*7f2fe78bSCy Schubert
1324*7f2fe78bSCy Schubert if (pol.pw_history_num > 1) {
1325*7f2fe78bSCy Schubert /* If hist_kvno has changed since the last password change, we
1326*7f2fe78bSCy Schubert * can't check the history. */
1327*7f2fe78bSCy Schubert if (adb.admin_history_kvno == hist_kvno) {
1328*7f2fe78bSCy Schubert ret = check_pw_reuse(handle->context, hist_keyblocks,
1329*7f2fe78bSCy Schubert kdb->n_key_data, kdb->key_data,
1330*7f2fe78bSCy Schubert adb.old_key_len, adb.old_keys);
1331*7f2fe78bSCy Schubert if (ret)
1332*7f2fe78bSCy Schubert goto done;
1333*7f2fe78bSCy Schubert }
1334*7f2fe78bSCy Schubert
1335*7f2fe78bSCy Schubert /* Don't save empty history. */
1336*7f2fe78bSCy Schubert if (hist.n_key_data > 0) {
1337*7f2fe78bSCy Schubert ret = add_to_history(handle->context, hist_kvno, &adb, &pol,
1338*7f2fe78bSCy Schubert &hist);
1339*7f2fe78bSCy Schubert if (ret)
1340*7f2fe78bSCy Schubert goto done;
1341*7f2fe78bSCy Schubert hist_added = 1;
1342*7f2fe78bSCy Schubert }
1343*7f2fe78bSCy Schubert }
1344*7f2fe78bSCy Schubert
1345*7f2fe78bSCy Schubert if (pol.pw_max_life)
1346*7f2fe78bSCy Schubert kdb->pw_expiration = ts_incr(now, pol.pw_max_life);
1347*7f2fe78bSCy Schubert }
1348*7f2fe78bSCy Schubert
1349*7f2fe78bSCy Schubert ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now);
1350*7f2fe78bSCy Schubert if (ret)
1351*7f2fe78bSCy Schubert goto done;
1352*7f2fe78bSCy Schubert
1353*7f2fe78bSCy Schubert /* unlock principal on this KDC */
1354*7f2fe78bSCy Schubert kdb->fail_auth_count = 0;
1355*7f2fe78bSCy Schubert
1356*7f2fe78bSCy Schubert if (hist_added)
1357*7f2fe78bSCy Schubert kdb->mask |= KADM5_KEY_HIST;
1358*7f2fe78bSCy Schubert
1359*7f2fe78bSCy Schubert ret = k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
1360*7f2fe78bSCy Schubert KADM5_HOOK_STAGE_PRECOMMIT, principal, keepold,
1361*7f2fe78bSCy Schubert new_n_ks_tuple, new_ks_tuple, password);
1362*7f2fe78bSCy Schubert if (ret)
1363*7f2fe78bSCy Schubert goto done;
1364*7f2fe78bSCy Schubert
1365*7f2fe78bSCy Schubert if ((ret = kdb_put_entry(handle, kdb, &adb)))
1366*7f2fe78bSCy Schubert goto done;
1367*7f2fe78bSCy Schubert
1368*7f2fe78bSCy Schubert (void) k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
1369*7f2fe78bSCy Schubert KADM5_HOOK_STAGE_POSTCOMMIT, principal,
1370*7f2fe78bSCy Schubert keepold, new_n_ks_tuple, new_ks_tuple, password);
1371*7f2fe78bSCy Schubert ret = KADM5_OK;
1372*7f2fe78bSCy Schubert done:
1373*7f2fe78bSCy Schubert free(new_ks_tuple);
1374*7f2fe78bSCy Schubert if (!hist_added && hist.key_data)
1375*7f2fe78bSCy Schubert free_history_entry(handle->context, &hist);
1376*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, &adb);
1377*7f2fe78bSCy Schubert kdb_free_keyblocks(handle, hist_keyblocks);
1378*7f2fe78bSCy Schubert
1379*7f2fe78bSCy Schubert if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol))
1380*7f2fe78bSCy Schubert && !ret)
1381*7f2fe78bSCy Schubert ret = ret2;
1382*7f2fe78bSCy Schubert
1383*7f2fe78bSCy Schubert return ret;
1384*7f2fe78bSCy Schubert }
1385*7f2fe78bSCy Schubert
1386*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_randkey_principal(void * server_handle,krb5_principal principal,krb5_keyblock ** keyblocks,int * n_keys)1387*7f2fe78bSCy Schubert kadm5_randkey_principal(void *server_handle,
1388*7f2fe78bSCy Schubert krb5_principal principal,
1389*7f2fe78bSCy Schubert krb5_keyblock **keyblocks,
1390*7f2fe78bSCy Schubert int *n_keys)
1391*7f2fe78bSCy Schubert {
1392*7f2fe78bSCy Schubert return
1393*7f2fe78bSCy Schubert kadm5_randkey_principal_3(server_handle, principal,
1394*7f2fe78bSCy Schubert FALSE, 0, NULL,
1395*7f2fe78bSCy Schubert keyblocks, n_keys);
1396*7f2fe78bSCy Schubert }
1397*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_randkey_principal_3(void * server_handle,krb5_principal principal,krb5_boolean keepold,int n_ks_tuple,krb5_key_salt_tuple * ks_tuple,krb5_keyblock ** keyblocks,int * n_keys)1398*7f2fe78bSCy Schubert kadm5_randkey_principal_3(void *server_handle,
1399*7f2fe78bSCy Schubert krb5_principal principal,
1400*7f2fe78bSCy Schubert krb5_boolean keepold,
1401*7f2fe78bSCy Schubert int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1402*7f2fe78bSCy Schubert krb5_keyblock **keyblocks,
1403*7f2fe78bSCy Schubert int *n_keys)
1404*7f2fe78bSCy Schubert {
1405*7f2fe78bSCy Schubert krb5_db_entry *kdb;
1406*7f2fe78bSCy Schubert osa_princ_ent_rec adb;
1407*7f2fe78bSCy Schubert krb5_timestamp now;
1408*7f2fe78bSCy Schubert kadm5_policy_ent_rec pol;
1409*7f2fe78bSCy Schubert int ret, n_new_keys;
1410*7f2fe78bSCy Schubert krb5_boolean have_pol = FALSE;
1411*7f2fe78bSCy Schubert kadm5_server_handle_t handle = server_handle;
1412*7f2fe78bSCy Schubert krb5_keyblock *act_mkey;
1413*7f2fe78bSCy Schubert krb5_kvno act_kvno;
1414*7f2fe78bSCy Schubert int new_n_ks_tuple = 0;
1415*7f2fe78bSCy Schubert krb5_key_salt_tuple *new_ks_tuple = NULL;
1416*7f2fe78bSCy Schubert
1417*7f2fe78bSCy Schubert if (keyblocks)
1418*7f2fe78bSCy Schubert *keyblocks = NULL;
1419*7f2fe78bSCy Schubert
1420*7f2fe78bSCy Schubert CHECK_HANDLE(server_handle);
1421*7f2fe78bSCy Schubert
1422*7f2fe78bSCy Schubert krb5_clear_error_message(handle->context);
1423*7f2fe78bSCy Schubert
1424*7f2fe78bSCy Schubert if (principal == NULL)
1425*7f2fe78bSCy Schubert return EINVAL;
1426*7f2fe78bSCy Schubert
1427*7f2fe78bSCy Schubert if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1428*7f2fe78bSCy Schubert return(ret);
1429*7f2fe78bSCy Schubert
1430*7f2fe78bSCy Schubert /* We will always be changing the key data, attributes, auth failure count,
1431*7f2fe78bSCy Schubert * and password expiration time. */
1432*7f2fe78bSCy Schubert kdb->mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES | KADM5_FAIL_AUTH_COUNT |
1433*7f2fe78bSCy Schubert KADM5_PW_EXPIRATION;
1434*7f2fe78bSCy Schubert
1435*7f2fe78bSCy Schubert ret = apply_keysalt_policy(handle, adb.policy, n_ks_tuple, ks_tuple,
1436*7f2fe78bSCy Schubert &new_n_ks_tuple, &new_ks_tuple);
1437*7f2fe78bSCy Schubert if (ret)
1438*7f2fe78bSCy Schubert goto done;
1439*7f2fe78bSCy Schubert
1440*7f2fe78bSCy Schubert if (krb5_principal_compare(handle->context, principal, hist_princ)) {
1441*7f2fe78bSCy Schubert /* If changing the history entry, the new entry must have exactly one
1442*7f2fe78bSCy Schubert * key. */
1443*7f2fe78bSCy Schubert if (keepold) {
1444*7f2fe78bSCy Schubert ret = KADM5_PROTECT_PRINCIPAL;
1445*7f2fe78bSCy Schubert goto done;
1446*7f2fe78bSCy Schubert }
1447*7f2fe78bSCy Schubert new_n_ks_tuple = 1;
1448*7f2fe78bSCy Schubert }
1449*7f2fe78bSCy Schubert
1450*7f2fe78bSCy Schubert ret = kdb_get_active_mkey(handle, &act_kvno, &act_mkey);
1451*7f2fe78bSCy Schubert if (ret)
1452*7f2fe78bSCy Schubert goto done;
1453*7f2fe78bSCy Schubert
1454*7f2fe78bSCy Schubert ret = krb5_dbe_crk(handle->context, act_mkey, new_ks_tuple, new_n_ks_tuple,
1455*7f2fe78bSCy Schubert keepold, kdb);
1456*7f2fe78bSCy Schubert if (ret)
1457*7f2fe78bSCy Schubert goto done;
1458*7f2fe78bSCy Schubert
1459*7f2fe78bSCy Schubert ret = krb5_dbe_update_mkvno(handle->context, kdb, act_kvno);
1460*7f2fe78bSCy Schubert if (ret)
1461*7f2fe78bSCy Schubert goto done;
1462*7f2fe78bSCy Schubert
1463*7f2fe78bSCy Schubert kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1464*7f2fe78bSCy Schubert
1465*7f2fe78bSCy Schubert ret = krb5_timeofday(handle->context, &now);
1466*7f2fe78bSCy Schubert if (ret)
1467*7f2fe78bSCy Schubert goto done;
1468*7f2fe78bSCy Schubert
1469*7f2fe78bSCy Schubert if ((adb.aux_attributes & KADM5_POLICY)) {
1470*7f2fe78bSCy Schubert ret = get_policy(handle, adb.policy, &pol, &have_pol);
1471*7f2fe78bSCy Schubert if (ret)
1472*7f2fe78bSCy Schubert goto done;
1473*7f2fe78bSCy Schubert }
1474*7f2fe78bSCy Schubert
1475*7f2fe78bSCy Schubert kdb->pw_expiration = 0;
1476*7f2fe78bSCy Schubert if (have_pol && pol.pw_max_life)
1477*7f2fe78bSCy Schubert kdb->pw_expiration = ts_incr(now, pol.pw_max_life);
1478*7f2fe78bSCy Schubert
1479*7f2fe78bSCy Schubert ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now);
1480*7f2fe78bSCy Schubert if (ret)
1481*7f2fe78bSCy Schubert goto done;
1482*7f2fe78bSCy Schubert
1483*7f2fe78bSCy Schubert /* unlock principal on this KDC */
1484*7f2fe78bSCy Schubert kdb->fail_auth_count = 0;
1485*7f2fe78bSCy Schubert
1486*7f2fe78bSCy Schubert if (keyblocks) {
1487*7f2fe78bSCy Schubert /* Return only the new keys added by krb5_dbe_crk. */
1488*7f2fe78bSCy Schubert n_new_keys = count_new_keys(kdb->n_key_data, kdb->key_data);
1489*7f2fe78bSCy Schubert ret = decrypt_key_data(handle->context, n_new_keys, kdb->key_data,
1490*7f2fe78bSCy Schubert keyblocks, n_keys);
1491*7f2fe78bSCy Schubert if (ret)
1492*7f2fe78bSCy Schubert goto done;
1493*7f2fe78bSCy Schubert }
1494*7f2fe78bSCy Schubert
1495*7f2fe78bSCy Schubert ret = k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
1496*7f2fe78bSCy Schubert KADM5_HOOK_STAGE_PRECOMMIT, principal, keepold,
1497*7f2fe78bSCy Schubert new_n_ks_tuple, new_ks_tuple, NULL);
1498*7f2fe78bSCy Schubert if (ret)
1499*7f2fe78bSCy Schubert goto done;
1500*7f2fe78bSCy Schubert if ((ret = kdb_put_entry(handle, kdb, &adb)))
1501*7f2fe78bSCy Schubert goto done;
1502*7f2fe78bSCy Schubert
1503*7f2fe78bSCy Schubert (void) k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
1504*7f2fe78bSCy Schubert KADM5_HOOK_STAGE_POSTCOMMIT, principal,
1505*7f2fe78bSCy Schubert keepold, new_n_ks_tuple, new_ks_tuple, NULL);
1506*7f2fe78bSCy Schubert ret = KADM5_OK;
1507*7f2fe78bSCy Schubert done:
1508*7f2fe78bSCy Schubert free(new_ks_tuple);
1509*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, &adb);
1510*7f2fe78bSCy Schubert if (have_pol)
1511*7f2fe78bSCy Schubert kadm5_free_policy_ent(handle->lhandle, &pol);
1512*7f2fe78bSCy Schubert
1513*7f2fe78bSCy Schubert return ret;
1514*7f2fe78bSCy Schubert }
1515*7f2fe78bSCy Schubert
1516*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_setkey_principal(void * server_handle,krb5_principal principal,krb5_keyblock * keyblocks,int n_keys)1517*7f2fe78bSCy Schubert kadm5_setkey_principal(void *server_handle,
1518*7f2fe78bSCy Schubert krb5_principal principal,
1519*7f2fe78bSCy Schubert krb5_keyblock *keyblocks,
1520*7f2fe78bSCy Schubert int n_keys)
1521*7f2fe78bSCy Schubert {
1522*7f2fe78bSCy Schubert return
1523*7f2fe78bSCy Schubert kadm5_setkey_principal_3(server_handle, principal,
1524*7f2fe78bSCy Schubert FALSE, 0, NULL,
1525*7f2fe78bSCy Schubert keyblocks, n_keys);
1526*7f2fe78bSCy Schubert }
1527*7f2fe78bSCy Schubert
1528*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_setkey_principal_3(void * server_handle,krb5_principal principal,krb5_boolean keepold,int n_ks_tuple,krb5_key_salt_tuple * ks_tuple,krb5_keyblock * keyblocks,int n_keys)1529*7f2fe78bSCy Schubert kadm5_setkey_principal_3(void *server_handle,
1530*7f2fe78bSCy Schubert krb5_principal principal,
1531*7f2fe78bSCy Schubert krb5_boolean keepold,
1532*7f2fe78bSCy Schubert int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1533*7f2fe78bSCy Schubert krb5_keyblock *keyblocks,
1534*7f2fe78bSCy Schubert int n_keys)
1535*7f2fe78bSCy Schubert {
1536*7f2fe78bSCy Schubert kadm5_key_data *key_data;
1537*7f2fe78bSCy Schubert kadm5_ret_t ret;
1538*7f2fe78bSCy Schubert int i;
1539*7f2fe78bSCy Schubert
1540*7f2fe78bSCy Schubert if (keyblocks == NULL)
1541*7f2fe78bSCy Schubert return EINVAL;
1542*7f2fe78bSCy Schubert
1543*7f2fe78bSCy Schubert if (n_ks_tuple) {
1544*7f2fe78bSCy Schubert if (n_ks_tuple != n_keys)
1545*7f2fe78bSCy Schubert return KADM5_SETKEY3_ETYPE_MISMATCH;
1546*7f2fe78bSCy Schubert for (i = 0; i < n_ks_tuple; i++) {
1547*7f2fe78bSCy Schubert if (ks_tuple[i].ks_enctype != keyblocks[i].enctype)
1548*7f2fe78bSCy Schubert return KADM5_SETKEY3_ETYPE_MISMATCH;
1549*7f2fe78bSCy Schubert }
1550*7f2fe78bSCy Schubert }
1551*7f2fe78bSCy Schubert
1552*7f2fe78bSCy Schubert key_data = calloc(n_keys, sizeof(kadm5_key_data));
1553*7f2fe78bSCy Schubert if (key_data == NULL)
1554*7f2fe78bSCy Schubert return ENOMEM;
1555*7f2fe78bSCy Schubert
1556*7f2fe78bSCy Schubert for (i = 0; i < n_keys; i++) {
1557*7f2fe78bSCy Schubert key_data[i].key = keyblocks[i];
1558*7f2fe78bSCy Schubert key_data[i].salt.type =
1559*7f2fe78bSCy Schubert n_ks_tuple ? ks_tuple[i].ks_salttype : KRB5_KDB_SALTTYPE_NORMAL;
1560*7f2fe78bSCy Schubert }
1561*7f2fe78bSCy Schubert
1562*7f2fe78bSCy Schubert ret = kadm5_setkey_principal_4(server_handle, principal, keepold,
1563*7f2fe78bSCy Schubert key_data, n_keys);
1564*7f2fe78bSCy Schubert free(key_data);
1565*7f2fe78bSCy Schubert return ret;
1566*7f2fe78bSCy Schubert }
1567*7f2fe78bSCy Schubert
1568*7f2fe78bSCy Schubert /* Create a key/salt list from a key_data array. */
1569*7f2fe78bSCy Schubert static kadm5_ret_t
make_ks_from_key_data(krb5_context context,kadm5_key_data * key_data,int n_key_data,krb5_key_salt_tuple ** out)1570*7f2fe78bSCy Schubert make_ks_from_key_data(krb5_context context, kadm5_key_data *key_data,
1571*7f2fe78bSCy Schubert int n_key_data, krb5_key_salt_tuple **out)
1572*7f2fe78bSCy Schubert {
1573*7f2fe78bSCy Schubert int i;
1574*7f2fe78bSCy Schubert krb5_key_salt_tuple *ks;
1575*7f2fe78bSCy Schubert
1576*7f2fe78bSCy Schubert *out = NULL;
1577*7f2fe78bSCy Schubert
1578*7f2fe78bSCy Schubert ks = calloc(n_key_data, sizeof(*ks));
1579*7f2fe78bSCy Schubert if (ks == NULL)
1580*7f2fe78bSCy Schubert return ENOMEM;
1581*7f2fe78bSCy Schubert
1582*7f2fe78bSCy Schubert for (i = 0; i < n_key_data; i++) {
1583*7f2fe78bSCy Schubert ks[i].ks_enctype = key_data[i].key.enctype;
1584*7f2fe78bSCy Schubert ks[i].ks_salttype = key_data[i].salt.type;
1585*7f2fe78bSCy Schubert }
1586*7f2fe78bSCy Schubert *out = ks;
1587*7f2fe78bSCy Schubert return 0;
1588*7f2fe78bSCy Schubert }
1589*7f2fe78bSCy Schubert
1590*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_setkey_principal_4(void * server_handle,krb5_principal principal,krb5_boolean keepold,kadm5_key_data * key_data,int n_key_data)1591*7f2fe78bSCy Schubert kadm5_setkey_principal_4(void *server_handle, krb5_principal principal,
1592*7f2fe78bSCy Schubert krb5_boolean keepold, kadm5_key_data *key_data,
1593*7f2fe78bSCy Schubert int n_key_data)
1594*7f2fe78bSCy Schubert {
1595*7f2fe78bSCy Schubert krb5_db_entry *kdb;
1596*7f2fe78bSCy Schubert osa_princ_ent_rec adb;
1597*7f2fe78bSCy Schubert krb5_timestamp now;
1598*7f2fe78bSCy Schubert kadm5_policy_ent_rec pol;
1599*7f2fe78bSCy Schubert krb5_key_data *new_key_data = NULL;
1600*7f2fe78bSCy Schubert int i, j, ret, n_new_key_data = 0;
1601*7f2fe78bSCy Schubert krb5_kvno kvno;
1602*7f2fe78bSCy Schubert krb5_boolean similar, have_pol = FALSE;
1603*7f2fe78bSCy Schubert kadm5_server_handle_t handle = server_handle;
1604*7f2fe78bSCy Schubert krb5_keyblock *act_mkey;
1605*7f2fe78bSCy Schubert krb5_key_salt_tuple *ks_from_keys = NULL;
1606*7f2fe78bSCy Schubert
1607*7f2fe78bSCy Schubert CHECK_HANDLE(server_handle);
1608*7f2fe78bSCy Schubert
1609*7f2fe78bSCy Schubert krb5_clear_error_message(handle->context);
1610*7f2fe78bSCy Schubert
1611*7f2fe78bSCy Schubert if (principal == NULL || key_data == NULL || n_key_data == 0)
1612*7f2fe78bSCy Schubert return EINVAL;
1613*7f2fe78bSCy Schubert
1614*7f2fe78bSCy Schubert /* hist_princ will be NULL when initializing the database. */
1615*7f2fe78bSCy Schubert if (hist_princ != NULL &&
1616*7f2fe78bSCy Schubert krb5_principal_compare(handle->context, principal, hist_princ))
1617*7f2fe78bSCy Schubert return KADM5_PROTECT_PRINCIPAL;
1618*7f2fe78bSCy Schubert
1619*7f2fe78bSCy Schubert /* For now, all keys must have the same kvno. */
1620*7f2fe78bSCy Schubert kvno = key_data[0].kvno;
1621*7f2fe78bSCy Schubert for (i = 1; i < n_key_data; i++) {
1622*7f2fe78bSCy Schubert if (key_data[i].kvno != kvno)
1623*7f2fe78bSCy Schubert return KADM5_SETKEY_BAD_KVNO;
1624*7f2fe78bSCy Schubert }
1625*7f2fe78bSCy Schubert
1626*7f2fe78bSCy Schubert ret = kdb_get_entry(handle, principal, &kdb, &adb);
1627*7f2fe78bSCy Schubert if (ret)
1628*7f2fe78bSCy Schubert return ret;
1629*7f2fe78bSCy Schubert
1630*7f2fe78bSCy Schubert /* We will always be changing the key data, attributes, auth failure count,
1631*7f2fe78bSCy Schubert * and password expiration time. */
1632*7f2fe78bSCy Schubert kdb->mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES | KADM5_FAIL_AUTH_COUNT |
1633*7f2fe78bSCy Schubert KADM5_PW_EXPIRATION;
1634*7f2fe78bSCy Schubert
1635*7f2fe78bSCy Schubert if (kvno == 0) {
1636*7f2fe78bSCy Schubert /* Pick the next kvno. */
1637*7f2fe78bSCy Schubert for (i = 0; i < kdb->n_key_data; i++) {
1638*7f2fe78bSCy Schubert if (kdb->key_data[i].key_data_kvno > kvno)
1639*7f2fe78bSCy Schubert kvno = kdb->key_data[i].key_data_kvno;
1640*7f2fe78bSCy Schubert }
1641*7f2fe78bSCy Schubert kvno++;
1642*7f2fe78bSCy Schubert } else if (keepold) {
1643*7f2fe78bSCy Schubert /* Check that the kvno does collide with existing keys. */
1644*7f2fe78bSCy Schubert for (i = 0; i < kdb->n_key_data; i++) {
1645*7f2fe78bSCy Schubert if (kdb->key_data[i].key_data_kvno == kvno) {
1646*7f2fe78bSCy Schubert ret = KADM5_SETKEY_BAD_KVNO;
1647*7f2fe78bSCy Schubert goto done;
1648*7f2fe78bSCy Schubert }
1649*7f2fe78bSCy Schubert }
1650*7f2fe78bSCy Schubert }
1651*7f2fe78bSCy Schubert
1652*7f2fe78bSCy Schubert ret = make_ks_from_key_data(handle->context, key_data, n_key_data,
1653*7f2fe78bSCy Schubert &ks_from_keys);
1654*7f2fe78bSCy Schubert if (ret)
1655*7f2fe78bSCy Schubert goto done;
1656*7f2fe78bSCy Schubert
1657*7f2fe78bSCy Schubert ret = apply_keysalt_policy(handle, adb.policy, n_key_data, ks_from_keys,
1658*7f2fe78bSCy Schubert NULL, NULL);
1659*7f2fe78bSCy Schubert free(ks_from_keys);
1660*7f2fe78bSCy Schubert if (ret)
1661*7f2fe78bSCy Schubert goto done;
1662*7f2fe78bSCy Schubert
1663*7f2fe78bSCy Schubert for (i = 0; i < n_key_data; i++) {
1664*7f2fe78bSCy Schubert for (j = i + 1; j < n_key_data; j++) {
1665*7f2fe78bSCy Schubert ret = krb5_c_enctype_compare(handle->context,
1666*7f2fe78bSCy Schubert key_data[i].key.enctype,
1667*7f2fe78bSCy Schubert key_data[j].key.enctype,
1668*7f2fe78bSCy Schubert &similar);
1669*7f2fe78bSCy Schubert if (ret)
1670*7f2fe78bSCy Schubert goto done;
1671*7f2fe78bSCy Schubert if (similar) {
1672*7f2fe78bSCy Schubert if (key_data[i].salt.type == key_data[j].salt.type) {
1673*7f2fe78bSCy Schubert ret = KADM5_SETKEY_DUP_ENCTYPES;
1674*7f2fe78bSCy Schubert goto done;
1675*7f2fe78bSCy Schubert }
1676*7f2fe78bSCy Schubert }
1677*7f2fe78bSCy Schubert }
1678*7f2fe78bSCy Schubert }
1679*7f2fe78bSCy Schubert
1680*7f2fe78bSCy Schubert n_new_key_data = n_key_data + (keepold ? kdb->n_key_data : 0);
1681*7f2fe78bSCy Schubert new_key_data = calloc(n_new_key_data, sizeof(krb5_key_data));
1682*7f2fe78bSCy Schubert if (new_key_data == NULL) {
1683*7f2fe78bSCy Schubert n_new_key_data = 0;
1684*7f2fe78bSCy Schubert ret = ENOMEM;
1685*7f2fe78bSCy Schubert goto done;
1686*7f2fe78bSCy Schubert }
1687*7f2fe78bSCy Schubert
1688*7f2fe78bSCy Schubert n_new_key_data = 0;
1689*7f2fe78bSCy Schubert for (i = 0; i < n_key_data; i++) {
1690*7f2fe78bSCy Schubert
1691*7f2fe78bSCy Schubert ret = kdb_get_active_mkey(handle, NULL, &act_mkey);
1692*7f2fe78bSCy Schubert if (ret)
1693*7f2fe78bSCy Schubert goto done;
1694*7f2fe78bSCy Schubert
1695*7f2fe78bSCy Schubert ret = krb5_dbe_encrypt_key_data(handle->context, act_mkey,
1696*7f2fe78bSCy Schubert &key_data[i].key, &key_data[i].salt,
1697*7f2fe78bSCy Schubert kvno, &new_key_data[i]);
1698*7f2fe78bSCy Schubert if (ret)
1699*7f2fe78bSCy Schubert goto done;
1700*7f2fe78bSCy Schubert
1701*7f2fe78bSCy Schubert n_new_key_data++;
1702*7f2fe78bSCy Schubert }
1703*7f2fe78bSCy Schubert
1704*7f2fe78bSCy Schubert /* Copy old key data if necessary. */
1705*7f2fe78bSCy Schubert if (keepold) {
1706*7f2fe78bSCy Schubert memcpy(new_key_data + n_new_key_data, kdb->key_data,
1707*7f2fe78bSCy Schubert kdb->n_key_data * sizeof(krb5_key_data));
1708*7f2fe78bSCy Schubert memset(kdb->key_data, 0, kdb->n_key_data * sizeof(krb5_key_data));
1709*7f2fe78bSCy Schubert
1710*7f2fe78bSCy Schubert /*
1711*7f2fe78bSCy Schubert * Sort the keys to maintain the defined kvno order. We only need to
1712*7f2fe78bSCy Schubert * sort if we keep old keys, as otherwise we allow only a single kvno
1713*7f2fe78bSCy Schubert * to be specified.
1714*7f2fe78bSCy Schubert */
1715*7f2fe78bSCy Schubert krb5_dbe_sort_key_data(new_key_data, n_new_key_data);
1716*7f2fe78bSCy Schubert }
1717*7f2fe78bSCy Schubert
1718*7f2fe78bSCy Schubert /* Replace kdb->key_data with the new keys. */
1719*7f2fe78bSCy Schubert cleanup_key_data(handle->context, kdb->n_key_data, kdb->key_data);
1720*7f2fe78bSCy Schubert kdb->key_data = new_key_data;
1721*7f2fe78bSCy Schubert kdb->n_key_data = n_new_key_data;
1722*7f2fe78bSCy Schubert new_key_data = NULL;
1723*7f2fe78bSCy Schubert n_new_key_data = 0;
1724*7f2fe78bSCy Schubert
1725*7f2fe78bSCy Schubert kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1726*7f2fe78bSCy Schubert
1727*7f2fe78bSCy Schubert ret = krb5_timeofday(handle->context, &now);
1728*7f2fe78bSCy Schubert if (ret)
1729*7f2fe78bSCy Schubert goto done;
1730*7f2fe78bSCy Schubert
1731*7f2fe78bSCy Schubert if (adb.aux_attributes & KADM5_POLICY) {
1732*7f2fe78bSCy Schubert ret = get_policy(handle, adb.policy, &pol, &have_pol);
1733*7f2fe78bSCy Schubert if (ret)
1734*7f2fe78bSCy Schubert goto done;
1735*7f2fe78bSCy Schubert }
1736*7f2fe78bSCy Schubert
1737*7f2fe78bSCy Schubert kdb->pw_expiration = 0;
1738*7f2fe78bSCy Schubert if (have_pol && pol.pw_max_life)
1739*7f2fe78bSCy Schubert kdb->pw_expiration = ts_incr(now, pol.pw_max_life);
1740*7f2fe78bSCy Schubert
1741*7f2fe78bSCy Schubert ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now);
1742*7f2fe78bSCy Schubert if (ret)
1743*7f2fe78bSCy Schubert goto done;
1744*7f2fe78bSCy Schubert
1745*7f2fe78bSCy Schubert /* Unlock principal on this KDC. */
1746*7f2fe78bSCy Schubert kdb->fail_auth_count = 0;
1747*7f2fe78bSCy Schubert
1748*7f2fe78bSCy Schubert ret = kdb_put_entry(handle, kdb, &adb);
1749*7f2fe78bSCy Schubert if (ret)
1750*7f2fe78bSCy Schubert goto done;
1751*7f2fe78bSCy Schubert
1752*7f2fe78bSCy Schubert ret = KADM5_OK;
1753*7f2fe78bSCy Schubert
1754*7f2fe78bSCy Schubert done:
1755*7f2fe78bSCy Schubert cleanup_key_data(handle->context, n_new_key_data, new_key_data);
1756*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, &adb);
1757*7f2fe78bSCy Schubert if (have_pol)
1758*7f2fe78bSCy Schubert kadm5_free_policy_ent(handle->lhandle, &pol);
1759*7f2fe78bSCy Schubert return ret;
1760*7f2fe78bSCy Schubert }
1761*7f2fe78bSCy Schubert
1762*7f2fe78bSCy Schubert /*
1763*7f2fe78bSCy Schubert * Return the list of keys like kadm5_randkey_principal,
1764*7f2fe78bSCy Schubert * but don't modify the principal.
1765*7f2fe78bSCy Schubert */
1766*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_get_principal_keys(void * server_handle,krb5_principal principal,krb5_kvno kvno,kadm5_key_data ** key_data_out,int * n_key_data_out)1767*7f2fe78bSCy Schubert kadm5_get_principal_keys(void *server_handle /* IN */,
1768*7f2fe78bSCy Schubert krb5_principal principal /* IN */,
1769*7f2fe78bSCy Schubert krb5_kvno kvno /* IN */,
1770*7f2fe78bSCy Schubert kadm5_key_data **key_data_out /* OUT */,
1771*7f2fe78bSCy Schubert int *n_key_data_out /* OUT */)
1772*7f2fe78bSCy Schubert {
1773*7f2fe78bSCy Schubert krb5_db_entry *kdb;
1774*7f2fe78bSCy Schubert osa_princ_ent_rec adb;
1775*7f2fe78bSCy Schubert kadm5_ret_t ret;
1776*7f2fe78bSCy Schubert kadm5_server_handle_t handle = server_handle;
1777*7f2fe78bSCy Schubert kadm5_key_data *key_data = NULL;
1778*7f2fe78bSCy Schubert int i, nkeys = 0;
1779*7f2fe78bSCy Schubert
1780*7f2fe78bSCy Schubert if (principal == NULL || key_data_out == NULL || n_key_data_out == NULL)
1781*7f2fe78bSCy Schubert return EINVAL;
1782*7f2fe78bSCy Schubert
1783*7f2fe78bSCy Schubert CHECK_HANDLE(server_handle);
1784*7f2fe78bSCy Schubert
1785*7f2fe78bSCy Schubert if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1786*7f2fe78bSCy Schubert return(ret);
1787*7f2fe78bSCy Schubert
1788*7f2fe78bSCy Schubert key_data = calloc(kdb->n_key_data, sizeof(kadm5_key_data));
1789*7f2fe78bSCy Schubert if (key_data == NULL) {
1790*7f2fe78bSCy Schubert ret = ENOMEM;
1791*7f2fe78bSCy Schubert goto done;
1792*7f2fe78bSCy Schubert }
1793*7f2fe78bSCy Schubert
1794*7f2fe78bSCy Schubert for (i = 0, nkeys = 0; i < kdb->n_key_data; i++) {
1795*7f2fe78bSCy Schubert if (kvno != 0 && kvno != kdb->key_data[i].key_data_kvno)
1796*7f2fe78bSCy Schubert continue;
1797*7f2fe78bSCy Schubert key_data[nkeys].kvno = kdb->key_data[i].key_data_kvno;
1798*7f2fe78bSCy Schubert
1799*7f2fe78bSCy Schubert ret = krb5_dbe_decrypt_key_data(handle->context, NULL,
1800*7f2fe78bSCy Schubert &kdb->key_data[i],
1801*7f2fe78bSCy Schubert &key_data[nkeys].key,
1802*7f2fe78bSCy Schubert &key_data[nkeys].salt);
1803*7f2fe78bSCy Schubert if (ret)
1804*7f2fe78bSCy Schubert goto done;
1805*7f2fe78bSCy Schubert nkeys++;
1806*7f2fe78bSCy Schubert }
1807*7f2fe78bSCy Schubert
1808*7f2fe78bSCy Schubert *n_key_data_out = nkeys;
1809*7f2fe78bSCy Schubert *key_data_out = key_data;
1810*7f2fe78bSCy Schubert key_data = NULL;
1811*7f2fe78bSCy Schubert nkeys = 0;
1812*7f2fe78bSCy Schubert ret = KADM5_OK;
1813*7f2fe78bSCy Schubert
1814*7f2fe78bSCy Schubert done:
1815*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, &adb);
1816*7f2fe78bSCy Schubert kadm5_free_kadm5_key_data(handle->context, nkeys, key_data);
1817*7f2fe78bSCy Schubert
1818*7f2fe78bSCy Schubert return ret;
1819*7f2fe78bSCy Schubert }
1820*7f2fe78bSCy Schubert
1821*7f2fe78bSCy Schubert
1822*7f2fe78bSCy Schubert /*
1823*7f2fe78bSCy Schubert * Allocate an array of n_key_data krb5_keyblocks, fill in each
1824*7f2fe78bSCy Schubert * element with the results of decrypting the nth key in key_data,
1825*7f2fe78bSCy Schubert * and if n_keys is not NULL fill it in with the
1826*7f2fe78bSCy Schubert * number of keys decrypted.
1827*7f2fe78bSCy Schubert */
decrypt_key_data(krb5_context context,int n_key_data,krb5_key_data * key_data,krb5_keyblock ** keyblocks,int * n_keys)1828*7f2fe78bSCy Schubert static int decrypt_key_data(krb5_context context,
1829*7f2fe78bSCy Schubert int n_key_data, krb5_key_data *key_data,
1830*7f2fe78bSCy Schubert krb5_keyblock **keyblocks, int *n_keys)
1831*7f2fe78bSCy Schubert {
1832*7f2fe78bSCy Schubert krb5_keyblock *keys;
1833*7f2fe78bSCy Schubert int ret, i;
1834*7f2fe78bSCy Schubert
1835*7f2fe78bSCy Schubert keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock));
1836*7f2fe78bSCy Schubert if (keys == NULL)
1837*7f2fe78bSCy Schubert return ENOMEM;
1838*7f2fe78bSCy Schubert memset(keys, 0, n_key_data*sizeof(krb5_keyblock));
1839*7f2fe78bSCy Schubert
1840*7f2fe78bSCy Schubert for (i = 0; i < n_key_data; i++) {
1841*7f2fe78bSCy Schubert ret = krb5_dbe_decrypt_key_data(context, NULL, &key_data[i], &keys[i],
1842*7f2fe78bSCy Schubert NULL);
1843*7f2fe78bSCy Schubert if (ret) {
1844*7f2fe78bSCy Schubert for (; i >= 0; i--)
1845*7f2fe78bSCy Schubert krb5_free_keyblock_contents(context, &keys[i]);
1846*7f2fe78bSCy Schubert free(keys);
1847*7f2fe78bSCy Schubert return ret;
1848*7f2fe78bSCy Schubert }
1849*7f2fe78bSCy Schubert }
1850*7f2fe78bSCy Schubert
1851*7f2fe78bSCy Schubert *keyblocks = keys;
1852*7f2fe78bSCy Schubert if (n_keys)
1853*7f2fe78bSCy Schubert *n_keys = n_key_data;
1854*7f2fe78bSCy Schubert
1855*7f2fe78bSCy Schubert return 0;
1856*7f2fe78bSCy Schubert }
1857*7f2fe78bSCy Schubert
1858*7f2fe78bSCy Schubert /*
1859*7f2fe78bSCy Schubert * Function: kadm5_decrypt_key
1860*7f2fe78bSCy Schubert *
1861*7f2fe78bSCy Schubert * Purpose: Retrieves and decrypts a principal key.
1862*7f2fe78bSCy Schubert *
1863*7f2fe78bSCy Schubert * Arguments:
1864*7f2fe78bSCy Schubert *
1865*7f2fe78bSCy Schubert * server_handle (r) kadm5 handle
1866*7f2fe78bSCy Schubert * entry (r) principal retrieved with kadm5_get_principal
1867*7f2fe78bSCy Schubert * ktype (r) enctype to search for, or -1 to ignore
1868*7f2fe78bSCy Schubert * stype (r) salt type to search for, or -1 to ignore
1869*7f2fe78bSCy Schubert * kvno (r) kvno to search for, -1 for max, 0 for max
1870*7f2fe78bSCy Schubert * only if it also matches ktype and stype
1871*7f2fe78bSCy Schubert * keyblock (w) keyblock to fill in
1872*7f2fe78bSCy Schubert * keysalt (w) keysalt to fill in, or NULL
1873*7f2fe78bSCy Schubert * kvnop (w) kvno to fill in, or NULL
1874*7f2fe78bSCy Schubert *
1875*7f2fe78bSCy Schubert * Effects: Searches the key_data array of entry, which must have been
1876*7f2fe78bSCy Schubert * retrieved with kadm5_get_principal with the KADM5_KEY_DATA mask, to
1877*7f2fe78bSCy Schubert * find a key with a specified enctype, salt type, and kvno in a
1878*7f2fe78bSCy Schubert * principal entry. If not found, return ENOENT. Otherwise, decrypt
1879*7f2fe78bSCy Schubert * it with the master key, and return the key in keyblock, the salt
1880*7f2fe78bSCy Schubert * in salttype, and the key version number in kvno.
1881*7f2fe78bSCy Schubert *
1882*7f2fe78bSCy Schubert * If ktype or stype is -1, it is ignored for the search. If kvno is
1883*7f2fe78bSCy Schubert * -1, ktype and stype are ignored and the key with the max kvno is
1884*7f2fe78bSCy Schubert * returned. If kvno is 0, only the key with the max kvno is returned
1885*7f2fe78bSCy Schubert * and only if it matches the ktype and stype; otherwise, ENOENT is
1886*7f2fe78bSCy Schubert * returned.
1887*7f2fe78bSCy Schubert */
kadm5_decrypt_key(void * server_handle,kadm5_principal_ent_t entry,krb5_int32 ktype,krb5_int32 stype,krb5_int32 kvno,krb5_keyblock * keyblock,krb5_keysalt * keysalt,int * kvnop)1888*7f2fe78bSCy Schubert kadm5_ret_t kadm5_decrypt_key(void *server_handle,
1889*7f2fe78bSCy Schubert kadm5_principal_ent_t entry, krb5_int32
1890*7f2fe78bSCy Schubert ktype, krb5_int32 stype, krb5_int32
1891*7f2fe78bSCy Schubert kvno, krb5_keyblock *keyblock,
1892*7f2fe78bSCy Schubert krb5_keysalt *keysalt, int *kvnop)
1893*7f2fe78bSCy Schubert {
1894*7f2fe78bSCy Schubert kadm5_server_handle_t handle = server_handle;
1895*7f2fe78bSCy Schubert krb5_db_entry dbent;
1896*7f2fe78bSCy Schubert krb5_key_data *key_data;
1897*7f2fe78bSCy Schubert krb5_keyblock *mkey_ptr;
1898*7f2fe78bSCy Schubert int ret;
1899*7f2fe78bSCy Schubert
1900*7f2fe78bSCy Schubert CHECK_HANDLE(server_handle);
1901*7f2fe78bSCy Schubert
1902*7f2fe78bSCy Schubert if (entry->n_key_data == 0 || entry->key_data == NULL)
1903*7f2fe78bSCy Schubert return EINVAL;
1904*7f2fe78bSCy Schubert
1905*7f2fe78bSCy Schubert /* find_enctype only uses these two fields */
1906*7f2fe78bSCy Schubert dbent.n_key_data = entry->n_key_data;
1907*7f2fe78bSCy Schubert dbent.key_data = entry->key_data;
1908*7f2fe78bSCy Schubert if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype,
1909*7f2fe78bSCy Schubert stype, kvno, &key_data)))
1910*7f2fe78bSCy Schubert return ret;
1911*7f2fe78bSCy Schubert
1912*7f2fe78bSCy Schubert /* find_mkey only uses this field */
1913*7f2fe78bSCy Schubert dbent.tl_data = entry->tl_data;
1914*7f2fe78bSCy Schubert if ((ret = krb5_dbe_find_mkey(handle->context, &dbent, &mkey_ptr))) {
1915*7f2fe78bSCy Schubert /* try refreshing master key list */
1916*7f2fe78bSCy Schubert /* XXX it would nice if we had the mkvno here for optimization */
1917*7f2fe78bSCy Schubert if (krb5_db_fetch_mkey_list(handle->context, master_princ,
1918*7f2fe78bSCy Schubert &master_keyblock) == 0) {
1919*7f2fe78bSCy Schubert if ((ret = krb5_dbe_find_mkey(handle->context, &dbent,
1920*7f2fe78bSCy Schubert &mkey_ptr))) {
1921*7f2fe78bSCy Schubert return ret;
1922*7f2fe78bSCy Schubert }
1923*7f2fe78bSCy Schubert } else {
1924*7f2fe78bSCy Schubert return ret;
1925*7f2fe78bSCy Schubert }
1926*7f2fe78bSCy Schubert }
1927*7f2fe78bSCy Schubert
1928*7f2fe78bSCy Schubert if ((ret = krb5_dbe_decrypt_key_data(handle->context, NULL, key_data,
1929*7f2fe78bSCy Schubert keyblock, keysalt)))
1930*7f2fe78bSCy Schubert return ret;
1931*7f2fe78bSCy Schubert
1932*7f2fe78bSCy Schubert /*
1933*7f2fe78bSCy Schubert * Coerce the enctype of the output keyblock in case we got an
1934*7f2fe78bSCy Schubert * inexact match on the enctype; this behavior will go away when
1935*7f2fe78bSCy Schubert * the key storage architecture gets redesigned for 1.3.
1936*7f2fe78bSCy Schubert */
1937*7f2fe78bSCy Schubert if (ktype != -1)
1938*7f2fe78bSCy Schubert keyblock->enctype = ktype;
1939*7f2fe78bSCy Schubert
1940*7f2fe78bSCy Schubert if (kvnop)
1941*7f2fe78bSCy Schubert *kvnop = key_data->key_data_kvno;
1942*7f2fe78bSCy Schubert
1943*7f2fe78bSCy Schubert return KADM5_OK;
1944*7f2fe78bSCy Schubert }
1945*7f2fe78bSCy Schubert
1946*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_purgekeys(void * server_handle,krb5_principal principal,int keepkvno)1947*7f2fe78bSCy Schubert kadm5_purgekeys(void *server_handle,
1948*7f2fe78bSCy Schubert krb5_principal principal,
1949*7f2fe78bSCy Schubert int keepkvno)
1950*7f2fe78bSCy Schubert {
1951*7f2fe78bSCy Schubert kadm5_server_handle_t handle = server_handle;
1952*7f2fe78bSCy Schubert kadm5_ret_t ret;
1953*7f2fe78bSCy Schubert krb5_db_entry *kdb;
1954*7f2fe78bSCy Schubert osa_princ_ent_rec adb;
1955*7f2fe78bSCy Schubert krb5_key_data *old_keydata;
1956*7f2fe78bSCy Schubert int n_old_keydata;
1957*7f2fe78bSCy Schubert int i, j, k;
1958*7f2fe78bSCy Schubert
1959*7f2fe78bSCy Schubert CHECK_HANDLE(server_handle);
1960*7f2fe78bSCy Schubert
1961*7f2fe78bSCy Schubert if (principal == NULL)
1962*7f2fe78bSCy Schubert return EINVAL;
1963*7f2fe78bSCy Schubert
1964*7f2fe78bSCy Schubert ret = kdb_get_entry(handle, principal, &kdb, &adb);
1965*7f2fe78bSCy Schubert if (ret)
1966*7f2fe78bSCy Schubert return(ret);
1967*7f2fe78bSCy Schubert
1968*7f2fe78bSCy Schubert if (keepkvno <= 0) {
1969*7f2fe78bSCy Schubert keepkvno = krb5_db_get_key_data_kvno(handle->context, kdb->n_key_data,
1970*7f2fe78bSCy Schubert kdb->key_data);
1971*7f2fe78bSCy Schubert }
1972*7f2fe78bSCy Schubert
1973*7f2fe78bSCy Schubert old_keydata = kdb->key_data;
1974*7f2fe78bSCy Schubert n_old_keydata = kdb->n_key_data;
1975*7f2fe78bSCy Schubert kdb->n_key_data = 0;
1976*7f2fe78bSCy Schubert /* Allocate one extra key_data to avoid allocating 0 bytes. */
1977*7f2fe78bSCy Schubert kdb->key_data = calloc(n_old_keydata, sizeof(krb5_key_data));
1978*7f2fe78bSCy Schubert if (kdb->key_data == NULL) {
1979*7f2fe78bSCy Schubert ret = ENOMEM;
1980*7f2fe78bSCy Schubert goto done;
1981*7f2fe78bSCy Schubert }
1982*7f2fe78bSCy Schubert memset(kdb->key_data, 0, n_old_keydata * sizeof(krb5_key_data));
1983*7f2fe78bSCy Schubert for (i = 0, j = 0; i < n_old_keydata; i++) {
1984*7f2fe78bSCy Schubert if (old_keydata[i].key_data_kvno < keepkvno)
1985*7f2fe78bSCy Schubert continue;
1986*7f2fe78bSCy Schubert
1987*7f2fe78bSCy Schubert /* Alias the key_data_contents pointers; we null them out in the
1988*7f2fe78bSCy Schubert * source array immediately after. */
1989*7f2fe78bSCy Schubert kdb->key_data[j] = old_keydata[i];
1990*7f2fe78bSCy Schubert for (k = 0; k < old_keydata[i].key_data_ver; k++) {
1991*7f2fe78bSCy Schubert old_keydata[i].key_data_contents[k] = NULL;
1992*7f2fe78bSCy Schubert }
1993*7f2fe78bSCy Schubert j++;
1994*7f2fe78bSCy Schubert }
1995*7f2fe78bSCy Schubert kdb->n_key_data = j;
1996*7f2fe78bSCy Schubert cleanup_key_data(handle->context, n_old_keydata, old_keydata);
1997*7f2fe78bSCy Schubert
1998*7f2fe78bSCy Schubert kdb->mask = KADM5_KEY_DATA;
1999*7f2fe78bSCy Schubert ret = kdb_put_entry(handle, kdb, &adb);
2000*7f2fe78bSCy Schubert if (ret)
2001*7f2fe78bSCy Schubert goto done;
2002*7f2fe78bSCy Schubert
2003*7f2fe78bSCy Schubert done:
2004*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, &adb);
2005*7f2fe78bSCy Schubert return ret;
2006*7f2fe78bSCy Schubert }
2007*7f2fe78bSCy Schubert
2008*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_get_strings(void * server_handle,krb5_principal principal,krb5_string_attr ** strings_out,int * count_out)2009*7f2fe78bSCy Schubert kadm5_get_strings(void *server_handle, krb5_principal principal,
2010*7f2fe78bSCy Schubert krb5_string_attr **strings_out, int *count_out)
2011*7f2fe78bSCy Schubert {
2012*7f2fe78bSCy Schubert kadm5_server_handle_t handle = server_handle;
2013*7f2fe78bSCy Schubert kadm5_ret_t ret;
2014*7f2fe78bSCy Schubert krb5_db_entry *kdb = NULL;
2015*7f2fe78bSCy Schubert
2016*7f2fe78bSCy Schubert *strings_out = NULL;
2017*7f2fe78bSCy Schubert *count_out = 0;
2018*7f2fe78bSCy Schubert CHECK_HANDLE(server_handle);
2019*7f2fe78bSCy Schubert if (principal == NULL)
2020*7f2fe78bSCy Schubert return EINVAL;
2021*7f2fe78bSCy Schubert
2022*7f2fe78bSCy Schubert ret = kdb_get_entry(handle, principal, &kdb, NULL);
2023*7f2fe78bSCy Schubert if (ret)
2024*7f2fe78bSCy Schubert return ret;
2025*7f2fe78bSCy Schubert
2026*7f2fe78bSCy Schubert ret = krb5_dbe_get_strings(handle->context, kdb, strings_out, count_out);
2027*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, NULL);
2028*7f2fe78bSCy Schubert return ret;
2029*7f2fe78bSCy Schubert }
2030*7f2fe78bSCy Schubert
2031*7f2fe78bSCy Schubert kadm5_ret_t
kadm5_set_string(void * server_handle,krb5_principal principal,const char * key,const char * value)2032*7f2fe78bSCy Schubert kadm5_set_string(void *server_handle, krb5_principal principal,
2033*7f2fe78bSCy Schubert const char *key, const char *value)
2034*7f2fe78bSCy Schubert {
2035*7f2fe78bSCy Schubert kadm5_server_handle_t handle = server_handle;
2036*7f2fe78bSCy Schubert kadm5_ret_t ret;
2037*7f2fe78bSCy Schubert krb5_db_entry *kdb;
2038*7f2fe78bSCy Schubert osa_princ_ent_rec adb;
2039*7f2fe78bSCy Schubert
2040*7f2fe78bSCy Schubert CHECK_HANDLE(server_handle);
2041*7f2fe78bSCy Schubert if (principal == NULL || key == NULL)
2042*7f2fe78bSCy Schubert return EINVAL;
2043*7f2fe78bSCy Schubert
2044*7f2fe78bSCy Schubert ret = kdb_get_entry(handle, principal, &kdb, &adb);
2045*7f2fe78bSCy Schubert if (ret)
2046*7f2fe78bSCy Schubert return ret;
2047*7f2fe78bSCy Schubert
2048*7f2fe78bSCy Schubert ret = krb5_dbe_set_string(handle->context, kdb, key, value);
2049*7f2fe78bSCy Schubert if (ret)
2050*7f2fe78bSCy Schubert goto done;
2051*7f2fe78bSCy Schubert
2052*7f2fe78bSCy Schubert kdb->mask = KADM5_TL_DATA;
2053*7f2fe78bSCy Schubert ret = kdb_put_entry(handle, kdb, &adb);
2054*7f2fe78bSCy Schubert
2055*7f2fe78bSCy Schubert done:
2056*7f2fe78bSCy Schubert kdb_free_entry(handle, kdb, &adb);
2057*7f2fe78bSCy Schubert return ret;
2058*7f2fe78bSCy Schubert }
2059