1 #pragma ident "%Z%%M% %I% %E% SMI"
2
3 /*
4 * lib/kdb/kdb_ldap/ldap_principal2.c
5 *
6 * Copyright (c) 2004-2005, Novell, Inc.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * * The copyright holder's name is not used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*
33 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
34 * Use is subject to license terms.
35 */
36
37 #include <time.h>
38 #include "ldap_main.h"
39 #include "kdb_ldap.h"
40 #include "ldap_principal.h"
41 #include "princ_xdr.h"
42 #include "ldap_tkt_policy.h"
43 #include "ldap_pwd_policy.h"
44 #include "ldap_err.h"
45 #include <kadm5/admin.h>
46 #include <libintl.h>
47
48 extern char* principal_attributes[];
49 extern char* max_pwd_life_attr[];
50
51 static char *
52 getstringtime(krb5_timestamp);
53
54 krb5_error_code
berval2tl_data(struct berval * in,krb5_tl_data ** out)55 berval2tl_data(struct berval *in, krb5_tl_data **out)
56 {
57 *out = (krb5_tl_data *) malloc (sizeof (krb5_tl_data));
58 if (*out == NULL)
59 return ENOMEM;
60
61 (*out)->tl_data_length = in->bv_len - 2;
62 (*out)->tl_data_contents = (krb5_octet *) malloc
63 ((*out)->tl_data_length * sizeof (krb5_octet));
64 if ((*out)->tl_data_contents == NULL) {
65 free (*out);
66 return ENOMEM;
67 }
68
69 /* Solaris Kerberos: need cast */
70 UNSTORE16_INT ((unsigned char *)in->bv_val, (*out)->tl_data_type);
71 memcpy ((*out)->tl_data_contents, in->bv_val + 2, (*out)->tl_data_length);
72
73 return 0;
74 }
75
76 /*
77 * look up a principal in the directory.
78 */
79
80 krb5_error_code
krb5_ldap_get_principal(context,searchfor,entries,nentries,more)81 krb5_ldap_get_principal(context, searchfor, entries, nentries, more)
82 krb5_context context;
83 krb5_const_principal searchfor;
84 krb5_db_entry *entries; /* filled in */
85 int *nentries; /* how much room/how many found */
86 krb5_boolean *more; /* are there more? */
87 {
88 char *user=NULL, *filter=NULL, **subtree=NULL;
89 unsigned int tree=0, ntrees=1, princlen=0;
90 krb5_error_code tempst=0, st=0;
91 char **values=NULL;
92 LDAP *ld=NULL;
93 LDAPMessage *result=NULL, *ent=NULL;
94 krb5_ldap_context *ldap_context=NULL;
95 kdb5_dal_handle *dal_handle=NULL;
96 krb5_ldap_server_handle *ldap_server_handle=NULL;
97
98 /* Clear the global error string */
99 krb5_clear_error_message(context);
100
101 /* set initial values */
102 *nentries = 0;
103 *more = 0;
104 memset(entries, 0, sizeof(*entries));
105
106 if (searchfor == NULL)
107 return EINVAL;
108
109 dal_handle = (kdb5_dal_handle *) context->db_context;
110 ldap_context = (krb5_ldap_context *) dal_handle->db_context;
111
112 CHECK_LDAP_HANDLE(ldap_context);
113
114 if (is_principal_in_realm(ldap_context, searchfor) != 0) {
115 *more = 0;
116 krb5_set_error_message (context, st, gettext("Principal does not belong to realm"));
117 goto cleanup;
118 }
119
120 if ((st=krb5_unparse_name(context, searchfor, &user)) != 0)
121 goto cleanup;
122
123 if ((st=krb5_ldap_unparse_principal_name(user)) != 0)
124 goto cleanup;
125
126 princlen = strlen(FILTER) + strlen(user) + 2 + 1; /* 2 for closing brackets */
127 if ((filter = malloc(princlen)) == NULL) {
128 st = ENOMEM;
129 goto cleanup;
130 }
131 snprintf(filter, princlen, FILTER"%s))", user);
132
133 if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
134 goto cleanup;
135
136 GET_HANDLE();
137 for (tree=0; tree < ntrees && *nentries == 0; ++tree) {
138
139 LDAP_SEARCH(subtree[tree], ldap_context->lrparams->search_scope, filter, principal_attributes);
140 for (ent=ldap_first_entry(ld, result); ent != NULL && *nentries == 0; ent=ldap_next_entry(ld, ent)) {
141
142 /* get the associated directory user information */
143 if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
144 int i;
145
146 /* a wild-card in a principal name can return a list of kerberos principals.
147 * Make sure that the correct principal is returned.
148 * NOTE: a principalname k* in ldap server will return all the principals starting with a k
149 */
150 for (i=0; values[i] != NULL; ++i) {
151 if (strcasecmp(values[i], user) == 0) {
152 *nentries = 1;
153 break;
154 }
155 }
156 ldap_value_free(values);
157
158 if (*nentries == 0) /* no matching principal found */
159 continue;
160 }
161
162 if ((st = populate_krb5_db_entry(context, ldap_context, ld, ent, searchfor,
163 entries)) != 0)
164 goto cleanup;
165 }
166 ldap_msgfree(result);
167 result = NULL;
168 } /* for (tree=0 ... */
169
170 /* once done, put back the ldap handle */
171 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
172 ldap_server_handle = NULL;
173
174 cleanup:
175 ldap_msgfree(result);
176
177 if (*nentries == 0 || st != 0)
178 krb5_dbe_free_contents(context, entries);
179
180 if (filter)
181 free (filter);
182
183 if (subtree) {
184 for (; ntrees; --ntrees)
185 if (subtree[ntrees-1])
186 free (subtree[ntrees-1]);
187 free (subtree);
188 }
189
190 if (ldap_server_handle)
191 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
192
193 if (user)
194 free(user);
195
196 return st;
197 }
198
199 typedef enum{ ADD_PRINCIPAL, MODIFY_PRINCIPAL } OPERATION;
200 /*
201 * ptype is creating confusions. Additionally the logic
202 * surronding ptype is redundunt and can be achevied
203 * with the help of dn and containerdn members.
204 * so dropping the ptype member
205 */
206
207 typedef struct _xargs_t {
208 char *dn;
209 char *linkdn;
210 krb5_boolean dn_from_kbd;
211 char *containerdn;
212 char *tktpolicydn;
213 }xargs_t;
214
215 static void
free_xargs(xargs)216 free_xargs(xargs)
217 xargs_t xargs;
218 {
219 if (xargs.dn)
220 free (xargs.dn);
221 if (xargs.linkdn)
222 free(xargs.linkdn);
223 if (xargs.containerdn)
224 free (xargs.containerdn);
225 if (xargs.tktpolicydn)
226 free (xargs.tktpolicydn);
227 }
228
229 static krb5_error_code
process_db_args(context,db_args,xargs,optype)230 process_db_args(context, db_args, xargs, optype)
231 krb5_context context;
232 char **db_args;
233 xargs_t *xargs;
234 OPERATION optype;
235 {
236 int i=0;
237 krb5_error_code st=0;
238 char errbuf[1024];
239 char *arg=NULL, *arg_val=NULL;
240 char **dptr=NULL;
241 unsigned int arg_val_len=0;
242
243 if (db_args) {
244 for (i=0; db_args[i]; ++i) {
245 arg = strtok_r(db_args[i], "=", &arg_val);
246 if (strcmp(arg, TKTPOLICY_ARG) == 0) {
247 dptr = &xargs->tktpolicydn;
248 } else {
249 if (strcmp(arg, USERDN_ARG) == 0) {
250 if (optype == MODIFY_PRINCIPAL ||
251 xargs->dn != NULL || xargs->containerdn != NULL ||
252 xargs->linkdn != NULL) {
253 st = EINVAL;
254 snprintf(errbuf, sizeof(errbuf),
255 gettext("%s option not supported"), arg);
256 krb5_set_error_message(context, st, "%s", errbuf);
257 goto cleanup;
258 }
259 dptr = &xargs->dn;
260 } else if (strcmp(arg, CONTAINERDN_ARG) == 0) {
261 if (optype == MODIFY_PRINCIPAL ||
262 xargs->dn != NULL || xargs->containerdn != NULL) {
263 st = EINVAL;
264 snprintf(errbuf, sizeof(errbuf),
265 gettext("%s option not supported"), arg);
266 krb5_set_error_message(context, st, "%s", errbuf);
267 goto cleanup;
268 }
269 dptr = &xargs->containerdn;
270 } else if (strcmp(arg, LINKDN_ARG) == 0) {
271 if (xargs->dn != NULL || xargs->linkdn != NULL) {
272 st = EINVAL;
273 snprintf(errbuf, sizeof(errbuf),
274 gettext("%s option not supported"), arg);
275 krb5_set_error_message(context, st, "%s", errbuf);
276 goto cleanup;
277 }
278 dptr = &xargs->linkdn;
279 } else {
280 st = EINVAL;
281 snprintf(errbuf, sizeof(errbuf), gettext("unknown option: %s"), arg);
282 krb5_set_error_message(context, st, "%s", errbuf);
283 goto cleanup;
284 }
285
286 xargs->dn_from_kbd = TRUE;
287 if (arg_val == NULL || strlen(arg_val) == 0) {
288 st = EINVAL;
289 snprintf(errbuf, sizeof(errbuf),
290 gettext("%s option value missing"), arg);
291 krb5_set_error_message(context, st, "%s", errbuf);
292 goto cleanup;
293 }
294 }
295
296 if (arg_val == NULL) {
297 st = EINVAL;
298 snprintf(errbuf, sizeof(errbuf),
299 gettext("%s option value missing"), arg);
300 krb5_set_error_message(context, st, "%s", errbuf);
301 goto cleanup;
302 }
303 arg_val_len = strlen(arg_val) + 1;
304
305 if (strcmp(arg, TKTPOLICY_ARG) == 0) {
306 if ((st = krb5_ldap_name_to_policydn (context,
307 arg_val,
308 dptr)) != 0)
309 goto cleanup;
310 } else {
311 *dptr = calloc (1, arg_val_len);
312 if (*dptr == NULL) {
313 st = ENOMEM;
314 goto cleanup;
315 }
316 memcpy(*dptr, arg_val, arg_val_len);
317 }
318 }
319 }
320
321 cleanup:
322 return st;
323 }
324
325 krb5int_access accessor;
326 extern int kldap_ensure_initialized (void);
327
328 static krb5_error_code
asn1_encode_sequence_of_keys(krb5_key_data * key_data,krb5_int16 n_key_data,krb5_int32 mkvno,krb5_data ** code)329 asn1_encode_sequence_of_keys (krb5_key_data *key_data, krb5_int16 n_key_data,
330 krb5_int32 mkvno, krb5_data **code)
331 {
332 krb5_error_code err;
333
334 /*
335 * This should be pushed back into other library initialization
336 * code.
337 */
338 err = kldap_ensure_initialized ();
339 if (err)
340 return err;
341
342 return accessor.asn1_ldap_encode_sequence_of_keys(key_data, n_key_data,
343 mkvno, code);
344 }
345
346 static krb5_error_code
asn1_decode_sequence_of_keys(krb5_data * in,krb5_key_data ** out,krb5_int16 * n_key_data,int * mkvno)347 asn1_decode_sequence_of_keys (krb5_data *in, krb5_key_data **out,
348 krb5_int16 *n_key_data, int *mkvno)
349 {
350 krb5_error_code err;
351
352 /*
353 * This should be pushed back into other library initialization
354 * code.
355 */
356 err = kldap_ensure_initialized ();
357 if (err)
358 return err;
359
360 return accessor.asn1_ldap_decode_sequence_of_keys(in, out, n_key_data,
361 mkvno);
362 }
363
364
365 /* Decoding ASN.1 encoded key */
366 static struct berval **
krb5_encode_krbsecretkey(krb5_key_data * key_data,int n_key_data)367 krb5_encode_krbsecretkey(krb5_key_data *key_data, int n_key_data) {
368 struct berval **ret = NULL;
369 int currkvno;
370 int num_versions = 1;
371 int i, j, last;
372 krb5_error_code err = 0;
373
374 if (n_key_data <= 0)
375 return NULL;
376
377 /* Find the number of key versions */
378 for (i = 0; i < n_key_data - 1; i++)
379 if (key_data[i].key_data_kvno != key_data[i + 1].key_data_kvno)
380 num_versions++;
381
382 ret = (struct berval **) calloc (num_versions + 1, sizeof (struct berval *));
383 if (ret == NULL) {
384 err = ENOMEM;
385 goto cleanup;
386 }
387 for (i = 0, last = 0, j = 0, currkvno = key_data[0].key_data_kvno; i < n_key_data; i++) {
388 krb5_data *code;
389 if (i == n_key_data - 1 || key_data[i + 1].key_data_kvno != currkvno) {
390 code = NULL;
391 asn1_encode_sequence_of_keys (key_data+last,
392 (krb5_int16) i - last + 1,
393 0, /* For now, mkvno == 0*/
394 &code);
395 if (code == NULL) {
396 err = ENOMEM;
397 goto cleanup;
398 }
399 ret[j] = malloc (sizeof (struct berval));
400 if (ret[j] == NULL) {
401 err = ENOMEM;
402 goto cleanup;
403 }
404 /*CHECK_NULL(ret[j]); */
405 ret[j]->bv_len = code->length;
406 ret[j]->bv_val = code->data;
407 j++;
408 last = i + 1;
409
410 currkvno = key_data[i].key_data_kvno;
411 /* Solaris Kerberos: fix memleak */
412 free(code);
413 }
414 }
415 ret[num_versions] = NULL;
416
417 cleanup:
418
419 if (err != 0) {
420 if (ret != NULL) {
421 for (i = 0; i <= num_versions; i++)
422 if (ret[i] != NULL)
423 free (ret[i]);
424 free (ret);
425 ret = NULL;
426 }
427 }
428
429 return ret;
430 }
431
tl_data2berval(krb5_tl_data * in,struct berval ** out)432 static krb5_error_code tl_data2berval (krb5_tl_data *in, struct berval **out) {
433 *out = (struct berval *) malloc (sizeof (struct berval));
434 if (*out == NULL)
435 return ENOMEM;
436
437 (*out)->bv_len = in->tl_data_length + 2;
438 (*out)->bv_val = (char *) malloc ((*out)->bv_len);
439 if ((*out)->bv_val == NULL) {
440 free (*out);
441 return ENOMEM;
442 }
443
444 /* Solaris Kerberos: need cast */
445 STORE16_INT((unsigned char *)(*out)->bv_val, in->tl_data_type);
446 memcpy ((*out)->bv_val + 2, in->tl_data_contents, in->tl_data_length);
447
448 return 0;
449 }
450
451 krb5_error_code
krb5_ldap_put_principal(context,entries,nentries,db_args)452 krb5_ldap_put_principal(context, entries, nentries, db_args)
453 krb5_context context;
454 krb5_db_entry *entries;
455 register int *nentries; /* number of entry structs to update */
456 char **db_args;
457 {
458 int i=0, l=0, kerberos_principal_object_type=0;
459 krb5_error_code st=0, tempst=0;
460 LDAP *ld=NULL;
461 LDAPMessage *result=NULL, *ent=NULL;
462 char *user=NULL, *subtree=NULL, *principal_dn=NULL;
463 char **values=NULL, *strval[10]={NULL}, errbuf[1024];
464 struct berval **bersecretkey=NULL;
465 LDAPMod **mods=NULL;
466 krb5_boolean create_standalone_prinicipal=FALSE;
467 krb5_boolean krb_identity_exists=FALSE, establish_links=FALSE;
468 char *standalone_principal_dn=NULL;
469 krb5_tl_data *tl_data=NULL;
470 kdb5_dal_handle *dal_handle=NULL;
471 krb5_ldap_context *ldap_context=NULL;
472 krb5_ldap_server_handle *ldap_server_handle=NULL;
473 osa_princ_ent_rec princ_ent;
474 xargs_t xargs = {0};
475 char *polname = NULL;
476 OPERATION optype;
477 krb5_boolean found_entry = FALSE;
478 struct berval **ber_tl_data = NULL;
479
480 /* Clear the global error string */
481 krb5_clear_error_message(context);
482
483 SETUP_CONTEXT();
484 if (ldap_context->lrparams == NULL || ldap_context->krbcontainer == NULL)
485 return EINVAL;
486
487 /* get ldap handle */
488 GET_HANDLE();
489
490 for (i=0; i < *nentries; ++i, ++entries) {
491 if (is_principal_in_realm(ldap_context, entries->princ) != 0) {
492 st = EINVAL;
493 krb5_set_error_message(context, st, gettext("Principal does not belong to the default realm"));
494 goto cleanup;
495 }
496
497 /* get the principal information to act on */
498 if (entries->princ) {
499 if (((st=krb5_unparse_name(context, entries->princ, &user)) != 0) ||
500 ((st=krb5_ldap_unparse_principal_name(user)) != 0))
501 goto cleanup;
502 }
503
504 /* Identity the type of operation, it can be
505 * add principal or modify principal.
506 * hack if the entries->mask has KRB_PRINCIPAL flag set
507 * then it is a add operation
508 */
509 if (entries->mask & KADM5_PRINCIPAL)
510 optype = ADD_PRINCIPAL;
511 else
512 optype = MODIFY_PRINCIPAL;
513
514 if (((st=krb5_get_princ_type(context, entries, &kerberos_principal_object_type)) != 0) ||
515 ((st=krb5_get_userdn(context, entries, &principal_dn)) != 0))
516 goto cleanup;
517
518 if ((st=process_db_args(context, db_args, &xargs, optype)) != 0)
519 goto cleanup;
520
521 if (entries->mask & KADM5_LOAD) {
522 int tree = 0, princlen = 0, numlentries = 0;
523 unsigned int ntrees = 0;
524 char **subtreelist = NULL, *filter = NULL;
525
526 /* A load operation is special, will do a mix-in (add krbprinc
527 * attrs to a non-krb object entry) if an object exists with a
528 * matching krbprincipalname attribute so try to find existing
529 * object and set principal_dn. This assumes that the
530 * krbprincipalname attribute is unique (only one object entry has
531 * a particular krbprincipalname attribute).
532 */
533 if (user == NULL) {
534 /* must have principal name for search */
535 st = EINVAL;
536 krb5_set_error_message(context, st, gettext("operation can not continue, principal name not found"));
537 goto cleanup;
538 }
539 princlen = strlen(FILTER) + strlen(user) + 2 + 1; /* 2 for closing brackets */
540 if ((filter = malloc(princlen)) == NULL) {
541 st = ENOMEM;
542 goto cleanup;
543 }
544 snprintf(filter, princlen, FILTER"%s))", user);
545
546 /* get the current subtree list */
547 if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
548 goto cleanup;
549
550 found_entry = FALSE;
551 /* search for entry with matching krbprincipalname attribute */
552 for (tree = 0; found_entry == FALSE && tree < ntrees; ++tree) {
553 result = NULL;
554 if (principal_dn == NULL) {
555 LDAP_SEARCH_1(subtreelist[tree], ldap_context->lrparams->search_scope, filter, principal_attributes, IGNORE_STATUS);
556 } else {
557 /* just look for entry with principal_dn */
558 LDAP_SEARCH_1(principal_dn, LDAP_SCOPE_BASE, filter, principal_attributes, IGNORE_STATUS);
559 }
560 if (st == LDAP_SUCCESS) {
561 numlentries = ldap_count_entries(ld, result);
562 if (numlentries > 1) {
563 ldap_msgfree(result);
564 free(filter);
565 st = EINVAL;
566 krb5_set_error_message(context, st,
567 gettext("operation can not continue, more than one entry with principal name \"%s\" found"),
568 user);
569 goto cleanup;
570 } else if (numlentries == 1) {
571 found_entry = TRUE;
572 if (principal_dn == NULL) {
573 ent = ldap_first_entry(ld, result);
574 if (ent != NULL) {
575 /* setting principal_dn will cause that entry to be modified further down */
576 if ((principal_dn = ldap_get_dn(ld, ent)) == NULL) {
577 ldap_get_option (ld, LDAP_OPT_RESULT_CODE, &st);
578 st = set_ldap_error (context, st, 0);
579 ldap_msgfree(result);
580 free(filter);
581 goto cleanup;
582 }
583 }
584 }
585 }
586 if (result)
587 ldap_msgfree(result);
588 } else if (st != LDAP_NO_SUCH_OBJECT) {
589 /* could not perform search, return with failure */
590 st = set_ldap_error (context, st, 0);
591 free(filter);
592 goto cleanup;
593 }
594 /*
595 * If it isn't found then assume a standalone princ entry is to
596 * be created.
597 */
598 } /* end for (tree = 0; principal_dn == ... */
599
600 free(filter);
601
602 if (found_entry == FALSE && principal_dn != NULL) {
603 /*
604 * if principal_dn is null then there is code further down to
605 * deal with setting standalone_principal_dn. Also note that
606 * this will set create_standalone_prinicipal true for
607 * non-mix-in entries which is okay if loading from a dump.
608 */
609 create_standalone_prinicipal = TRUE;
610 standalone_principal_dn = strdup(principal_dn);
611 CHECK_NULL(standalone_principal_dn);
612 }
613 } /* end if (entries->mask & KADM5_LOAD */
614
615 /* time to generate the DN information with the help of
616 * containerdn, principalcontainerreference or
617 * realmcontainerdn information
618 */
619 if (principal_dn == NULL && xargs.dn == NULL) { /* creation of standalone principal */
620 /* get the subtree information */
621 if (entries->princ->length == 2 && entries->princ->data[0].length == strlen("krbtgt") &&
622 strncmp(entries->princ->data[0].data, "krbtgt", entries->princ->data[0].length) == 0) {
623 /* if the principal is a inter-realm principal, always created in the realm container */
624 subtree = strdup(ldap_context->lrparams->realmdn);
625 } else if (xargs.containerdn) {
626 if ((st=checkattributevalue(ld, xargs.containerdn, NULL, NULL, NULL)) != 0) {
627 if (st == KRB5_KDB_NOENTRY || st == KRB5_KDB_CONSTRAINT_VIOLATION) {
628 int ost = st;
629 st = EINVAL;
630 snprintf(errbuf, sizeof(errbuf), gettext("'%s' not found: "), xargs.containerdn);
631 prepend_err_str(context, errbuf, st, ost);
632 }
633 goto cleanup;
634 }
635 subtree = strdup(xargs.containerdn);
636 } else if (ldap_context->lrparams->containerref && strlen(ldap_context->lrparams->containerref) != 0) {
637 /*
638 * Here the subtree should be changed with
639 * principalcontainerreference attribute value
640 */
641 subtree = strdup(ldap_context->lrparams->containerref);
642 } else {
643 subtree = strdup(ldap_context->lrparams->realmdn);
644 }
645 CHECK_NULL(subtree);
646
647 standalone_principal_dn = malloc(strlen("krbprincipalname=") + strlen(user) + strlen(",") +
648 strlen(subtree) + 1);
649 CHECK_NULL(standalone_principal_dn);
650 /*LINTED*/
651 sprintf(standalone_principal_dn, "krbprincipalname=%s,%s", user, subtree);
652 /*
653 * free subtree when you are done using the subtree
654 * set the boolean create_standalone_prinicipal to TRUE
655 */
656 create_standalone_prinicipal = TRUE;
657 free(subtree);
658 subtree = NULL;
659 }
660
661 /*
662 * If the DN information is presented by the user, time to
663 * validate the input to ensure that the DN falls under
664 * any of the subtrees
665 */
666 if (xargs.dn_from_kbd == TRUE) {
667 /* make sure the DN falls in the subtree */
668 int tre=0, dnlen=0, subtreelen=0;
669 unsigned int ntrees = 0;
670 char **subtreelist=NULL;
671 char *dn=NULL;
672 krb5_boolean outofsubtree=TRUE;
673
674 if (xargs.dn != NULL) {
675 dn = xargs.dn;
676 } else if (xargs.linkdn != NULL) {
677 dn = xargs.linkdn;
678 } else if (standalone_principal_dn != NULL) {
679 /*
680 * Even though the standalone_principal_dn is constructed
681 * within this function, there is the containerdn input
682 * from the user that can become part of the it.
683 */
684 dn = standalone_principal_dn;
685 }
686
687 /* get the current subtree list */
688 if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
689 goto cleanup;
690
691 for (tre=0; tre<ntrees; ++tre) {
692 if (subtreelist[tre] == NULL || strlen(subtreelist[tre]) == 0) {
693 outofsubtree = FALSE;
694 break;
695 } else {
696 dnlen = strlen (dn);
697 subtreelen = strlen(subtreelist[tre]);
698 if ((dnlen >= subtreelen) && (strcasecmp((dn + dnlen - subtreelen), subtreelist[tre]) == 0)) {
699 outofsubtree = FALSE;
700 break;
701 }
702 }
703 }
704
705 for (tre=0; tre < ntrees; ++tre) {
706 free(subtreelist[tre]);
707 }
708
709 if (outofsubtree == TRUE) {
710 st = EINVAL;
711 krb5_set_error_message(context, st, gettext("DN is out of the realm subtree"));
712 goto cleanup;
713 }
714
715 /*
716 * dn value will be set either by dn, linkdn or the standalone_principal_dn
717 * In the first 2 cases, the dn should be existing and in the last case we
718 * are supposed to create the ldap object. so the below should not be
719 * executed for the last case.
720 */
721
722 if (standalone_principal_dn == NULL) {
723 /*
724 * If the ldap object is missing, this results in an error.
725 */
726
727 /*
728 * Search for krbprincipalname attribute here.
729 * This is to find if a kerberos identity is already present
730 * on the ldap object, in which case adding a kerberos identity
731 * on the ldap object should result in an error.
732 */
733 char *attributes[]={"krbticketpolicyreference", "krbprincipalname", NULL};
734
735 LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attributes, IGNORE_STATUS);
736 if (st == LDAP_SUCCESS) {
737 ent = ldap_first_entry(ld, result);
738 if (ent != NULL) {
739 if ((values=ldap_get_values(ld, ent, "krbticketpolicyreference")) != NULL) {
740 ldap_value_free(values);
741 }
742
743 if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
744 krb_identity_exists = TRUE;
745 ldap_value_free(values);
746 }
747 }
748 ldap_msgfree(result);
749 } else {
750 st = set_ldap_error(context, st, OP_SEARCH);
751 goto cleanup;
752 }
753 }
754 }
755
756 /*
757 * If xargs.dn is set then the request is to add a
758 * kerberos principal on a ldap object, but if
759 * there is one already on the ldap object this
760 * should result in an error.
761 */
762
763 if (xargs.dn != NULL && krb_identity_exists == TRUE) {
764 st = EINVAL;
765 snprintf(errbuf, sizeof(errbuf), gettext("ldap object is already kerberized"));
766 krb5_set_error_message(context, st, "%s", errbuf);
767 goto cleanup;
768 }
769
770 if (xargs.linkdn != NULL) {
771 /*
772 * link information can be changed using modprinc.
773 * However, link information can be changed only on the
774 * standalone kerberos principal objects. A standalone
775 * kerberos principal object is of type krbprincipal
776 * structural objectclass.
777 *
778 * NOTE: kerberos principals on an ldap object can't be
779 * linked to other ldap objects.
780 */
781 if (optype == MODIFY_PRINCIPAL &&
782 kerberos_principal_object_type != KDB_STANDALONE_PRINCIPAL_OBJECT) {
783 st = EINVAL;
784 snprintf(errbuf, sizeof(errbuf),
785 gettext("link information can not be set/updated as the kerberos principal belongs to an ldap object"));
786 krb5_set_error_message(context, st, "%s", errbuf);
787 goto cleanup;
788 }
789 /*
790 * Check the link information. If there is already a link
791 * existing then this operation is not allowed.
792 */
793 {
794 char **linkdns=NULL;
795 int j=0;
796
797 if ((st=krb5_get_linkdn(context, entries, &linkdns)) != 0) {
798 snprintf(errbuf, sizeof(errbuf),
799 gettext("Failed getting object references"));
800 krb5_set_error_message(context, st, "%s", errbuf);
801 goto cleanup;
802 }
803 if (linkdns != NULL) {
804 st = EINVAL;
805 snprintf(errbuf, sizeof(errbuf),
806 gettext("kerberos principal is already linked "
807 "to a ldap object"));
808 krb5_set_error_message(context, st, "%s", errbuf);
809 for (j=0; linkdns[j] != NULL; ++j)
810 free (linkdns[j]);
811 free (linkdns);
812 goto cleanup;
813 }
814 }
815
816 establish_links = TRUE;
817 }
818
819 if ((entries->last_success)!=0) {
820 memset(strval, 0, sizeof(strval));
821 if ((strval[0]=getstringtime(entries->last_success)) == NULL)
822 goto cleanup;
823 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastSuccessfulAuth", LDAP_MOD_REPLACE, strval)) != 0) {
824 free (strval[0]);
825 goto cleanup;
826 }
827 free (strval[0]);
828 }
829
830 if (entries->last_failed!=0) {
831 memset(strval, 0, sizeof(strval));
832 if ((strval[0]=getstringtime(entries->last_failed)) == NULL)
833 goto cleanup;
834 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastFailedAuth", LDAP_MOD_REPLACE, strval)) != 0) {
835 free (strval[0]);
836 goto cleanup;
837 }
838 free(strval[0]);
839 }
840
841 if (entries->fail_auth_count!=0) {
842 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount", LDAP_MOD_REPLACE, entries->fail_auth_count)) !=0)
843 goto cleanup;
844 }
845
846 if (entries->mask & KADM5_MAX_LIFE) {
847 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, entries->max_life)) != 0)
848 goto cleanup;
849 }
850
851 if (entries->mask & KADM5_MAX_RLIFE) {
852 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE,
853 entries->max_renewable_life)) != 0)
854 goto cleanup;
855 }
856
857 if (entries->mask & KADM5_ATTRIBUTES) {
858 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE,
859 entries->attributes)) != 0)
860 goto cleanup;
861 }
862
863 if (entries->mask & KADM5_PRINCIPAL) {
864 memset(strval, 0, sizeof(strval));
865 strval[0] = user;
866 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_REPLACE, strval)) != 0)
867 goto cleanup;
868 }
869
870 /*
871 * Solaris Kerberos: this logic was not working properly when
872 * default_principal_expiration set.
873 */
874 if (entries->mask & KADM5_PRINC_EXPIRE_TIME || entries->expiration != 0) {
875 memset(strval, 0, sizeof(strval));
876 if ((strval[0]=getstringtime(entries->expiration)) == NULL)
877 goto cleanup;
878 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalexpiration", LDAP_MOD_REPLACE, strval)) != 0) {
879 free (strval[0]);
880 goto cleanup;
881 }
882 free (strval[0]);
883 }
884
885 /*
886 * Solaris Kerberos: in case KADM5_PW_EXPIRATION isn't set, check
887 * pw_expiration
888 */
889 if (entries->mask & KADM5_PW_EXPIRATION || entries->pw_expiration != 0) {
890 memset(strval, 0, sizeof(strval));
891 if ((strval[0]=getstringtime(entries->pw_expiration)) == NULL)
892 goto cleanup;
893 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpasswordexpiration",
894 LDAP_MOD_REPLACE,
895 strval)) != 0) {
896 free (strval[0]);
897 goto cleanup;
898 }
899 free (strval[0]);
900 }
901
902 if (entries->mask & KADM5_POLICY) {
903 memset(&princ_ent, 0, sizeof(princ_ent));
904 for (tl_data=entries->tl_data; tl_data; tl_data=tl_data->tl_data_next) {
905 if (tl_data->tl_data_type == KRB5_TL_KADM_DATA) {
906 /* FIX ME: I guess the princ_ent should be freed after this call */
907 if ((st = krb5_lookup_tl_kadm_data(tl_data, &princ_ent)) != 0) {
908 goto cleanup;
909 }
910 }
911 }
912
913 if (princ_ent.aux_attributes & KADM5_POLICY) {
914 memset(strval, 0, sizeof(strval));
915 if ((st = krb5_ldap_name_to_policydn (context, princ_ent.policy, &polname)) != 0)
916 goto cleanup;
917 strval[0] = polname;
918 /* Solaris Kerberos: fix memleak */
919 free(princ_ent.policy);
920 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
921 goto cleanup;
922 } else {
923 st = EINVAL;
924 krb5_set_error_message(context, st, gettext("Password policy value null"));
925 goto cleanup;
926 }
927 } else if (entries->mask & KADM5_LOAD && found_entry == TRUE) {
928 /*
929 * a load is special in that existing entries must have attrs that
930 * removed.
931 */
932
933 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, NULL)) != 0)
934 goto cleanup;
935 }
936
937 if (entries->mask & KADM5_POLICY_CLR) {
938 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
939 goto cleanup;
940 }
941
942 if (entries->mask & KADM5_KEY_DATA || entries->mask & KADM5_KVNO) {
943 bersecretkey = krb5_encode_krbsecretkey (entries->key_data,
944 entries->n_key_data);
945
946 if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey",
947 LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, bersecretkey)) != 0)
948 goto cleanup;
949
950 if (!(entries->mask & KADM5_PRINCIPAL)) {
951 memset(strval, 0, sizeof(strval));
952 if ((strval[0]=getstringtime(entries->pw_expiration)) == NULL)
953 goto cleanup;
954 if ((st=krb5_add_str_mem_ldap_mod(&mods,
955 "krbpasswordexpiration",
956 LDAP_MOD_REPLACE, strval)) != 0) {
957 free (strval[0]);
958 goto cleanup;
959 }
960 free (strval[0]);
961 }
962
963 /* Update last password change whenever a new key is set */
964 {
965 krb5_timestamp last_pw_changed;
966 if ((st=krb5_dbe_lookup_last_pwd_change(context, entries,
967 &last_pw_changed)) != 0)
968 goto cleanup;
969
970 memset(strval, 0, sizeof(strval));
971 if ((strval[0] = getstringtime(last_pw_changed)) == NULL)
972 goto cleanup;
973
974 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastPwdChange",
975 LDAP_MOD_REPLACE, strval)) != 0) {
976 free (strval[0]);
977 goto cleanup;
978 }
979 free (strval[0]);
980 }
981
982 } /* Modify Key data ends here */
983
984 /* Set tl_data */
985 if (entries->tl_data != NULL) {
986 int count = 0;
987 /* struct berval **ber_tl_data = NULL; */
988 krb5_tl_data *ptr;
989 for (ptr = entries->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
990 if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
991 #ifdef SECURID
992 || ptr->tl_data_type == KRB5_TL_DB_ARGS
993 #endif
994 || ptr->tl_data_type == KDB_TL_USER_INFO)
995 continue;
996
997 /* Solaris Kerberos: fix key history issue */
998 if (ptr->tl_data_type == KRB5_TL_KADM_DATA && ! entries->mask & KADM5_KEY_HIST)
999 continue;
1000
1001 count++;
1002 }
1003 if (count != 0) {
1004 int j;
1005 ber_tl_data = (struct berval **) calloc (count + 1,
1006 sizeof (struct berval*));
1007 if (ber_tl_data == NULL) {
1008 st = ENOMEM;
1009 goto cleanup;
1010 }
1011 for (j = 0, ptr = entries->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
1012 /* Ignore tl_data that are stored in separate directory
1013 * attributes */
1014 if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
1015 #ifdef SECURID
1016 || ptr->tl_data_type == KRB5_TL_DB_ARGS
1017 #endif
1018 || ptr->tl_data_type == KDB_TL_USER_INFO)
1019 continue;
1020
1021 /*
1022 * Solaris Kerberos: key history needs to be stored (it's in
1023 * the KRB5_TL_KADM_DATA).
1024 */
1025 if (ptr->tl_data_type == KRB5_TL_KADM_DATA && ! entries->mask & KADM5_KEY_HIST)
1026 continue;
1027
1028 if ((st = tl_data2berval (ptr, &ber_tl_data[j])) != 0)
1029 break;
1030 j++;
1031 }
1032 if (st != 0) {
1033 /* Solaris Kerberos: don't free here, do it at cleanup */
1034 goto cleanup;
1035 }
1036 ber_tl_data[count] = NULL;
1037 if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbExtraData",
1038 LDAP_MOD_REPLACE | LDAP_MOD_BVALUES,
1039 ber_tl_data)) != 0)
1040 goto cleanup;
1041 }
1042 }
1043
1044 /* Directory specific attribute */
1045 if (xargs.tktpolicydn != NULL) {
1046 int tmask=0;
1047
1048 if (strlen(xargs.tktpolicydn) != 0) {
1049 st = checkattributevalue(ld, xargs.tktpolicydn, "objectclass", policyclass, &tmask);
1050 CHECK_CLASS_VALIDITY(st, tmask, "ticket policy object value: ");
1051
1052 strval[0] = xargs.tktpolicydn;
1053 strval[1] = NULL;
1054 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
1055 goto cleanup;
1056
1057 } else {
1058 /* if xargs.tktpolicydn is a empty string, then delete
1059 * already existing krbticketpolicyreference attr */
1060 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
1061 goto cleanup;
1062 }
1063
1064 }
1065
1066 if (establish_links == TRUE) {
1067 memset(strval, 0, sizeof(strval));
1068 strval[0] = xargs.linkdn;
1069 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbObjectReferences", LDAP_MOD_REPLACE, strval)) != 0)
1070 goto cleanup;
1071 }
1072
1073 /*
1074 * in case mods is NULL then return
1075 * not sure but can happen in a modprinc
1076 * so no need to return an error
1077 * addprinc will at least have the principal name
1078 * and the keys passed in
1079 */
1080 if (mods == NULL)
1081 goto cleanup;
1082
1083 if (create_standalone_prinicipal == TRUE) {
1084 memset(strval, 0, sizeof(strval));
1085 strval[0] = "krbprincipal";
1086 strval[1] = "krbprincipalaux";
1087 strval[2] = "krbTicketPolicyAux";
1088
1089 if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
1090 goto cleanup;
1091
1092 st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
1093 if (st == LDAP_ALREADY_EXISTS && entries->mask & KADM5_LOAD) {
1094 /* a load operation must replace an existing entry */
1095 st = ldap_delete_ext_s(ld, standalone_principal_dn, NULL, NULL);
1096 if (st != LDAP_SUCCESS) {
1097 snprintf(errbuf, sizeof (errbuf), gettext("Principal delete failed (trying to replace entry): %s"),
1098 ldap_err2string(st));
1099 st = translate_ldap_error (st, OP_ADD);
1100 krb5_set_error_message(context, st, "%s", errbuf);
1101 goto cleanup;
1102 } else {
1103 st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
1104 }
1105 }
1106 if (st != LDAP_SUCCESS) {
1107 snprintf(errbuf, sizeof (errbuf), gettext("Principal add failed: %s"), ldap_err2string(st));
1108 st = translate_ldap_error (st, OP_ADD);
1109 krb5_set_error_message(context, st, "%s", errbuf);
1110 goto cleanup;
1111 }
1112 } else {
1113 /*
1114 * Here existing ldap object is modified and can be related
1115 * to any attribute, so always ensure that the ldap
1116 * object is extended with all the kerberos related
1117 * objectclasses so that there are no constraint
1118 * violations.
1119 */
1120 {
1121 char *attrvalues[] = {"krbprincipalaux", "krbTicketPolicyAux", NULL};
1122 int p, q, r=0, amask=0;
1123
1124 if ((st=checkattributevalue(ld, (xargs.dn) ? xargs.dn : principal_dn,
1125 "objectclass", attrvalues, &amask)) != 0)
1126 goto cleanup;
1127
1128 memset(strval, 0, sizeof(strval));
1129 for (p=1, q=0; p<=2; p<<=1, ++q) {
1130 if ((p & amask) == 0)
1131 strval[r++] = attrvalues[q];
1132 }
1133 if (r != 0) {
1134 if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
1135 goto cleanup;
1136 }
1137 }
1138 if (xargs.dn != NULL)
1139 st=ldap_modify_ext_s(ld, xargs.dn, mods, NULL, NULL);
1140 else
1141 st = ldap_modify_ext_s(ld, principal_dn, mods, NULL, NULL);
1142
1143 if (st != LDAP_SUCCESS) {
1144 snprintf(errbuf, sizeof (errbuf), gettext("User modification failed: %s"), ldap_err2string(st));
1145 st = translate_ldap_error (st, OP_MOD);
1146 krb5_set_error_message(context, st, "%s", errbuf);
1147 goto cleanup;
1148 }
1149 }
1150 }
1151
1152 cleanup:
1153 if (user)
1154 free(user);
1155
1156 free_xargs(xargs);
1157
1158 if (standalone_principal_dn)
1159 free(standalone_principal_dn);
1160
1161 if (principal_dn)
1162 free (principal_dn);
1163
1164 /* Solaris Kerberos: fix memleak */
1165 if (ber_tl_data) {
1166 int j;
1167
1168 for (j = 0; ber_tl_data[j] != NULL; j++) {
1169 free (ber_tl_data[j]->bv_val);
1170 free (ber_tl_data[j]);
1171 }
1172 free(ber_tl_data);
1173 }
1174
1175 if (polname != NULL)
1176 free(polname);
1177
1178 if (subtree)
1179 free (subtree);
1180
1181 if (bersecretkey) {
1182 for (l=0; bersecretkey[l]; ++l) {
1183 if (bersecretkey[l]->bv_val)
1184 free (bersecretkey[l]->bv_val);
1185 free (bersecretkey[l]);
1186 }
1187 free (bersecretkey);
1188 }
1189
1190 ldap_mods_free(mods, 1);
1191 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
1192 *nentries = i;
1193 return(st);
1194 }
1195
1196 krb5_error_code
krb5_read_tkt_policy(context,ldap_context,entries,policy)1197 krb5_read_tkt_policy (context, ldap_context, entries, policy)
1198 krb5_context context;
1199 krb5_ldap_context *ldap_context;
1200 krb5_db_entry *entries;
1201 char *policy;
1202 {
1203 krb5_error_code st=0;
1204 unsigned int mask=0, omask=0;
1205 int tkt_mask=(KDB_MAX_LIFE_ATTR | KDB_MAX_RLIFE_ATTR | KDB_TKT_FLAGS_ATTR);
1206 krb5_ldap_policy_params *tktpoldnparam=NULL;
1207
1208 if ((st=krb5_get_attributes_mask(context, entries, &mask)) != 0)
1209 goto cleanup;
1210
1211 if ((mask & tkt_mask) == tkt_mask)
1212 goto cleanup;
1213
1214 if (policy != NULL) {
1215 st = krb5_ldap_read_policy(context, policy, &tktpoldnparam, &omask);
1216 if (st && st != KRB5_KDB_NOENTRY) {
1217 prepend_err_str(context, gettext("Error reading ticket policy. "), st, st);
1218 goto cleanup;
1219 }
1220
1221 st = 0; /* reset the return status */
1222 }
1223
1224 if ((mask & KDB_MAX_LIFE_ATTR) == 0) {
1225 if ((omask & KDB_MAX_LIFE_ATTR) == KDB_MAX_LIFE_ATTR)
1226 entries->max_life = tktpoldnparam->maxtktlife;
1227 else if (ldap_context->lrparams->max_life)
1228 entries->max_life = ldap_context->lrparams->max_life;
1229 }
1230
1231 if ((mask & KDB_MAX_RLIFE_ATTR) == 0) {
1232 if ((omask & KDB_MAX_RLIFE_ATTR) == KDB_MAX_RLIFE_ATTR)
1233 entries->max_renewable_life = tktpoldnparam->maxrenewlife;
1234 else if (ldap_context->lrparams->max_renewable_life)
1235 entries->max_renewable_life = ldap_context->lrparams->max_renewable_life;
1236 }
1237
1238 if ((mask & KDB_TKT_FLAGS_ATTR) == 0) {
1239 if ((omask & KDB_TKT_FLAGS_ATTR) == KDB_TKT_FLAGS_ATTR)
1240 entries->attributes = tktpoldnparam->tktflags;
1241 else if (ldap_context->lrparams->tktflags)
1242 entries->attributes |= ldap_context->lrparams->tktflags;
1243 }
1244 krb5_ldap_free_policy(context, tktpoldnparam);
1245
1246 cleanup:
1247 return st;
1248 }
1249
1250 krb5_error_code
krb5_decode_krbsecretkey(context,entries,bvalues)1251 krb5_decode_krbsecretkey(context, entries, bvalues)
1252 krb5_context context;
1253 krb5_db_entry *entries;
1254 struct berval **bvalues;
1255 {
1256 char *user=NULL;
1257 int i=0, j=0, noofkeys=0;
1258 krb5_key_data *key_data=NULL, *tmp;
1259 krb5_error_code st=0;
1260
1261 if ((st=krb5_unparse_name(context, entries->princ, &user)) != 0)
1262 goto cleanup;
1263
1264 for (i=0; bvalues[i] != NULL; ++i) {
1265 int mkvno; /* Not used currently */
1266 krb5_int16 n_kd;
1267 krb5_key_data *kd;
1268 krb5_data in;
1269
1270 if (bvalues[i]->bv_len == 0)
1271 continue;
1272 in.length = bvalues[i]->bv_len;
1273 in.data = bvalues[i]->bv_val;
1274
1275 st = asn1_decode_sequence_of_keys (&in,
1276 &kd,
1277 &n_kd,
1278 &mkvno);
1279
1280 if (st != 0) {
1281 const char *msg = error_message(st);
1282 st = -1; /* Something more appropriate ? */
1283 krb5_set_error_message (context, st,
1284 gettext("unable to decode stored principal key data (%s)"), msg);
1285 goto cleanup;
1286 }
1287 noofkeys += n_kd;
1288 tmp = key_data;
1289 key_data = realloc (key_data, noofkeys * sizeof (krb5_key_data));
1290 if (key_data == NULL) {
1291 key_data = tmp;
1292 st = ENOMEM;
1293 goto cleanup;
1294 }
1295 for (j = 0; j < n_kd; j++)
1296 key_data[noofkeys - n_kd + j] = kd[j];
1297 free (kd);
1298 }
1299
1300 entries->n_key_data = noofkeys;
1301 entries->key_data = key_data;
1302
1303 cleanup:
1304 ldap_value_free_len(bvalues);
1305 free (user);
1306 return st;
1307 }
1308
1309 static char *
getstringtime(epochtime)1310 getstringtime(epochtime)
1311 krb5_timestamp epochtime;
1312 {
1313 struct tm tme;
1314 char *strtime=NULL;
1315 time_t posixtime = epochtime;
1316
1317 strtime = calloc (50, 1);
1318 if (strtime == NULL)
1319 return NULL;
1320
1321 if (gmtime_r(&posixtime, &tme) == NULL)
1322 return NULL;
1323
1324 strftime(strtime, 50, DATE_FORMAT, &tme);
1325 return strtime;
1326 }
1327
1328