|
1 # |
|
2 # This patch cherry-picks Password history in LDAP KDB plugin feature from |
|
3 # MIT krb5 1.15. |
|
4 # |
|
5 # It is 1-1 port of the following changesets: |
|
6 # 44ad57d8d38efc944f64536354435f5b721c0ee0 |
|
7 # d7f91ac2f6655e77bb3658c2c8cc6132f958a340 |
|
8 # b46cce2ea8c0841f7f93db73eefcd180c87a3eae |
|
9 # 9526953f36b39323ec07448a5f218d27c6f1c76f |
|
10 # |
|
11 # Patch source: upstream |
|
12 # |
|
13 # When upgrading to MIT krb5 1.15 this patch will be dropped. |
|
14 # |
|
15 --- a/src/include/kdb.h |
|
16 +++ b/src/include/kdb.h |
|
17 @@ -1,6 +1,6 @@ |
|
18 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
|
19 /* |
|
20 - * Copyright 1990,1991 by the Massachusetts Institute of Technology. |
|
21 + * Copyright 1990, 1991, 2016 by the Massachusetts Institute of Technology. |
|
22 * All Rights Reserved. |
|
23 * |
|
24 * Export of this software from the United States of America may |
|
25 @@ -209,6 +209,8 @@ typedef struct _krb5_db_entry_new { |
|
26 |
|
27 krb5_principal princ; /* Length, data */ |
|
28 krb5_tl_data * tl_data; /* Linked list */ |
|
29 + |
|
30 + /* key_data must be sorted by kvno in descending order. */ |
|
31 krb5_key_data * key_data; /* Array */ |
|
32 } krb5_db_entry; |
|
33 |
|
34 @@ -683,6 +685,19 @@ krb5_error_code krb5_db_check_allowed_to |
|
35 const krb5_db_entry *server, |
|
36 krb5_const_principal proxy); |
|
37 |
|
38 +/** |
|
39 + * Sort an array of @a krb5_key_data keys in descending order by their kvno. |
|
40 + * Key data order within a kvno is preserved. |
|
41 + * |
|
42 + * @param key_data |
|
43 + * The @a krb5_key_data array to sort. This is sorted in place so the |
|
44 + * array will be modified. |
|
45 + * @param key_data_length |
|
46 + * The length of @a key_data. |
|
47 + */ |
|
48 +void |
|
49 +krb5_dbe_sort_key_data(krb5_key_data *key_data, size_t key_data_length); |
|
50 + |
|
51 /* default functions. Should not be directly called */ |
|
52 /* |
|
53 * Default functions prototype |
|
54 --- a/src/lib/kadm5/admin.h |
|
55 +++ b/src/lib/kadm5/admin.h |
|
56 @@ -113,7 +113,7 @@ typedef long kadm5_ret_t; |
|
57 #define KADM5_RANDKEY_USED 0x100000 |
|
58 #endif |
|
59 #define KADM5_LOAD 0x200000 |
|
60 -#define KADM5_NOKEY 0x400000 |
|
61 +#define KADM5_KEY_HIST 0x400000 |
|
62 |
|
63 /* all but KEY_DATA, TL_DATA, LOAD */ |
|
64 #define KADM5_PRINCIPAL_NORMAL_MASK 0x41ffff |
|
65 --- a/src/lib/kadm5/srv/svr_principal.c |
|
66 +++ b/src/lib/kadm5/srv/svr_principal.c |
|
67 @@ -1084,6 +1084,16 @@ check_pw_reuse(krb5_context context, |
|
68 return(0); |
|
69 } |
|
70 |
|
71 +static void |
|
72 +free_history_entry(krb5_context context, osa_pw_hist_ent *hist) |
|
73 +{ |
|
74 + int i; |
|
75 + |
|
76 + for (i = 0; i < hist->n_key_data; i++) |
|
77 + krb5_free_key_data_contents(context, &hist->key_data[i]); |
|
78 + free(hist->key_data); |
|
79 +} |
|
80 + |
|
81 /* |
|
82 * Function: create_history_entry |
|
83 * |
|
84 @@ -1097,7 +1107,7 @@ check_pw_reuse(krb5_context context, |
|
85 * hist_key (r) history keyblock to encrypt key data with |
|
86 * n_key_data (r) number of elements in key_data |
|
87 * key_data (r) keys to add to the history entry |
|
88 - * hist (w) history entry to fill in |
|
89 + * hist_out (w) history entry to fill in |
|
90 * |
|
91 * Effects: |
|
92 * |
|
93 @@ -1109,45 +1119,62 @@ check_pw_reuse(krb5_context context, |
|
94 static |
|
95 int create_history_entry(krb5_context context, |
|
96 krb5_keyblock *hist_key, int n_key_data, |
|
97 - krb5_key_data *key_data, osa_pw_hist_ent *hist) |
|
98 + krb5_key_data *key_data, osa_pw_hist_ent *hist_out) |
|
99 { |
|
100 - krb5_error_code ret; |
|
101 + int i; |
|
102 + krb5_error_code ret = 0; |
|
103 krb5_keyblock key; |
|
104 krb5_keysalt salt; |
|
105 - int i; |
|
106 + krb5_ui_2 kvno; |
|
107 + osa_pw_hist_ent hist; |
|
108 + |
|
109 + hist_out->key_data = NULL; |
|
110 + hist_out->n_key_data = 0; |
|
111 + |
|
112 + if (n_key_data < 0) |
|
113 + return EINVAL; |
|
114 + |
|
115 + memset(&key, 0, sizeof(key)); |
|
116 + memset(&hist, 0, sizeof(hist)); |
|
117 + |
|
118 + if (n_key_data == 0) |
|
119 + goto cleanup; |
|
120 |
|
121 - hist->key_data = k5calloc(n_key_data, sizeof(krb5_key_data), &ret); |
|
122 - if (hist->key_data == NULL) |
|
123 - return ret; |
|
124 + hist.key_data = k5calloc(n_key_data, sizeof(krb5_key_data), &ret); |
|
125 + if (hist.key_data == NULL) |
|
126 + goto cleanup; |
|
127 + |
|
128 + /* We only want to store the most recent kvno, and key_data should already |
|
129 + * be sorted in descending order by kvno. */ |
|
130 + kvno = key_data[0].key_data_kvno; |
|
131 |
|
132 for (i = 0; i < n_key_data; i++) { |
|
133 - ret = krb5_dbe_decrypt_key_data(context, NULL, &key_data[i], &key, |
|
134 + if (key_data[i].key_data_kvno < kvno) |
|
135 + break; |
|
136 + ret = krb5_dbe_decrypt_key_data(context, NULL, |
|
137 + &key_data[i], &key, |
|
138 &salt); |
|
139 if (ret) |
|
140 - return ret; |
|
141 + goto cleanup; |
|
142 |
|
143 ret = krb5_dbe_encrypt_key_data(context, hist_key, &key, &salt, |
|
144 key_data[i].key_data_kvno, |
|
145 - &hist->key_data[i]); |
|
146 + &hist.key_data[hist.n_key_data]); |
|
147 if (ret) |
|
148 - return ret; |
|
149 - |
|
150 + goto cleanup; |
|
151 + hist.n_key_data++; |
|
152 krb5_free_keyblock_contents(context, &key); |
|
153 /* krb5_free_keysalt(context, &salt); */ |
|
154 } |
|
155 |
|
156 - hist->n_key_data = n_key_data; |
|
157 - return 0; |
|
158 -} |
|
159 - |
|
160 -static |
|
161 -void free_history_entry(krb5_context context, osa_pw_hist_ent *hist) |
|
162 -{ |
|
163 - int i; |
|
164 - |
|
165 - for (i = 0; i < hist->n_key_data; i++) |
|
166 - krb5_free_key_data_contents(context, &hist->key_data[i]); |
|
167 - free(hist->key_data); |
|
168 + *hist_out = hist; |
|
169 + hist.n_key_data = 0; |
|
170 + hist.key_data = NULL; |
|
171 + |
|
172 +cleanup: |
|
173 + krb5_free_keyblock_contents(context, &key); |
|
174 + free_history_entry(context, &hist); |
|
175 + return ret; |
|
176 } |
|
177 |
|
178 /* |
|
179 @@ -1526,11 +1553,14 @@ kadm5_chpass_principal_3(void *server_ha |
|
180 goto done; |
|
181 } |
|
182 |
|
183 - ret = add_to_history(handle->context, hist_kvno, &adb, &pol, |
|
184 - &hist); |
|
185 - if (ret) |
|
186 - goto done; |
|
187 - hist_added = 1; |
|
188 + /* Don't save empty history. */ |
|
189 + if (hist.n_key_data > 0) { |
|
190 + ret = add_to_history(handle->context, hist_kvno, &adb, &pol, |
|
191 + &hist); |
|
192 + if (ret) |
|
193 + goto done; |
|
194 + hist_added = 1; |
|
195 + } |
|
196 } |
|
197 |
|
198 if (pol.pw_max_life) |
|
199 @@ -1582,6 +1612,9 @@ kadm5_chpass_principal_3(void *server_ha |
|
200 KADM5_FAIL_AUTH_COUNT; |
|
201 /* | KADM5_CPW_FUNCTION */ |
|
202 |
|
203 + if (hist_added) |
|
204 + kdb->mask |= KADM5_KEY_HIST; |
|
205 + |
|
206 ret = k5_kadm5_hook_chpass(handle->context, handle->hook_handles, |
|
207 KADM5_HOOK_STAGE_PRECOMMIT, principal, keepold, |
|
208 new_n_ks_tuple, new_ks_tuple, password); |
|
209 --- a/src/lib/kdb/kdb5.c |
|
210 +++ b/src/lib/kdb/kdb5.c |
|
211 @@ -1,6 +1,7 @@ |
|
212 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
|
213 /* |
|
214 - * Copyright 2006, 2009, 2010 by the Massachusetts Institute of Technology. |
|
215 + * Copyright 2006, 2009, 2010, 2016 by the Massachusetts Institute of |
|
216 + * Technology. |
|
217 * All Rights Reserved. |
|
218 * |
|
219 * Export of this software from the United States of America may |
|
220 @@ -758,7 +759,15 @@ krb5_db_get_principal(krb5_context kcont |
|
221 return status; |
|
222 if (v->get_principal == NULL) |
|
223 return KRB5_PLUGIN_OP_NOTSUPP; |
|
224 - return v->get_principal(kcontext, search_for, flags, entry); |
|
225 + status = v->get_principal(kcontext, search_for, flags, entry); |
|
226 + if (status) |
|
227 + return status; |
|
228 + |
|
229 + /* Sort the keys in the db entry as some parts of krb5 expect it to be. */ |
|
230 + if ((*entry)->key_data != NULL) |
|
231 + krb5_dbe_sort_key_data((*entry)->key_data, (*entry)->n_key_data); |
|
232 + |
|
233 + return 0; |
|
234 } |
|
235 |
|
236 void |
|
237 @@ -948,6 +957,26 @@ krb5_db_delete_principal(krb5_context kc |
|
238 return status; |
|
239 } |
|
240 |
|
241 +/* |
|
242 + * Use a proxy function for iterate so that we can sort the keys before sending |
|
243 + * them to the callback. |
|
244 + */ |
|
245 +struct callback_proxy_args { |
|
246 + int (*func)(krb5_pointer, krb5_db_entry *); |
|
247 + krb5_pointer func_arg; |
|
248 +}; |
|
249 + |
|
250 +static int |
|
251 +sort_entry_callback_proxy(krb5_pointer func_arg, krb5_db_entry *entry) |
|
252 +{ |
|
253 + struct callback_proxy_args *args = (struct callback_proxy_args *)func_arg; |
|
254 + |
|
255 + /* Sort the keys in the db entry as some parts of krb5 expect it to be. */ |
|
256 + if (entry && entry->key_data) |
|
257 + krb5_dbe_sort_key_data(entry->key_data, entry->n_key_data); |
|
258 + return args->func(args->func_arg, entry); |
|
259 +} |
|
260 + |
|
261 krb5_error_code |
|
262 krb5_db_iterate(krb5_context kcontext, char *match_entry, |
|
263 int (*func)(krb5_pointer, krb5_db_entry *), |
|
264 @@ -955,13 +984,20 @@ krb5_db_iterate(krb5_context kcontext, c |
|
265 { |
|
266 krb5_error_code status = 0; |
|
267 kdb_vftabl *v; |
|
268 + struct callback_proxy_args proxy_args; |
|
269 |
|
270 status = get_vftabl(kcontext, &v); |
|
271 if (status) |
|
272 return status; |
|
273 if (v->iterate == NULL) |
|
274 return KRB5_PLUGIN_OP_NOTSUPP; |
|
275 - return v->iterate(kcontext, match_entry, func, func_arg, iterflags); |
|
276 + |
|
277 + /* Use the proxy function to sort key data before passing entries to |
|
278 + * callback. */ |
|
279 + proxy_args.func = func; |
|
280 + proxy_args.func_arg = func_arg; |
|
281 + return v->iterate(kcontext, match_entry, sort_entry_callback_proxy, |
|
282 + &proxy_args, iterflags); |
|
283 } |
|
284 |
|
285 /* Return a read only pointer alias to mkey list. Do not free this! */ |
|
286 @@ -2570,3 +2606,22 @@ krb5_db_check_allowed_to_delegate(krb5_c |
|
287 return KRB5_PLUGIN_OP_NOTSUPP; |
|
288 return v->check_allowed_to_delegate(kcontext, client, server, proxy); |
|
289 } |
|
290 + |
|
291 +void |
|
292 +krb5_dbe_sort_key_data(krb5_key_data *key_data, size_t key_data_length) |
|
293 +{ |
|
294 + size_t i, j; |
|
295 + krb5_key_data tmp; |
|
296 + |
|
297 + /* Use insertion sort as a stable sort. */ |
|
298 + for (i = 1; i < key_data_length; i++) { |
|
299 + j = i; |
|
300 + while (j > 0 && |
|
301 + key_data[j - 1].key_data_kvno < key_data[j].key_data_kvno) { |
|
302 + tmp = key_data[j]; |
|
303 + key_data[j] = key_data[j - 1]; |
|
304 + key_data[j - 1] = tmp; |
|
305 + j--; |
|
306 + } |
|
307 + } |
|
308 +} |
|
309 --- a/src/lib/kdb/libkdb5.exports |
|
310 +++ b/src/lib/kdb/libkdb5.exports |
|
311 @@ -99,3 +99,4 @@ ulog_get_sno_status |
|
312 ulog_replay |
|
313 ulog_set_last |
|
314 xdr_kdb_incr_update_t |
|
315 +krb5_dbe_sort_key_data |
|
316 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c |
|
317 +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c |
|
318 @@ -40,6 +40,7 @@ |
|
319 #include "ldap_pwd_policy.h" |
|
320 #include <time.h> |
|
321 #include <ctype.h> |
|
322 +#include <kadm5/admin.h> |
|
323 |
|
324 #ifdef NEED_STRPTIME_PROTO |
|
325 extern char *strptime(const char *, const char *, struct tm *); |
|
326 @@ -1324,6 +1325,22 @@ remove_overlapping_subtrees(char **list, |
|
327 *subtcount = count; |
|
328 } |
|
329 |
|
330 +static void |
|
331 +free_princ_ent_contents(osa_princ_ent_t princ_ent) |
|
332 +{ |
|
333 + unsigned int i; |
|
334 + |
|
335 + for (i = 0; i < princ_ent->old_key_len; i++) { |
|
336 + k5_free_key_data(princ_ent->old_keys[i].n_key_data, |
|
337 + princ_ent->old_keys[i].key_data); |
|
338 + princ_ent->old_keys[i].n_key_data = 0; |
|
339 + princ_ent->old_keys[i].key_data = NULL; |
|
340 + } |
|
341 + free(princ_ent->old_keys); |
|
342 + princ_ent->old_keys = NULL; |
|
343 + princ_ent->old_key_len = 0; |
|
344 +} |
|
345 + |
|
346 /* |
|
347 * Fill out a krb5_db_entry princ entry struct given a LDAP message containing |
|
348 * the results of a principal search of the directory. |
|
349 @@ -1344,6 +1361,9 @@ populate_krb5_db_entry(krb5_context cont |
|
350 char **pnvalues = NULL, **ocvalues = NULL, **a2d2 = NULL; |
|
351 struct berval **ber_key_data = NULL, **ber_tl_data = NULL; |
|
352 krb5_tl_data userinfo_tl_data = { NULL }, **endp, *tl; |
|
353 + osa_princ_ent_rec princ_ent; |
|
354 + |
|
355 + memset(&princ_ent, 0, sizeof(princ_ent)); |
|
356 |
|
357 ret = krb5_copy_principal(context, princ, &entry->princ); |
|
358 if (ret) |
|
359 @@ -1462,8 +1482,21 @@ populate_krb5_db_entry(krb5_context cont |
|
360 ret = krb5_ldap_policydn_to_name(context, pwdpolicydn, &polname); |
|
361 if (ret) |
|
362 goto cleanup; |
|
363 + princ_ent.policy = polname; |
|
364 + princ_ent.aux_attributes |= KADM5_POLICY; |
|
365 + } |
|
366 + |
|
367 + ber_key_data = ldap_get_values_len(ld, ent, "krbpwdhistory"); |
|
368 + if (ber_key_data != NULL) { |
|
369 + mask |= KDB_PWD_HISTORY_ATTR; |
|
370 + ret = krb5_decode_histkey(context, ber_key_data, &princ_ent); |
|
371 + if (ret) |
|
372 + goto cleanup; |
|
373 + ldap_value_free_len(ber_key_data); |
|
374 + } |
|
375 |
|
376 - ret = krb5_update_tl_kadm_data(context, entry, polname); |
|
377 + if (princ_ent.aux_attributes) { |
|
378 + ret = krb5_update_tl_kadm_data(context, entry, &princ_ent); |
|
379 if (ret) |
|
380 goto cleanup; |
|
381 } |
|
382 @@ -1471,8 +1504,7 @@ populate_krb5_db_entry(krb5_context cont |
|
383 ber_key_data = ldap_get_values_len(ld, ent, "krbprincipalkey"); |
|
384 if (ber_key_data != NULL) { |
|
385 mask |= KDB_SECRET_KEY_ATTR; |
|
386 - ret = krb5_decode_krbsecretkey(context, entry, ber_key_data, |
|
387 - &userinfo_tl_data, &mkvno); |
|
388 + ret = krb5_decode_krbsecretkey(context, entry, ber_key_data, &mkvno); |
|
389 if (ret) |
|
390 goto cleanup; |
|
391 if (mkvno != 0) { |
|
392 @@ -1578,6 +1610,7 @@ cleanup: |
|
393 free(tktpolname); |
|
394 free(policydn); |
|
395 krb5_free_unparsed_name(context, user); |
|
396 + free_princ_ent_contents(&princ_ent); |
|
397 return ret; |
|
398 } |
|
399 |
|
400 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c |
|
401 +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c |
|
402 @@ -59,6 +59,7 @@ char *principal_attributes[] = { "kr |
|
403 "krbExtraData", |
|
404 "krbObjectReferences", |
|
405 "krbAllowedToDelegateTo", |
|
406 + "krbPwdHistory", |
|
407 NULL }; |
|
408 |
|
409 /* Must match KDB_*_ATTR macros in ldap_principal.h. */ |
|
410 @@ -77,14 +78,38 @@ static char *attributes_set[] = { "krbma |
|
411 "krbLastFailedAuth", |
|
412 "krbLoginFailedCount", |
|
413 "krbLastAdminUnlock", |
|
414 + "krbPwdHistory", |
|
415 NULL }; |
|
416 |
|
417 + |
|
418 +static void |
|
419 +k5_free_key_data_contents(krb5_key_data *key) |
|
420 +{ |
|
421 + int16_t i; |
|
422 + |
|
423 + for (i = 0; i < key->key_data_ver; i++) { |
|
424 + zapfree(key->key_data_contents[i], key->key_data_length[i]); |
|
425 + key->key_data_contents[i] = NULL; |
|
426 + } |
|
427 +} |
|
428 + |
|
429 +void |
|
430 +k5_free_key_data(krb5_int16 n_key_data, krb5_key_data *key_data) |
|
431 +{ |
|
432 + int16_t i; |
|
433 + |
|
434 + if (key_data == NULL) |
|
435 + return; |
|
436 + for (i = 0; i < n_key_data; i++) |
|
437 + k5_free_key_data_contents(&key_data[i]); |
|
438 + free(key_data); |
|
439 +} |
|
440 + |
|
441 void |
|
442 krb5_dbe_free_contents(krb5_context context, krb5_db_entry *entry) |
|
443 { |
|
444 krb5_tl_data *tl_data_next=NULL; |
|
445 krb5_tl_data *tl_data=NULL; |
|
446 - int i, j; |
|
447 |
|
448 if (entry->e_data) |
|
449 free(entry->e_data); |
|
450 @@ -96,24 +121,7 @@ krb5_dbe_free_contents(krb5_context cont |
|
451 free(tl_data->tl_data_contents); |
|
452 free(tl_data); |
|
453 } |
|
454 - if (entry->key_data) { |
|
455 - for (i = 0; i < entry->n_key_data; i++) { |
|
456 - for (j = 0; j < entry->key_data[i].key_data_ver; j++) { |
|
457 - if (entry->key_data[i].key_data_length[j]) { |
|
458 - if (entry->key_data[i].key_data_contents[j]) { |
|
459 - memset(entry->key_data[i].key_data_contents[j], |
|
460 - 0, |
|
461 - (unsigned) entry->key_data[i].key_data_length[j]); |
|
462 - free (entry->key_data[i].key_data_contents[j]); |
|
463 - } |
|
464 - } |
|
465 - entry->key_data[i].key_data_contents[j] = NULL; |
|
466 - entry->key_data[i].key_data_length[j] = 0; |
|
467 - entry->key_data[i].key_data_type[j] = 0; |
|
468 - } |
|
469 - } |
|
470 - free(entry->key_data); |
|
471 - } |
|
472 + k5_free_key_data(entry->n_key_data, entry->key_data); |
|
473 memset(entry, 0, sizeof(*entry)); |
|
474 return; |
|
475 } |
|
476 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.h |
|
477 +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.h |
|
478 @@ -32,6 +32,7 @@ |
|
479 #define _LDAP_PRINCIPAL_H 1 |
|
480 |
|
481 #include "ldap_tkt_policy.h" |
|
482 +#include "princ_xdr.h" |
|
483 |
|
484 #define KEYHEADER 12 |
|
485 |
|
486 @@ -82,6 +83,7 @@ |
|
487 #define KDB_LAST_FAILED_ATTR 0x001000 |
|
488 #define KDB_FAIL_AUTH_COUNT_ATTR 0x002000 |
|
489 #define KDB_LAST_ADMIN_UNLOCK_ATTR 0x004000 |
|
490 +#define KDB_PWD_HISTORY_ATTR 0x008000 |
|
491 |
|
492 /* |
|
493 * This is a private contract between krb5_ldap_lockout_audit() |
|
494 @@ -112,6 +114,12 @@ krb5_ldap_iterate(krb5_context, char *, |
|
495 krb5_pointer, krb5_flags); |
|
496 |
|
497 void |
|
498 +k5_free_key_data(krb5_int16 n_key_data, krb5_key_data *key_data); |
|
499 + |
|
500 +void |
|
501 +krb5_dbe_free_contents(krb5_context context, krb5_db_entry *entry); |
|
502 + |
|
503 +void |
|
504 krb5_dbe_free_contents(krb5_context, krb5_db_entry *); |
|
505 |
|
506 krb5_error_code |
|
507 @@ -121,8 +129,11 @@ krb5_error_code |
|
508 krb5_ldap_parse_principal_name(char *, char **); |
|
509 |
|
510 krb5_error_code |
|
511 +krb5_decode_histkey(krb5_context, struct berval **, osa_princ_ent_rec *); |
|
512 + |
|
513 +krb5_error_code |
|
514 krb5_decode_krbsecretkey(krb5_context, krb5_db_entry *, struct berval **, |
|
515 - krb5_tl_data *, krb5_kvno *); |
|
516 + krb5_kvno *); |
|
517 |
|
518 krb5_error_code |
|
519 berval2tl_data(struct berval *in, krb5_tl_data **out); |
|
520 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c |
|
521 +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c |
|
522 @@ -1,6 +1,35 @@ |
|
523 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
|
524 /* plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c */ |
|
525 /* |
|
526 + * Copyright (C) 2016 by the Massachusetts Institute of Technology. |
|
527 + * All rights reserved. |
|
528 + * |
|
529 + * Redistribution and use in source and binary forms, with or without |
|
530 + * modification, are permitted provided that the following conditions |
|
531 + * are met: |
|
532 + * |
|
533 + * * Redistributions of source code must retain the above copyright |
|
534 + * notice, this list of conditions and the following disclaimer. |
|
535 + * |
|
536 + * * Redistributions in binary form must reproduce the above copyright |
|
537 + * notice, this list of conditions and the following disclaimer in |
|
538 + * the documentation and/or other materials provided with the |
|
539 + * distribution. |
|
540 + * |
|
541 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
542 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
543 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
|
544 + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
545 + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
|
546 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
547 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
|
548 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
549 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
|
550 + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
551 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
|
552 + * OF THE POSSIBILITY OF SUCH DAMAGE. |
|
553 + */ |
|
554 +/* |
|
555 * Copyright (c) 2004-2005, Novell, Inc. |
|
556 * All rights reserved. |
|
557 * |
|
558 @@ -362,13 +391,14 @@ asn1_encode_sequence_of_keys(krb5_key_da |
|
559 } |
|
560 |
|
561 static krb5_error_code |
|
562 -asn1_decode_sequence_of_keys(krb5_data *in, krb5_key_data **out, |
|
563 - krb5_int16 *n_key_data, krb5_kvno *mkvno) |
|
564 +asn1_decode_sequence_of_keys(krb5_data *in, ldap_seqof_key_data *out) |
|
565 { |
|
566 krb5_error_code err; |
|
567 ldap_seqof_key_data *p; |
|
568 int i; |
|
569 |
|
570 + memset(out, 0, sizeof(*out)); |
|
571 + |
|
572 /* |
|
573 * This should be pushed back into other library initialization |
|
574 * code. |
|
575 @@ -390,9 +420,7 @@ asn1_decode_sequence_of_keys(krb5_data * |
|
576 p->key_data[i].key_data_ver = 2; |
|
577 } |
|
578 |
|
579 - *out = p->key_data; |
|
580 - *n_key_data = p->n_key_data; |
|
581 - *mkvno = p->mkvno; |
|
582 + *out = *p; |
|
583 free(p); |
|
584 return 0; |
|
585 } |
|
586 @@ -416,19 +444,24 @@ free_berdata(struct berval **array) |
|
587 } |
|
588 } |
|
589 |
|
590 -/* Decoding ASN.1 encoded key */ |
|
591 -static struct berval ** |
|
592 -krb5_encode_krbsecretkey(krb5_key_data *key_data_in, int n_key_data, |
|
593 - krb5_kvno mkvno) { |
|
594 - struct berval **ret = NULL; |
|
595 - int currkvno; |
|
596 - int num_versions = 1; |
|
597 - int i, j, last; |
|
598 +/* |
|
599 + * Encode krb5_key_data into a berval struct for insertion into LDAP. |
|
600 + */ |
|
601 +static krb5_error_code |
|
602 +encode_keys(krb5_key_data *key_data_in, int n_key_data, krb5_kvno mkvno, |
|
603 + struct berval **bval_out) |
|
604 +{ |
|
605 krb5_error_code err = 0; |
|
606 + int i; |
|
607 krb5_key_data *key_data = NULL; |
|
608 + struct berval *bval = NULL; |
|
609 + krb5_data *code; |
|
610 |
|
611 - if (n_key_data < 0) |
|
612 - return NULL; |
|
613 + *bval_out = NULL; |
|
614 + if (n_key_data <= 0) { |
|
615 + err = EINVAL; |
|
616 + goto cleanup; |
|
617 + } |
|
618 |
|
619 /* Make a shallow copy of the key data so we can alter it. */ |
|
620 key_data = k5calloc(n_key_data, sizeof(*key_data), &err); |
|
621 @@ -447,31 +480,68 @@ krb5_encode_krbsecretkey(krb5_key_data * |
|
622 } |
|
623 } |
|
624 |
|
625 + bval = k5alloc(sizeof(struct berval), &err); |
|
626 + if (bval == NULL) |
|
627 + goto cleanup; |
|
628 + |
|
629 + err = asn1_encode_sequence_of_keys(key_data, n_key_data, mkvno, &code); |
|
630 + if (err) |
|
631 + goto cleanup; |
|
632 + |
|
633 + /* Steal the data pointer from code for bval and discard code. */ |
|
634 + bval->bv_len = code->length; |
|
635 + bval->bv_val = code->data; |
|
636 + free(code); |
|
637 + |
|
638 + *bval_out = bval; |
|
639 + bval = NULL; |
|
640 + |
|
641 +cleanup: |
|
642 + free(key_data); |
|
643 + free(bval); |
|
644 + return err; |
|
645 +} |
|
646 + |
|
647 +/* Decoding ASN.1 encoded key */ |
|
648 +static struct berval ** |
|
649 +krb5_encode_krbsecretkey(krb5_key_data *key_data, int n_key_data, |
|
650 + krb5_kvno mkvno) |
|
651 +{ |
|
652 + struct berval **ret = NULL; |
|
653 + int currkvno; |
|
654 + int num_versions = 0; |
|
655 + int i, j, last; |
|
656 + krb5_error_code err = 0; |
|
657 + |
|
658 + if (n_key_data < 0) |
|
659 + return NULL; |
|
660 + |
|
661 /* Find the number of key versions */ |
|
662 - for (i = 0; i < n_key_data - 1; i++) |
|
663 - if (key_data[i].key_data_kvno != key_data[i + 1].key_data_kvno) |
|
664 - num_versions++; |
|
665 + if (n_key_data > 0) { |
|
666 + for (i = 0, num_versions = 1; i < n_key_data - 1; i++) { |
|
667 + if (key_data[i].key_data_kvno != key_data[i + 1].key_data_kvno) |
|
668 + num_versions++; |
|
669 + } |
|
670 + } |
|
671 |
|
672 - ret = (struct berval **) calloc (num_versions + 1, sizeof (struct berval *)); |
|
673 + ret = calloc(num_versions + 1, sizeof(struct berval *)); |
|
674 if (ret == NULL) { |
|
675 err = ENOMEM; |
|
676 goto cleanup; |
|
677 } |
|
678 - for (i = 0, last = 0, j = 0, currkvno = key_data[0].key_data_kvno; i < n_key_data; i++) { |
|
679 - krb5_data *code; |
|
680 + ret[num_versions] = NULL; |
|
681 + |
|
682 + /* n_key_data may be 0 if a principal is created without a key. */ |
|
683 + if (n_key_data == 0) |
|
684 + goto cleanup; |
|
685 + |
|
686 + currkvno = key_data[0].key_data_kvno; |
|
687 + for (i = 0, last = 0, j = 0; i < n_key_data; i++) { |
|
688 if (i == n_key_data - 1 || key_data[i + 1].key_data_kvno != currkvno) { |
|
689 - ret[j] = k5alloc(sizeof(struct berval), &err); |
|
690 - if (ret[j] == NULL) |
|
691 - goto cleanup; |
|
692 - err = asn1_encode_sequence_of_keys(key_data + last, |
|
693 - (krb5_int16)i - last + 1, |
|
694 - mkvno, &code); |
|
695 + err = encode_keys(key_data + last, (krb5_int16)i - last + 1, mkvno, |
|
696 + &ret[j]); |
|
697 if (err) |
|
698 goto cleanup; |
|
699 - /*CHECK_NULL(ret[j]); */ |
|
700 - ret[j]->bv_len = code->length; |
|
701 - ret[j]->bv_val = code->data; |
|
702 - free(code); |
|
703 j++; |
|
704 last = i + 1; |
|
705 |
|
706 @@ -479,11 +549,48 @@ krb5_encode_krbsecretkey(krb5_key_data * |
|
707 currkvno = key_data[i + 1].key_data_kvno; |
|
708 } |
|
709 } |
|
710 - ret[num_versions] = NULL; |
|
711 |
|
712 cleanup: |
|
713 + if (err != 0) { |
|
714 + free_berdata(ret); |
|
715 + ret = NULL; |
|
716 + } |
|
717 |
|
718 - free(key_data); |
|
719 + return ret; |
|
720 +} |
|
721 + |
|
722 +/* |
|
723 + * Encode a principal's key history for insertion into ldap. |
|
724 + */ |
|
725 +static struct berval ** |
|
726 +krb5_encode_histkey(osa_princ_ent_rec *princ_ent) |
|
727 +{ |
|
728 + unsigned int i; |
|
729 + krb5_error_code err = 0; |
|
730 + struct berval **ret = NULL; |
|
731 + |
|
732 + if (princ_ent->old_key_len <= 0) |
|
733 + return NULL; |
|
734 + |
|
735 + ret = k5calloc(princ_ent->old_key_len + 1, sizeof(struct berval *), &err); |
|
736 + if (ret == NULL) |
|
737 + goto cleanup; |
|
738 + |
|
739 + for (i = 0; i < princ_ent->old_key_len; i++) { |
|
740 + if (princ_ent->old_keys[i].n_key_data <= 0) { |
|
741 + err = EINVAL; |
|
742 + goto cleanup; |
|
743 + } |
|
744 + err = encode_keys(princ_ent->old_keys[i].key_data, |
|
745 + princ_ent->old_keys[i].n_key_data, |
|
746 + princ_ent->admin_history_kvno, &ret[i]); |
|
747 + if (err) |
|
748 + goto cleanup; |
|
749 + } |
|
750 + |
|
751 + ret[princ_ent->old_key_len] = NULL; |
|
752 + |
|
753 +cleanup: |
|
754 if (err != 0) { |
|
755 free_berdata(ret); |
|
756 ret = NULL; |
|
757 @@ -1004,7 +1111,7 @@ krb5_ldap_put_principal(krb5_context con |
|
758 free (strval[0]); |
|
759 } |
|
760 |
|
761 - if (entry->mask & KADM5_POLICY) { |
|
762 + if (entry->mask & KADM5_POLICY || entry->mask & KADM5_KEY_HIST) { |
|
763 memset(&princ_ent, 0, sizeof(princ_ent)); |
|
764 for (tl_data=entry->tl_data; tl_data; tl_data=tl_data->tl_data_next) { |
|
765 if (tl_data->tl_data_type == KRB5_TL_KADM_DATA) { |
|
766 @@ -1014,7 +1121,9 @@ krb5_ldap_put_principal(krb5_context con |
|
767 break; |
|
768 } |
|
769 } |
|
770 + } |
|
771 |
|
772 + if (entry->mask & KADM5_POLICY) { |
|
773 if (princ_ent.aux_attributes & KADM5_POLICY) { |
|
774 memset(strval, 0, sizeof(strval)); |
|
775 if ((st = krb5_ldap_name_to_policydn (context, princ_ent.policy, &polname)) != 0) |
|
776 @@ -1042,6 +1151,22 @@ krb5_ldap_put_principal(krb5_context con |
|
777 goto cleanup; |
|
778 } |
|
779 |
|
780 + if (entry->mask & KADM5_KEY_HIST) { |
|
781 + bersecretkey = krb5_encode_histkey(&princ_ent); |
|
782 + if (bersecretkey == NULL) { |
|
783 + st = ENOMEM; |
|
784 + goto cleanup; |
|
785 + } |
|
786 + |
|
787 + st = krb5_add_ber_mem_ldap_mod(&mods, "krbpwdhistory", |
|
788 + LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, |
|
789 + bersecretkey); |
|
790 + if (st != 0) |
|
791 + goto cleanup; |
|
792 + free_berdata(bersecretkey); |
|
793 + bersecretkey = NULL; |
|
794 + } |
|
795 + |
|
796 if (entry->mask & KADM5_KEY_DATA || entry->mask & KADM5_KVNO) { |
|
797 krb5_kvno mkvno; |
|
798 |
|
799 @@ -1376,22 +1501,62 @@ cleanup: |
|
800 return st; |
|
801 } |
|
802 |
|
803 -krb5_error_code |
|
804 -krb5_decode_krbsecretkey(krb5_context context, krb5_db_entry *entries, |
|
805 - struct berval **bvalues, |
|
806 - krb5_tl_data *userinfo_tl_data, krb5_kvno *mkvno) |
|
807 +static void |
|
808 +free_ldap_seqof_key_data(ldap_seqof_key_data *keysets, krb5_int16 n_keysets) |
|
809 { |
|
810 - char *user=NULL; |
|
811 - int i=0, j=0, noofkeys=0; |
|
812 - krb5_key_data *key_data=NULL, *tmp; |
|
813 - krb5_error_code st=0; |
|
814 + int i; |
|
815 |
|
816 - if ((st=krb5_unparse_name(context, entries->princ, &user)) != 0) |
|
817 + if (keysets == NULL) |
|
818 + return; |
|
819 + |
|
820 + for (i = 0; i < n_keysets; i++) |
|
821 + k5_free_key_data(keysets[i].n_key_data, keysets[i].key_data); |
|
822 + free(keysets); |
|
823 +} |
|
824 + |
|
825 +/* |
|
826 + * Decode keys from ldap search results. |
|
827 + * |
|
828 + * Arguments: |
|
829 + * - bvalues |
|
830 + * The ldap search results containing the key data. |
|
831 + * - mkvno |
|
832 + * The master kvno that the keys were encrypted with. |
|
833 + * - keysets_out |
|
834 + * The decoded keys in a ldap_seqof_key_data struct. Must be freed using |
|
835 + * free_ldap_seqof_key_data. |
|
836 + * - n_keysets_out |
|
837 + * The number of entries in keys_out. |
|
838 + * - total_keys_out |
|
839 + * An optional argument that if given will be set to the total number of |
|
840 + * keys found throughout all the entries: sum(keys_out.n_key_data) |
|
841 + * May be NULL. |
|
842 + */ |
|
843 +static krb5_error_code |
|
844 +decode_keys(struct berval **bvalues, ldap_seqof_key_data **keysets_out, |
|
845 + krb5_int16 *n_keysets_out, krb5_int16 *total_keys_out) |
|
846 +{ |
|
847 + krb5_error_code err = 0; |
|
848 + krb5_int16 n_keys, i, ki, total_keys; |
|
849 + ldap_seqof_key_data *keysets = NULL; |
|
850 + |
|
851 + *keysets_out = NULL; |
|
852 + *n_keysets_out = 0; |
|
853 + if (total_keys_out) |
|
854 + *total_keys_out = 0; |
|
855 + |
|
856 + /* Precount the number of keys. */ |
|
857 + for (n_keys = 0, i = 0; bvalues[i] != NULL; i++) { |
|
858 + if (bvalues[i]->bv_len > 0) |
|
859 + n_keys++; |
|
860 + } |
|
861 + |
|
862 + keysets = k5calloc(n_keys, sizeof(ldap_seqof_key_data), &err); |
|
863 + if (keysets == NULL) |
|
864 goto cleanup; |
|
865 + memset(keysets, 0, n_keys * sizeof(ldap_seqof_key_data)); |
|
866 |
|
867 - for (i=0; bvalues[i] != NULL; ++i) { |
|
868 - krb5_int16 n_kd; |
|
869 - krb5_key_data *kd; |
|
870 + for (i = 0, ki = 0, total_keys = 0; bvalues[i] != NULL; i++) { |
|
871 krb5_data in; |
|
872 |
|
873 if (bvalues[i]->bv_len == 0) |
|
874 @@ -1399,39 +1564,131 @@ krb5_decode_krbsecretkey(krb5_context co |
|
875 in.length = bvalues[i]->bv_len; |
|
876 in.data = bvalues[i]->bv_val; |
|
877 |
|
878 - st = asn1_decode_sequence_of_keys (&in, |
|
879 - &kd, |
|
880 - &n_kd, |
|
881 - mkvno); |
|
882 - |
|
883 - if (st != 0) { |
|
884 - const char *msg = error_message(st); |
|
885 - st = -1; /* Something more appropriate ? */ |
|
886 - k5_setmsg(context, st, |
|
887 - _("unable to decode stored principal key data (%s)"), |
|
888 - msg); |
|
889 - goto cleanup; |
|
890 - } |
|
891 - noofkeys += n_kd; |
|
892 - tmp = key_data; |
|
893 - /* Allocate an extra key data to avoid allocating zero bytes. */ |
|
894 - key_data = realloc(key_data, (noofkeys + 1) * sizeof (krb5_key_data)); |
|
895 - if (key_data == NULL) { |
|
896 - key_data = tmp; |
|
897 - st = ENOMEM; |
|
898 + err = asn1_decode_sequence_of_keys(&in, &keysets[ki]); |
|
899 + if (err) |
|
900 goto cleanup; |
|
901 - } |
|
902 - for (j = 0; j < n_kd; j++) |
|
903 - key_data[noofkeys - n_kd + j] = kd[j]; |
|
904 - free (kd); |
|
905 + |
|
906 + if (total_keys_out) |
|
907 + total_keys += keysets[ki].n_key_data; |
|
908 + ki++; |
|
909 + } |
|
910 + |
|
911 + if (total_keys_out) |
|
912 + *total_keys_out = total_keys; |
|
913 + |
|
914 + *n_keysets_out = n_keys; |
|
915 + *keysets_out = keysets; |
|
916 + keysets = NULL; |
|
917 + n_keys = 0; |
|
918 + |
|
919 +cleanup: |
|
920 + free_ldap_seqof_key_data(keysets, n_keys); |
|
921 + return err; |
|
922 +} |
|
923 + |
|
924 +krb5_error_code |
|
925 +krb5_decode_krbsecretkey(krb5_context context, krb5_db_entry *entries, |
|
926 + struct berval **bvalues, krb5_kvno *mkvno) |
|
927 +{ |
|
928 + krb5_key_data *key_data = NULL, *tmp; |
|
929 + krb5_error_code err = 0; |
|
930 + ldap_seqof_key_data *keysets = NULL; |
|
931 + krb5_int16 i, n_keysets = 0, total_keys = 0; |
|
932 + |
|
933 + err = decode_keys(bvalues, &keysets, &n_keysets, &total_keys); |
|
934 + if (err != 0) { |
|
935 + k5_prependmsg(context, err, |
|
936 + _("unable to decode stored principal key data")); |
|
937 + goto cleanup; |
|
938 } |
|
939 |
|
940 - entries->n_key_data = noofkeys; |
|
941 + key_data = k5calloc(total_keys, sizeof(krb5_key_data), &err); |
|
942 + if (key_data == NULL) |
|
943 + goto cleanup; |
|
944 + memset(key_data, 0, total_keys * sizeof(krb5_key_data)); |
|
945 + |
|
946 + if (n_keysets > 0) |
|
947 + *mkvno = keysets[0].mkvno; |
|
948 + |
|
949 + /* Transfer key data values from keysets to a flat list in entries. */ |
|
950 + tmp = key_data; |
|
951 + for (i = 0; i < n_keysets; i++) { |
|
952 + memcpy(tmp, keysets[i].key_data, |
|
953 + sizeof(krb5_key_data) * keysets[i].n_key_data); |
|
954 + tmp += keysets[i].n_key_data; |
|
955 + keysets[i].n_key_data = 0; |
|
956 + } |
|
957 + entries->n_key_data = total_keys; |
|
958 entries->key_data = key_data; |
|
959 + key_data = NULL; |
|
960 |
|
961 cleanup: |
|
962 - free (user); |
|
963 - return st; |
|
964 + free_ldap_seqof_key_data(keysets, n_keysets); |
|
965 + k5_free_key_data(total_keys, key_data); |
|
966 + return err; |
|
967 +} |
|
968 + |
|
969 +static int |
|
970 +compare_osa_pw_hist_ent(const void *left_in, const void *right_in) |
|
971 +{ |
|
972 + int kvno_left, kvno_right; |
|
973 + osa_pw_hist_ent *left = (osa_pw_hist_ent *)left_in; |
|
974 + osa_pw_hist_ent *right = (osa_pw_hist_ent *)right_in; |
|
975 + |
|
976 + kvno_left = left->n_key_data ? left->key_data[0].key_data_kvno : 0; |
|
977 + kvno_right = right->n_key_data ? right->key_data[0].key_data_kvno : 0; |
|
978 + return kvno_left - kvno_right; |
|
979 +} |
|
980 + |
|
981 +/* |
|
982 + * Decode the key history entries from an LDAP search. |
|
983 + * |
|
984 + * NOTE: the caller must free princ_ent->old_keys even on error. |
|
985 + */ |
|
986 +krb5_error_code |
|
987 +krb5_decode_histkey(krb5_context context, struct berval **bvalues, |
|
988 + osa_princ_ent_rec *princ_ent) |
|
989 +{ |
|
990 + krb5_error_code err = 0; |
|
991 + krb5_int16 i, n_keysets = 0; |
|
992 + ldap_seqof_key_data *keysets = NULL; |
|
993 + |
|
994 + err = decode_keys(bvalues, &keysets, &n_keysets, NULL); |
|
995 + if (err != 0) { |
|
996 + k5_prependmsg(context, err, |
|
997 + _("unable to decode stored principal pw history")); |
|
998 + goto cleanup; |
|
999 + } |
|
1000 + |
|
1001 + princ_ent->old_keys = k5calloc(n_keysets, sizeof(osa_pw_hist_ent), &err); |
|
1002 + if (princ_ent->old_keys == NULL) |
|
1003 + goto cleanup; |
|
1004 + princ_ent->old_key_len = n_keysets; |
|
1005 + |
|
1006 + if (n_keysets > 0) |
|
1007 + princ_ent->admin_history_kvno = keysets[0].mkvno; |
|
1008 + |
|
1009 + /* Transfer key data pointers from keysets to princ_ent. */ |
|
1010 + for (i = 0; i < n_keysets; i++) { |
|
1011 + princ_ent->old_keys[i].n_key_data = keysets[i].n_key_data; |
|
1012 + princ_ent->old_keys[i].key_data = keysets[i].key_data; |
|
1013 + keysets[i].n_key_data = 0; |
|
1014 + keysets[i].key_data = NULL; |
|
1015 + } |
|
1016 + |
|
1017 + /* Sort the principal entries by kvno in ascending order. */ |
|
1018 + qsort(princ_ent->old_keys, princ_ent->old_key_len, sizeof(osa_pw_hist_ent), |
|
1019 + &compare_osa_pw_hist_ent); |
|
1020 + |
|
1021 + princ_ent->aux_attributes |= KADM5_KEY_HIST; |
|
1022 + |
|
1023 + /* Set the next key to the end of the list. The queue will be lengthened |
|
1024 + * if it isn't full yet; the first entry will be replaced if it is full. */ |
|
1025 + princ_ent->old_key_next = princ_ent->old_key_len; |
|
1026 + |
|
1027 +cleanup: |
|
1028 + free_ldap_seqof_key_data(keysets, n_keysets); |
|
1029 + return err; |
|
1030 } |
|
1031 |
|
1032 static char * |
|
1033 --- a/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.c |
|
1034 +++ b/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.c |
|
1035 @@ -204,20 +204,14 @@ krb5_lookup_tl_kadm_data(krb5_tl_data *t |
|
1036 |
|
1037 krb5_error_code |
|
1038 krb5_update_tl_kadm_data(krb5_context context, krb5_db_entry *entry, |
|
1039 - char *policy_dn) |
|
1040 + osa_princ_ent_rec *princ_entry) |
|
1041 { |
|
1042 XDR xdrs; |
|
1043 - osa_princ_ent_rec princ_entry; |
|
1044 krb5_tl_data tl_data; |
|
1045 krb5_error_code retval; |
|
1046 |
|
1047 - memset(&princ_entry, 0, sizeof(osa_princ_ent_rec)); |
|
1048 - princ_entry.admin_history_kvno = 2; |
|
1049 - princ_entry.aux_attributes = KADM5_POLICY; |
|
1050 - princ_entry.policy = policy_dn; |
|
1051 - |
|
1052 xdralloc_create(&xdrs, XDR_ENCODE); |
|
1053 - if (! ldap_xdr_osa_princ_ent_rec(&xdrs, &princ_entry)) { |
|
1054 + if (! ldap_xdr_osa_princ_ent_rec(&xdrs, princ_entry)) { |
|
1055 xdr_destroy(&xdrs); |
|
1056 return KADM5_XDR_FAILURE; |
|
1057 } |
|
1058 --- a/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.h |
|
1059 +++ b/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.h |
|
1060 @@ -57,6 +57,6 @@ krb5_lookup_tl_kadm_data(krb5_tl_data *t |
|
1061 |
|
1062 krb5_error_code |
|
1063 krb5_update_tl_kadm_data(krb5_context context, krb5_db_entry *entry, |
|
1064 - char *policy_dn); |
|
1065 + osa_princ_ent_rec *princ_entry); |
|
1066 |
|
1067 #endif |
|
1068 --- a/src/tests/kdbtest.c |
|
1069 +++ b/src/tests/kdbtest.c |
|
1070 @@ -97,7 +97,7 @@ static krb5_tl_data tl3 = { &tl4, KRB5_T |
|
1071 U("\x12\x34\x5C\x01\x00\x00\x00\x08" |
|
1072 "\x3C\x74\x65\x73\x74\x2A\x3E\x00" |
|
1073 "\x00\x00\x08\x00\x00\x00\x00\x00" |
|
1074 - "\x00\x00\x00\x02\x00\x00\x00\x00") }; |
|
1075 + "\x00\x00\x00\x00\x00\x00\x00\x00") }; |
|
1076 static krb5_tl_data tl2 = { &tl3, KRB5_TL_MOD_PRINC, 8, U("\5\6\7\0x@Y\0") }; |
|
1077 static krb5_tl_data tl1 = { &tl2, KRB5_TL_LAST_PWD_CHANGE, 4, U("\1\2\3\4") }; |
|
1078 |
|
1079 --- a/src/tests/t_kdb.py |
|
1080 +++ b/src/tests/t_kdb.py |
|
1081 @@ -337,6 +337,31 @@ realm.run([kadminl, 'modprinc', '+requir |
|
1082 realm.kinit('canon', password('canon')) |
|
1083 realm.kinit('alias', password('canon'), ['-C']) |
|
1084 |
|
1085 +# Test password history. |
|
1086 +def test_pwhist(nhist): |
|
1087 + def cpw(n, **kwargs): |
|
1088 + realm.run([kadminl, 'cpw', '-pw', str(n), princ], **kwargs) |
|
1089 + def cpw_fail(n): |
|
1090 + cpw(n, expected_code=1) |
|
1091 + output('*** Testing password history of size %d\n' % nhist) |
|
1092 + princ = 'pwhistprinc' + str(nhist) |
|
1093 + pol = 'pwhistpol' + str(nhist) |
|
1094 + realm.run([kadminl, 'addpol', '-history', str(nhist), pol]) |
|
1095 + realm.run([kadminl, 'addprinc', '-policy', pol, '-nokey', princ]) |
|
1096 + for i in range(nhist): |
|
1097 + # Set a password, then check that all previous passwords fail. |
|
1098 + cpw(i) |
|
1099 + for j in range(i + 1): |
|
1100 + cpw_fail(j) |
|
1101 + # Set one more new password, and make sure the oldest key is |
|
1102 + # rotated out. |
|
1103 + cpw(nhist) |
|
1104 + cpw_fail(1) |
|
1105 + cpw(0) |
|
1106 + |
|
1107 +for n in (1, 2, 3, 4, 5): |
|
1108 + test_pwhist(n) |
|
1109 + |
|
1110 # Regression test for #7980 (fencepost when dividing keys up by kvno). |
|
1111 realm.run([kadminl, 'addprinc', '-randkey', '-e', 'aes256-cts,aes128-cts', |
|
1112 'kvnoprinc']) |
|
1113 @@ -368,6 +393,13 @@ out = realm.run([kadminl, 'getprinc', 'k |
|
1114 if 'Number of keys: 0' not in out: |
|
1115 fail('After purgekeys -all, keys remain') |
|
1116 |
|
1117 +# Test for 8354 (old password history entries when -keepold is used) |
|
1118 +realm.run([kadminl, 'addpol', '-history', '2', 'keepoldpasspol']) |
|
1119 +realm.run([kadminl, 'addprinc', '-policy', 'keepoldpasspol', '-pw', 'aaaa', |
|
1120 + 'keepoldpassprinc']) |
|
1121 +for p in ('bbbb', 'cccc', 'aaaa'): |
|
1122 + realm.run([kadminl, 'cpw', '-keepold', '-pw', p, 'keepoldpassprinc']) |
|
1123 + |
|
1124 realm.stop() |
|
1125 |
|
1126 # Briefly test dump and load. |