1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * This file contains api's for conversion of the kdb_incr_update_t
8 * struct(s) into krb5_db_entry struct(s) and vice-versa.
9 */
10 #include <sys/types.h>
11 #include <com_err.h>
12 #include <locale.h>
13 #include <errno.h>
14 #include <iprop_hdr.h>
15 #include "iprop.h"
16 #include <k5-int.h>
17 #include <kdb.h>
18 #include <kdb_log.h>
19
20 /* BEGIN CSTYLED */
21 #define ULOG_ENTRY_TYPE(upd, i) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i]
22
23 #define ULOG_ENTRY(upd, i) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i].kdbe_val_t_u
24
25 #define ULOG_ENTRY_KEYVAL(upd, i, j) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i].kdbe_val_t_u.av_keydata.av_keydata_val[j]
26
27 #define ULOG_ENTRY_PRINC(upd, i, j) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i].kdbe_val_t_u.av_princ.k_components.k_components_val[j]
28
29 #define ULOG_ENTRY_MOD_PRINC(upd, i, j) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i].kdbe_val_t_u.av_mod_princ.k_components.k_components_val[j]
30 /* END CSTYLED */
31
32 typedef enum {
33 REG_PRINC = 0,
34 MOD_PRINC = 1
35 } princ_type;
36
37
38 /*
39 * This routine tracks the krb5_db_entry fields that have been modified
40 * (by comparing it to the db_entry currently present in principal.db)
41 * in the update.
42 */
43 static void
find_changed_attrs(krb5_db_entry * current,krb5_db_entry * new,kdbe_attr_type_t * attrs,int * nattrs)44 find_changed_attrs(krb5_db_entry *current, krb5_db_entry *new,
45 kdbe_attr_type_t *attrs, int *nattrs)
46 {
47 int i = 0, j = 0;
48
49 krb5_tl_data *first, *second;
50
51 if (current->attributes != new->attributes)
52 attrs[i++] = AT_ATTRFLAGS;
53
54 if (current->max_life != new->max_life)
55 attrs[i++] = AT_MAX_LIFE;
56
57 if (current->max_renewable_life != new->max_renewable_life)
58 attrs[i++] = AT_MAX_RENEW_LIFE;
59
60 if (current->expiration != new->expiration)
61 attrs[i++] = AT_EXP;
62
63 if (current->pw_expiration != new->pw_expiration)
64 attrs[i++] = AT_PW_EXP;
65
66 if (current->last_success != new->last_success)
67 attrs[i++] = AT_LAST_SUCCESS;
68
69 if (current->last_failed != new->last_failed)
70 attrs[i++] = AT_LAST_FAILED;
71
72 if (current->fail_auth_count != new->fail_auth_count)
73 attrs[i++] = AT_FAIL_AUTH_COUNT;
74
75 if ((current->princ->type == new->princ->type) &&
76 (current->princ->length == new->princ->length)) {
77 if ((current->princ->realm.length ==
78 new->princ->realm.length) &&
79 strncmp(current->princ->realm.data,
80 new->princ->realm.data,
81 current->princ->realm.length)) {
82 for (j = 0; j < current->princ->length; j++) {
83 if ((current->princ->data[j].data != NULL) &&
84 (strncmp(current->princ->data[j].data,
85 new->princ->data[j].data,
86 current->princ->data[j].length))) {
87 attrs[i++] = AT_PRINC;
88 break;
89 }
90 }
91 } else {
92 attrs[i++] = AT_PRINC;
93 }
94 } else {
95 attrs[i++] = AT_PRINC;
96 }
97
98 if (current->n_key_data == new->n_key_data) {
99 /* Assuming key ordering is the same in new & current */
100 for (j = 0; j < new->n_key_data; j++) {
101 if (current->key_data[j].key_data_kvno !=
102 new->key_data[j].key_data_kvno) {
103 attrs[i++] = AT_KEYDATA;
104 break;
105 }
106 }
107 } else {
108 attrs[i++] = AT_KEYDATA;
109 }
110
111 if (current->n_tl_data == new->n_tl_data) {
112 /* Assuming we preserve the TL_DATA ordering between updates */
113 for (first = current->tl_data, second = new->tl_data;
114 first; first = first->tl_data_next,
115 second = second->tl_data_next) {
116 if ((first->tl_data_length == second->tl_data_length) &&
117 (first->tl_data_type == second->tl_data_type)) {
118 if ((memcmp((char *)first->tl_data_contents,
119 (char *)second->tl_data_contents,
120 first->tl_data_length)) != 0) {
121 attrs[i++] = AT_TL_DATA;
122 break;
123 }
124 } else {
125 attrs[i++] = AT_TL_DATA;
126 break;
127 }
128 }
129
130 } else {
131 attrs[i++] = AT_TL_DATA;
132 }
133
134 if (current->len != new->len)
135 attrs[i++] = AT_LEN;
136 /*
137 * Store the no. of (possibly :)) changed attributes
138 */
139 *nattrs = i;
140 }
141
142 static int
data_to_utf8str(utf8str_t * u,krb5_data d)143 data_to_utf8str(utf8str_t *u, krb5_data d)
144 {
145 u->utf8str_t_len = d.length;
146 if (d.data) {
147 u->utf8str_t_val = malloc(d.length);
148 if (u->utf8str_t_val == NULL)
149 return -1;
150 memcpy(u->utf8str_t_val, d.data, d.length);
151 } else
152 u->utf8str_t_val = NULL;
153 return 0;
154 }
155
156 /*
157 * Converts the krb5_principal struct from db2 to ulog format.
158 */
159 static krb5_error_code
conv_princ_2ulog(krb5_principal princ,kdb_incr_update_t * upd,int cnt,princ_type tp)160 conv_princ_2ulog(krb5_principal princ, kdb_incr_update_t *upd,
161 int cnt, princ_type tp) {
162 int i = 0;
163 kdbe_princ_t *p;
164 kdbe_data_t *components;
165
166 if ((upd == NULL) || !princ)
167 return (KRB5KRB_ERR_GENERIC);
168
169 switch (tp) {
170 case REG_PRINC:
171 case MOD_PRINC:
172 p = &ULOG_ENTRY(upd, cnt).av_princ; /* or av_mod_princ */
173 p->k_nametype = (int32_t)princ->type;
174
175 if (data_to_utf8str(&p->k_realm, princ->realm) < 0) {
176 return ENOMEM;
177 }
178
179 p->k_components.k_components_len = princ->length;
180
181 p->k_components.k_components_val = components
182 = malloc(princ->length * sizeof (kdbe_data_t));
183 if (p->k_components.k_components_val == NULL) {
184 free(p->k_realm.utf8str_t_val);
185 p->k_realm.utf8str_t_val = NULL;
186 return (ENOMEM);
187 }
188
189 memset(components, 0, princ->length * sizeof(kdbe_data_t));
190 for (i = 0; i < princ->length; i++)
191 components[i].k_data.utf8str_t_val = NULL;
192 for (i = 0; i < princ->length; i++) {
193 components[i].k_magic = princ->data[i].magic;
194 if (data_to_utf8str(&components[i].k_data,
195 princ->data[i]) < 0) {
196 int j;
197 for (j = 0; j < i; j++) {
198 free(components[j].k_data.utf8str_t_val);
199 components[j].k_data.utf8str_t_val = NULL;
200 }
201 free(components);
202 p->k_components.k_components_val = NULL;
203 free(p->k_realm.utf8str_t_val);
204 p->k_realm.utf8str_t_val = NULL;
205 return ENOMEM;
206 }
207 }
208 break;
209
210 default:
211 break;
212 }
213 return (0);
214 }
215
216 /*
217 * Copies a UTF-8 string from ulog to a krb5_data object, which may
218 * already have allocated storage associated with it.
219 *
220 * Maybe a return value should indicate success/failure?
221 */
222 static void
set_from_utf8str(krb5_data * d,utf8str_t u)223 set_from_utf8str(krb5_data *d, utf8str_t u)
224 {
225 if (u.utf8str_t_len > INT_MAX-1 || u.utf8str_t_len >= SIZE_MAX-1) {
226 d->data = NULL;
227 return;
228 }
229 d->length = u.utf8str_t_len;
230 d->data = malloc(d->length + 1);
231 if (d->data == NULL)
232 return;
233 if (d->length) /* Pointer may be null if length = 0. */
234 strncpy(d->data, u.utf8str_t_val, d->length);
235 d->data[d->length] = 0;
236 }
237
238 /*
239 * Converts the krb5_principal struct from ulog to db2 format.
240 */
241 static krb5_principal
conv_princ_2db(krb5_context context,kdbe_princ_t * kdbe_princ)242 conv_princ_2db(krb5_context context, kdbe_princ_t *kdbe_princ)
243 {
244 int i;
245 krb5_principal princ;
246 kdbe_data_t *components;
247
248 princ = calloc(1, sizeof (krb5_principal_data));
249 if (princ == NULL) {
250 return NULL;
251 }
252 princ->length = 0;
253 princ->data = NULL;
254
255 components = kdbe_princ->k_components.k_components_val;
256
257 princ->type = (krb5_int32) kdbe_princ->k_nametype;
258 princ->realm.data = NULL;
259 set_from_utf8str(&princ->realm, kdbe_princ->k_realm);
260 if (princ->realm.data == NULL)
261 goto error;
262
263 princ->data = calloc(kdbe_princ->k_components.k_components_len,
264 sizeof (krb5_data));
265 if (princ->data == NULL)
266 goto error;
267 for (i = 0; i < kdbe_princ->k_components.k_components_len; i++)
268 princ->data[i].data = NULL;
269 princ->length = (krb5_int32)kdbe_princ->k_components.k_components_len;
270
271 for (i = 0; i < princ->length; i++) {
272 princ->data[i].magic = components[i].k_magic;
273 set_from_utf8str(&princ->data[i], components[i].k_data);
274 if (princ->data[i].data == NULL)
275 goto error;
276 }
277
278 return princ;
279 error:
280 krb5_free_principal(context, princ);
281 return NULL;
282 }
283
284 /*
285 * This routine converts one or more krb5 db2 records into update
286 * log (ulog) entry format. Space for the update log entries should
287 * be allocated prior to invocation of this routine.
288 */
289 krb5_error_code
ulog_conv_2logentry(krb5_context context,krb5_db_entry * entries,kdb_incr_update_t * updates,int nentries)290 ulog_conv_2logentry(krb5_context context, krb5_db_entry *entries,
291 kdb_incr_update_t *updates,
292 int nentries)
293 {
294 int i, j, k, cnt, final, nattrs, tmpint, nprincs;
295 unsigned int more;
296 krb5_principal tmpprinc;
297 krb5_tl_data *newtl;
298 krb5_db_entry curr;
299 krb5_error_code ret;
300 kdbe_attr_type_t *attr_types;
301 kdb_incr_update_t *upd;
302 krb5_db_entry *ent;
303 int kadm_data_yes;
304
305 if ((updates == NULL) || (entries == NULL))
306 return (KRB5KRB_ERR_GENERIC);
307
308 upd = updates;
309 ent = entries;
310
311 for (k = 0; k < nentries; k++) {
312 nprincs = nattrs = tmpint = 0;
313 final = -1;
314 kadm_data_yes = 0;
315 attr_types = NULL;
316
317 if ((upd->kdb_update.kdbe_t_val = (kdbe_val_t *)
318 malloc(MAXENTRY_SIZE)) == NULL) {
319 return (ENOMEM);
320 }
321
322 /*
323 * Find out which attrs have been modified
324 */
325 if ((attr_types = (kdbe_attr_type_t *)malloc(
326 sizeof (kdbe_attr_type_t) * MAXATTRS_SIZE))
327 == NULL) {
328 return (ENOMEM);
329 }
330
331 if ((ret = krb5_db_get_principal_nolock(context, ent->princ, &curr,
332 &nprincs, &more))) {
333 free(attr_types);
334 return (ret);
335 }
336
337 if (nprincs == 0) {
338 /*
339 * This is a new entry to the database, hence will
340 * include all the attribute-value pairs
341 *
342 * We leave out the TL_DATA types which we model as
343 * attrs in kdbe_attr_type_t, since listing AT_TL_DATA
344 * encompasses these other types-turned-attributes
345 *
346 * So, we do *NOT* consider AT_MOD_PRINC, AT_MOD_TIME,
347 * AT_MOD_WHERE, AT_PW_LAST_CHANGE, AT_PW_POLICY,
348 * AT_PW_POLICY_SWITCH, AT_PW_HIST_KVNO and AT_PW_HIST,
349 * totalling 8 attrs.
350 */
351 while (nattrs < MAXATTRS_SIZE - 8) {
352 attr_types[nattrs] = nattrs;
353 nattrs++;
354 }
355 } else {
356 find_changed_attrs(&curr, ent, attr_types, &nattrs);
357
358 krb5_db_free_principal(context, &curr, nprincs);
359 }
360
361 for (i = 0; i < nattrs; i++) {
362 switch (attr_types[i]) {
363 case AT_ATTRFLAGS:
364 if (ent->attributes >= 0) {
365 ULOG_ENTRY_TYPE(upd, ++final).av_type =
366 AT_ATTRFLAGS;
367 ULOG_ENTRY(upd, final).av_attrflags =
368 (uint32_t)ent->attributes;
369 }
370 break;
371
372 case AT_MAX_LIFE:
373 if (ent->max_life >= 0) {
374 ULOG_ENTRY_TYPE(upd, ++final).av_type =
375 AT_MAX_LIFE;
376 ULOG_ENTRY(upd, final).av_max_life =
377 (uint32_t)ent->max_life;
378 }
379 break;
380
381 case AT_MAX_RENEW_LIFE:
382 if (ent->max_renewable_life >= 0) {
383 ULOG_ENTRY_TYPE(upd, ++final).av_type =
384 AT_MAX_RENEW_LIFE;
385 ULOG_ENTRY(upd,
386 final).av_max_renew_life =
387 (uint32_t)ent->max_renewable_life;
388 }
389 break;
390
391 case AT_EXP:
392 if (ent->expiration >= 0) {
393 ULOG_ENTRY_TYPE(upd, ++final).av_type =
394 AT_EXP;
395 ULOG_ENTRY(upd, final).av_exp =
396 (uint32_t)ent->expiration;
397 }
398 break;
399
400 case AT_PW_EXP:
401 if (ent->pw_expiration >= 0) {
402 ULOG_ENTRY_TYPE(upd, ++final).av_type =
403 AT_PW_EXP;
404 ULOG_ENTRY(upd, final).av_pw_exp =
405 (uint32_t)ent->pw_expiration;
406 }
407 break;
408
409 case AT_LAST_SUCCESS:
410 if (ent->last_success >= 0) {
411 ULOG_ENTRY_TYPE(upd, ++final).av_type =
412 AT_LAST_SUCCESS;
413 ULOG_ENTRY(upd,
414 final).av_last_success =
415 (uint32_t)ent->last_success;
416 }
417 break;
418
419 case AT_LAST_FAILED:
420 if (ent->last_failed >= 0) {
421 ULOG_ENTRY_TYPE(upd, ++final).av_type =
422 AT_LAST_FAILED;
423 ULOG_ENTRY(upd,
424 final).av_last_failed =
425 (uint32_t)ent->last_failed;
426 }
427 break;
428
429 case AT_FAIL_AUTH_COUNT:
430 if (ent->fail_auth_count >= (krb5_kvno)0) {
431 ULOG_ENTRY_TYPE(upd, ++final).av_type =
432 AT_FAIL_AUTH_COUNT;
433 ULOG_ENTRY(upd,
434 final).av_fail_auth_count =
435 (uint32_t)ent->fail_auth_count;
436 }
437 break;
438
439 case AT_PRINC:
440 if (ent->princ->length > 0) {
441 ULOG_ENTRY_TYPE(upd, ++final).av_type =
442 AT_PRINC;
443 if ((ret = conv_princ_2ulog(ent->princ,
444 upd, final, REG_PRINC))) {
445 free(attr_types);
446 return (ret);
447 }
448 }
449 break;
450
451 case AT_KEYDATA:
452 /* BEGIN CSTYLED */
453 if (ent->n_key_data >= 0) {
454 ULOG_ENTRY_TYPE(upd, ++final).av_type =
455 AT_KEYDATA;
456 ULOG_ENTRY(upd, final).av_keydata.av_keydata_len = ent->n_key_data;
457
458 ULOG_ENTRY(upd, final).av_keydata.av_keydata_val = malloc(ent->n_key_data * sizeof (kdbe_key_t));
459 if (ULOG_ENTRY(upd, final).av_keydata.av_keydata_val == NULL) {
460 free(attr_types);
461 return (ENOMEM);
462 }
463
464 for (j = 0; j < ent->n_key_data; j++) {
465 ULOG_ENTRY_KEYVAL(upd, final, j).k_ver = ent->key_data[j].key_data_ver;
466 ULOG_ENTRY_KEYVAL(upd, final, j).k_kvno = ent->key_data[j].key_data_kvno;
467 ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_len = ent->key_data[j].key_data_ver;
468 ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_len = ent->key_data[j].key_data_ver;
469
470 ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_val = malloc(ent->key_data[j].key_data_ver * sizeof(int32_t));
471 if (ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_val == NULL) {
472 free(attr_types);
473 return (ENOMEM);
474 }
475
476 ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val = malloc(ent->key_data[j].key_data_ver * sizeof(utf8str_t));
477 if (ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val == NULL) {
478 free(attr_types);
479 return (ENOMEM);
480 }
481
482 for (cnt = 0; cnt < ent->key_data[j].key_data_ver; cnt++) {
483 ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_val[cnt] = ent->key_data[j].key_data_type[cnt];
484 ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_len = ent->key_data[j].key_data_length[cnt];
485 ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_val = malloc(ent->key_data[j].key_data_length[cnt] * sizeof (char));
486 if (ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_val == NULL) {
487 free(attr_types);
488 return (ENOMEM);
489 }
490 (void) memcpy(ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_val, ent->key_data[j].key_data_contents[cnt], ent->key_data[j].key_data_length[cnt]);
491 }
492 }
493 }
494 break;
495
496 case AT_TL_DATA:
497 ret = krb5_dbe_lookup_last_pwd_change(context,
498 ent, &tmpint);
499 if (ret == 0) {
500 ULOG_ENTRY_TYPE(upd, ++final).av_type =
501 AT_PW_LAST_CHANGE;
502 ULOG_ENTRY(upd, final).av_pw_last_change = tmpint;
503 }
504 tmpint = 0;
505
506 if(!(ret = krb5_dbe_lookup_mod_princ_data(
507 context, ent, &tmpint, &tmpprinc))) {
508
509 ULOG_ENTRY_TYPE(upd, ++final).av_type =
510 AT_MOD_PRINC;
511
512 ret = conv_princ_2ulog(tmpprinc,
513 upd, final, MOD_PRINC);
514 krb5_free_principal(context, tmpprinc);
515 if (ret) {
516 free(attr_types);
517 return (ret);
518 }
519 ULOG_ENTRY_TYPE(upd, ++final).av_type =
520 AT_MOD_TIME;
521 ULOG_ENTRY(upd, final).av_mod_time =
522 tmpint;
523 }
524
525 newtl = ent->tl_data;
526 while (newtl) {
527 switch (newtl->tl_data_type) {
528 case KRB5_TL_LAST_PWD_CHANGE:
529 case KRB5_TL_MOD_PRINC:
530 break;
531
532 case KRB5_TL_KADM_DATA:
533 default:
534 if (kadm_data_yes == 0) {
535 ULOG_ENTRY_TYPE(upd, ++final).av_type = AT_TL_DATA;
536 ULOG_ENTRY(upd, final).av_tldata.av_tldata_len = 0;
537 ULOG_ENTRY(upd, final).av_tldata.av_tldata_val = malloc(ent->n_tl_data * sizeof(kdbe_tl_t));
538
539 if (ULOG_ENTRY(upd, final).av_tldata.av_tldata_val == NULL) {
540 free(attr_types);
541 return (ENOMEM);
542 }
543 kadm_data_yes = 1;
544 }
545
546 tmpint = ULOG_ENTRY(upd, final).av_tldata.av_tldata_len;
547 ULOG_ENTRY(upd, final).av_tldata.av_tldata_len++;
548 ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_type = newtl->tl_data_type;
549 ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_len = newtl->tl_data_length;
550 ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val = malloc(newtl->tl_data_length * sizeof (char));
551 if (ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val == NULL) {
552 free(attr_types);
553 return (ENOMEM);
554 }
555 (void) memcpy(ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val, newtl->tl_data_contents, newtl->tl_data_length);
556 break;
557 }
558 newtl = newtl->tl_data_next;
559 }
560 break;
561 /* END CSTYLED */
562
563 case AT_LEN:
564 ULOG_ENTRY_TYPE(upd, ++final).av_type =
565 AT_LEN;
566 ULOG_ENTRY(upd, final).av_len =
567 (int16_t)ent->len;
568 break;
569
570 default:
571 break;
572 }
573
574 }
575
576 if (attr_types)
577 free(attr_types);
578
579 /*
580 * Update len field in kdb_update
581 */
582 upd->kdb_update.kdbe_t_len = ++final;
583
584 /*
585 * Bump up to next struct
586 */
587 upd++;
588 ent++;
589 }
590 return (0);
591 }
592
593 /*
594 * This routine converts one or more update log (ulog) entries into
595 * kerberos db2 records. Required memory should be allocated
596 * for the db2 records (pointed to by krb5_db_entry *ent), prior
597 * to calling this routine.
598 */
599 krb5_error_code
ulog_conv_2dbentry(krb5_context context,krb5_db_entry * entries,kdb_incr_update_t * updates,int nentries)600 ulog_conv_2dbentry(krb5_context context, krb5_db_entry *entries,
601 kdb_incr_update_t *updates,
602 int nentries)
603 {
604 int k;
605 krb5_db_entry *ent;
606 kdb_incr_update_t *upd;
607
608 if ((updates == NULL) || (entries == NULL))
609 return (KRB5KRB_ERR_GENERIC);
610
611 ent = entries;
612 upd = updates;
613
614 for (k = 0; k < nentries; k++) {
615 krb5_principal mod_princ = NULL;
616 int i, j, cnt = 0, mod_time = 0, nattrs, nprincs = 0;
617 krb5_principal dbprinc;
618 char *dbprincstr = NULL;
619
620 krb5_tl_data *newtl = NULL;
621 krb5_error_code ret;
622 unsigned int more;
623 unsigned int prev_n_keys = 0;
624
625 /*
626 * If the ulog entry represents a DELETE update,
627 * just skip to the next entry.
628 */
629 if (upd->kdb_deleted == TRUE)
630 goto next;
631
632 /*
633 * Store the no. of changed attributes in nattrs
634 */
635 nattrs = upd->kdb_update.kdbe_t_len;
636
637 dbprincstr = malloc((upd->kdb_princ_name.utf8str_t_len + 1)
638 * sizeof (char));
639 if (dbprincstr == NULL)
640 return (ENOMEM);
641 strncpy(dbprincstr, (char *)upd->kdb_princ_name.utf8str_t_val,
642 upd->kdb_princ_name.utf8str_t_len);
643 dbprincstr[upd->kdb_princ_name.utf8str_t_len] = 0;
644 ret = krb5_parse_name(context, dbprincstr, &dbprinc);
645 free(dbprincstr);
646 if (ret)
647 return (ret);
648
649 ret = krb5_db_get_principal(context, dbprinc, ent, &nprincs,
650 &more);
651 krb5_free_principal(context, dbprinc);
652 if (ret)
653 return (ret);
654
655 /*
656 * Set ent->n_tl_data = 0 initially, if this is an ADD update
657 */
658 if (nprincs == 0)
659 ent->n_tl_data = 0;
660
661 for (i = 0; i < nattrs; i++) {
662 krb5_principal tmpprinc = NULL;
663
664 #define u (ULOG_ENTRY(upd, i))
665 switch (ULOG_ENTRY_TYPE(upd, i).av_type) {
666 case AT_ATTRFLAGS:
667 ent->attributes = (krb5_flags) u.av_attrflags;
668 break;
669
670 case AT_MAX_LIFE:
671 ent->max_life = (krb5_deltat) u.av_max_life;
672 break;
673
674 case AT_MAX_RENEW_LIFE:
675 ent->max_renewable_life = (krb5_deltat) u.av_max_renew_life;
676 break;
677
678 case AT_EXP:
679 ent->expiration = (krb5_timestamp) u.av_exp;
680 break;
681
682 case AT_PW_EXP:
683 ent->pw_expiration = (krb5_timestamp) u.av_pw_exp;
684 break;
685
686 case AT_LAST_SUCCESS:
687 ent->last_success = (krb5_timestamp) u.av_last_success;
688 break;
689
690 case AT_LAST_FAILED:
691 ent->last_failed = (krb5_timestamp) u.av_last_failed;
692 break;
693
694 case AT_FAIL_AUTH_COUNT:
695 ent->fail_auth_count = (krb5_kvno) u.av_fail_auth_count;
696 break;
697
698 case AT_PRINC:
699 tmpprinc = conv_princ_2db(context, &u.av_princ);
700 if (tmpprinc == NULL)
701 return ENOMEM;
702 if (nprincs)
703 krb5_free_principal(context, ent->princ);
704 ent->princ = tmpprinc;
705 break;
706
707 case AT_KEYDATA:
708
709 if (nprincs != 0)
710 prev_n_keys = ent->n_key_data;
711 else
712 prev_n_keys = 0;
713 ent->n_key_data = (krb5_int16)u.av_keydata.av_keydata_len;
714 if (nprincs == 0)
715 ent->key_data = NULL;
716
717 ent->key_data = (krb5_key_data *)realloc(ent->key_data,
718 (ent->n_key_data *
719 sizeof (krb5_key_data)));
720 /* XXX Memory leak: Old key data in
721 records eliminated by resizing to
722 smaller size. */
723 if (ent->key_data == NULL)
724 /* XXX Memory leak: old storage. */
725 return (ENOMEM);
726
727 /* BEGIN CSTYLED */
728 for (j = prev_n_keys; j < ent->n_key_data; j++) {
729 for (cnt = 0; cnt < 2; cnt++) {
730 ent->key_data[j].key_data_contents[cnt] = NULL;
731 }
732 }
733 for (j = 0; j < ent->n_key_data; j++) {
734 krb5_key_data *kp = &ent->key_data[j];
735 kdbe_key_t *kv = &ULOG_ENTRY_KEYVAL(upd, i, j);
736 kp->key_data_ver = (krb5_int16)kv->k_ver;
737 kp->key_data_kvno = (krb5_int16)kv->k_kvno;
738 if (kp->key_data_ver > 2) {
739 return EINVAL; /* XXX ? */
740 }
741
742 for (cnt = 0; cnt < kp->key_data_ver; cnt++) {
743 void *newptr;
744 kp->key_data_type[cnt] = (krb5_int16)kv->k_enctype.k_enctype_val[cnt];
745 kp->key_data_length[cnt] = (krb5_int16)kv->k_contents.k_contents_val[cnt].utf8str_t_len;
746 newptr = realloc(kp->key_data_contents[cnt],
747 kp->key_data_length[cnt]);
748 if (newptr == NULL)
749 return ENOMEM;
750 kp->key_data_contents[cnt] = newptr;
751
752 (void) memset(kp->key_data_contents[cnt], 0,
753 kp->key_data_length[cnt]);
754 (void) memcpy(kp->key_data_contents[cnt],
755 kv->k_contents.k_contents_val[cnt].utf8str_t_val,
756 kp->key_data_length[cnt]);
757 }
758 }
759 break;
760
761 case AT_TL_DATA:
762 cnt = u.av_tldata.av_tldata_len;
763 newtl = malloc(cnt * sizeof (krb5_tl_data));
764 (void) memset(newtl, 0, (cnt * sizeof (krb5_tl_data)));
765 if (newtl == NULL)
766 return (ENOMEM);
767
768 for (j = 0; j < cnt; j++) {
769 newtl[j].tl_data_type = (krb5_int16)u.av_tldata.av_tldata_val[j].tl_type;
770 newtl[j].tl_data_length = (krb5_int16)u.av_tldata.av_tldata_val[j].tl_data.tl_data_len;
771 newtl[j].tl_data_contents = NULL;
772 newtl[j].tl_data_contents = malloc(newtl[j].tl_data_length * sizeof (krb5_octet));
773 if (newtl[j].tl_data_contents == NULL)
774 /* XXX Memory leak: newtl
775 and previously
776 allocated elements. */
777 return (ENOMEM);
778
779 (void) memset(newtl[j].tl_data_contents, 0, (newtl[j].tl_data_length * sizeof (krb5_octet)));
780 (void) memcpy(newtl[j].tl_data_contents, u.av_tldata.av_tldata_val[j].tl_data.tl_data_val, newtl[j].tl_data_length);
781 newtl[j].tl_data_next = NULL;
782 if (j > 0)
783 newtl[j - 1].tl_data_next = &newtl[j];
784 }
785
786 if ((ret = krb5_dbe_update_tl_data(context, ent, newtl)))
787 return (ret);
788 for (j = 0; j < cnt; j++)
789 if (newtl[j].tl_data_contents) {
790 free(newtl[j].tl_data_contents);
791 newtl[j].tl_data_contents = NULL;
792 }
793 if (newtl) {
794 free(newtl);
795 newtl = NULL;
796 }
797 break;
798 /* END CSTYLED */
799
800 case AT_PW_LAST_CHANGE:
801 if ((ret = krb5_dbe_update_last_pwd_change(context, ent,
802 u.av_pw_last_change)))
803 return (ret);
804 break;
805
806 case AT_MOD_PRINC:
807 tmpprinc = conv_princ_2db(context, &u.av_mod_princ);
808 if (tmpprinc == NULL)
809 return ENOMEM;
810 mod_princ = tmpprinc;
811 break;
812
813 case AT_MOD_TIME:
814 mod_time = u.av_mod_time;
815 break;
816
817 case AT_LEN:
818 ent->len = (krb5_int16) u.av_len;
819 break;
820
821 default:
822 break;
823 }
824 #undef u
825 }
826
827 /*
828 * process mod_princ_data request
829 */
830 if (mod_time && mod_princ) {
831 ret = krb5_dbe_update_mod_princ_data(context, ent,
832 mod_time, mod_princ);
833 krb5_free_principal(context, mod_princ);
834 mod_princ = NULL;
835 if (ret)
836 return (ret);
837 }
838
839 next:
840 /*
841 * Bump up to next struct
842 */
843 upd++;
844 ent++;
845 }
846 return (0);
847 }
848
849
850
851 /*
852 * This routine frees up memory associated with the bunched ulog entries.
853 */
854 void
ulog_free_entries(kdb_incr_update_t * updates,int no_of_updates)855 ulog_free_entries(kdb_incr_update_t *updates, int no_of_updates)
856 {
857
858 kdb_incr_update_t *upd;
859 int i, j, k, cnt;
860
861 if (updates == NULL)
862 return;
863
864 upd = updates;
865
866 /*
867 * Loop thru each ulog entry
868 */
869 for (cnt = 0; cnt < no_of_updates; cnt++) {
870
871 /*
872 * ulog entry - kdb_princ_name
873 */
874 free(upd->kdb_princ_name.utf8str_t_val);
875
876 /* BEGIN CSTYLED */
877
878 /*
879 * ulog entry - kdb_kdcs_seen_by
880 */
881 if (upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val) {
882 for (i = 0; i < upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_len; i++)
883 free(upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val[i].utf8str_t_val);
884 free(upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val);
885 }
886
887 /*
888 * ulog entry - kdb_futures
889 */
890 free(upd->kdb_futures.kdb_futures_val);
891
892 /*
893 * ulog entry - kdb_update
894 */
895 if (upd->kdb_update.kdbe_t_val) {
896 /*
897 * Loop thru all the attributes and free up stuff
898 */
899 for (i = 0; i < upd->kdb_update.kdbe_t_len; i++) {
900
901 /*
902 * Free av_key_data
903 */
904 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_KEYDATA) && ULOG_ENTRY(upd, i).av_keydata.av_keydata_val) {
905
906 for (j = 0; j < ULOG_ENTRY(upd, i).av_keydata.av_keydata_len; j++) {
907 free(ULOG_ENTRY_KEYVAL(upd, i, j).k_enctype.k_enctype_val);
908 if (ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val) {
909 for (k = 0; k < ULOG_ENTRY_KEYVAL(upd, i, j).k_ver; k++) {
910 free(ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val[k].utf8str_t_val);
911 }
912 free(ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val);
913 }
914 }
915 free(ULOG_ENTRY(upd, i).av_keydata.av_keydata_val);
916 }
917
918
919 /*
920 * Free av_tl_data
921 */
922 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_TL_DATA) && ULOG_ENTRY(upd, i).av_tldata.av_tldata_val) {
923 for (j = 0; j < ULOG_ENTRY(upd, i).av_tldata.av_tldata_len; j++) {
924 free(ULOG_ENTRY(upd, i).av_tldata.av_tldata_val[j].tl_data.tl_data_val);
925 }
926 free(ULOG_ENTRY(upd, i).av_tldata.av_tldata_val);
927 }
928
929 /*
930 * Free av_princ
931 */
932 if (ULOG_ENTRY_TYPE(upd, i).av_type == AT_PRINC) {
933 free(ULOG_ENTRY(upd, i).av_princ.k_realm.utf8str_t_val);
934 if (ULOG_ENTRY(upd, i).av_princ.k_components.k_components_val) {
935 for (j = 0; j < ULOG_ENTRY(upd, i).av_princ.k_components.k_components_len; j++) {
936 free(ULOG_ENTRY_PRINC(upd, i, j).k_data.utf8str_t_val);
937 }
938 free(ULOG_ENTRY(upd, i).av_princ.k_components.k_components_val);
939 }
940 }
941
942 /*
943 * Free av_mod_princ
944 */
945 if (ULOG_ENTRY_TYPE(upd, i).av_type == AT_MOD_PRINC) {
946 free(ULOG_ENTRY(upd, i).av_mod_princ.k_realm.utf8str_t_val);
947 if (ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_val) {
948 for (j = 0; j < ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_len; j++) {
949 free(ULOG_ENTRY_MOD_PRINC(upd, i, j).k_data.utf8str_t_val);
950 }
951 free(ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_val);
952 }
953 }
954
955 /*
956 * Free av_mod_where
957 */
958 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_MOD_WHERE) && ULOG_ENTRY(upd, i).av_mod_where.utf8str_t_val)
959 free(ULOG_ENTRY(upd, i).av_mod_where.utf8str_t_val);
960
961 /*
962 * Free av_pw_policy
963 */
964 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_PW_POLICY) && ULOG_ENTRY(upd, i).av_pw_policy.utf8str_t_val)
965 free(ULOG_ENTRY(upd, i).av_pw_policy.utf8str_t_val);
966
967 /*
968 * XXX: Free av_pw_hist
969 *
970 * For now, we just free the pointer
971 * to av_pw_hist_val, since we aren't
972 * populating this union member in
973 * the conv api function(s) anyways.
974 */
975 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_PW_HIST) && ULOG_ENTRY(upd, i).av_pw_hist.av_pw_hist_val)
976 free(ULOG_ENTRY(upd, i).av_pw_hist.av_pw_hist_val);
977
978 }
979
980 /*
981 * Free up the pointer to kdbe_t_val
982 */
983 free(upd->kdb_update.kdbe_t_val);
984 }
985
986 /* END CSTYLED */
987
988 /*
989 * Bump up to next struct
990 */
991 upd++;
992 }
993
994
995 /*
996 * Finally, free up the pointer to the bunched ulog entries
997 */
998 free(updates);
999 }
1000