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 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 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 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 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 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 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 ** 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 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 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 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 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 * 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