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