1 /* 2 * lib/kdb/kdb_ldap/ldap_misc.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 #include <string.h> 35 #include <time.h> 36 #include <k5-platform.h> 37 #include "ldap_main.h" 38 #include "ldap_err.h" 39 #include "ldap_principal.h" 40 #include "princ_xdr.h" 41 #include "ldap_pwd_policy.h" 42 #include <libintl.h> 43 44 #ifdef NEED_STRPTIME_PROTO 45 extern char *strptime (const char *, const char *, struct tm *); 46 #endif 47 48 static krb5_error_code 49 remove_overlapping_subtrees(char **listin, char **listop, int *subtcount, 50 int sscope); 51 52 /* Linux (GNU Libc) provides a length-limited variant of strdup. 53 But all the world's not Linux. */ 54 #undef strndup 55 #define strndup my_strndup 56 #ifdef HAVE_LDAP_STR2DN 57 static char *my_strndup (const char *input, size_t limit) 58 { 59 size_t len = strlen(input); 60 char *result; 61 if (len > limit) { 62 result = malloc(1 + limit); 63 if (result != NULL) { 64 memcpy(result, input, limit); 65 result[limit] = 0; 66 } 67 return result; 68 } else 69 return strdup(input); 70 } 71 #endif 72 73 /* Get integer or string values from the config section, falling back 74 to the default section, then to hard-coded values. */ 75 static errcode_t 76 prof_get_integer_def(krb5_context ctx, const char *conf_section, 77 const char *name, int dfl, krb5_ui_4 *out) 78 { 79 errcode_t err; 80 int out_temp = 0; 81 82 err = profile_get_integer (ctx->profile, 83 KDB_MODULE_SECTION, conf_section, name, 84 0, &out_temp); 85 if (err) { 86 krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"), 87 name, error_message(err)); 88 return err; 89 } 90 if (out_temp != 0) { 91 *out = out_temp; 92 return 0; 93 } 94 err = profile_get_integer (ctx->profile, 95 KDB_MODULE_DEF_SECTION, name, 0, 96 dfl, &out_temp); 97 if (err) { 98 krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"), 99 name, error_message(err)); 100 return err; 101 } 102 *out = out_temp; 103 return 0; 104 } 105 106 /* We don't have non-null defaults in any of our calls, so don't 107 bother with the extra argument. */ 108 static errcode_t 109 prof_get_string_def(krb5_context ctx, const char *conf_section, 110 const char *name, char **out) 111 { 112 errcode_t err; 113 114 err = profile_get_string (ctx->profile, 115 KDB_MODULE_SECTION, conf_section, name, 116 0, out); 117 if (err) { 118 krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"), 119 name, error_message(err)); 120 return err; 121 } 122 if (*out != 0) 123 return 0; 124 err = profile_get_string (ctx->profile, 125 KDB_MODULE_DEF_SECTION, name, 0, 126 0, out); 127 if (err) { 128 krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"), 129 name, error_message(err)); 130 return err; 131 } 132 return 0; 133 } 134 135 136 137 /* 138 * This function reads the parameters from the krb5.conf file. The 139 * parameters read here are DAL-LDAP specific attributes. Some of 140 * these are ldap_server .... 141 */ 142 krb5_error_code 143 krb5_ldap_read_server_params(context, conf_section, srv_type) 144 krb5_context context; 145 char *conf_section; 146 int srv_type; 147 { 148 char *tempval=NULL, *save_ptr=NULL; 149 const char *delims="\t\n\f\v\r ,"; 150 krb5_error_code st=0; 151 kdb5_dal_handle *dal_handle=NULL; 152 krb5_ldap_context *ldap_context=NULL; 153 krb5_ldap_server_info ***server_info=NULL; 154 155 dal_handle = (kdb5_dal_handle *) context->db_context; 156 ldap_context = (krb5_ldap_context *) dal_handle->db_context; 157 158 /* copy the conf_section into ldap_context for later use */ 159 if (conf_section) { 160 ldap_context->conf_section = strdup (conf_section); 161 if (ldap_context->conf_section == NULL) { 162 st = ENOMEM; 163 goto cleanup; 164 } 165 } 166 167 /* initialize the mutexs and condition variable */ 168 /* this portion logically doesn't fit here should be moved appropriately */ 169 170 /* this mutex is used in ldap reconnection pool */ 171 if (k5_mutex_init(&(ldap_context->hndl_lock)) != 0) { 172 st = KRB5_KDB_SERVER_INTERNAL_ERR; 173 #if 0 174 st = -1; 175 krb5_ldap_dal_err_funcp(context, krb5_err_have_str, st, 176 "k5_mutex_init failed"); 177 #endif 178 goto cleanup; 179 } 180 181 /* 182 * If max_server_conns is not set read it from database module 183 * section of conf file this parameter defines maximum ldap 184 * connections per ldap server. 185 */ 186 if (ldap_context->max_server_conns == 0) { 187 st = prof_get_integer_def (context, conf_section, 188 "ldap_conns_per_server", 189 DEFAULT_CONNS_PER_SERVER, 190 &ldap_context->max_server_conns); 191 if (st) 192 goto cleanup; 193 } 194 195 if (ldap_context->max_server_conns < 2) { 196 st = EINVAL; 197 krb5_set_error_message (context, st, 198 gettext("Minimum connections required per server is 2")); 199 goto cleanup; 200 } 201 202 /* 203 * If the bind dn is not set read it from the database module 204 * section of conf file this paramter is populated by one of the 205 * KDC, ADMIN or PASSWD dn to be used to connect to LDAP 206 * server. The srv_type decides which dn to read. 207 */ 208 if (ldap_context->bind_dn == NULL) { 209 char *name = 0; 210 if (srv_type == KRB5_KDB_SRV_TYPE_KDC) 211 name = "ldap_kdc_dn"; 212 else if (srv_type == KRB5_KDB_SRV_TYPE_ADMIN) 213 name = "ldap_kadmind_dn"; 214 else if (srv_type == KRB5_KDB_SRV_TYPE_PASSWD) 215 name = "ldap_kpasswdd_dn"; 216 217 if (name) { 218 st = prof_get_string_def (context, conf_section, name, 219 &ldap_context->bind_dn); 220 if (st) 221 goto cleanup; 222 } 223 } 224 225 /* 226 * Read service_password_file parameter from database module 227 * section of conf file this file contains stashed passwords of 228 * the KDC, ADMIN and PASSWD dns. 229 */ 230 if (ldap_context->service_password_file == NULL) { 231 /* 232 * Solaris Kerberos: providing a default. 233 */ 234 st = profile_get_string (context->profile, KDB_MODULE_SECTION, 235 conf_section, 236 "ldap_service_password_file", 237 NULL, 238 &ldap_context->service_password_file); 239 240 if (st) 241 goto cleanup; 242 243 if (ldap_context->service_password_file == NULL) { 244 st = profile_get_string (context->profile, KDB_MODULE_DEF_SECTION, 245 "ldap_service_password_file", 246 NULL, 247 DEF_SERVICE_PASSWD_FILE, 248 &ldap_context->service_password_file); 249 if (st) 250 goto cleanup; 251 } 252 } 253 254 /* 255 * Solaris Kerberos: we must use root_certificate_file 256 * 257 * Note, I've changed the ldap_root_certificate_file config parameter to 258 * ldap_cert_path which is more appropriate for that parameter. 259 */ 260 /* #ifdef HAVE_EDIRECTORY */ 261 /* 262 * If root certificate file is not set read it from database 263 * module section of conf file this is the trusted root 264 * certificate of the Directory. 265 */ 266 if (ldap_context->root_certificate_file == NULL) { 267 st = prof_get_string_def (context, conf_section, 268 "ldap_cert_path", 269 &ldap_context->root_certificate_file); 270 if (st) 271 goto cleanup; 272 } 273 /* #endif */ 274 275 /* 276 * If the ldap server parameter is not set read the list of ldap 277 * servers from the database module section of the conf file. 278 */ 279 280 if (ldap_context->server_info_list == NULL) { 281 unsigned int ele=0; 282 283 server_info = &(ldap_context->server_info_list); 284 *server_info = (krb5_ldap_server_info **) calloc (SERV_COUNT+1, 285 sizeof (krb5_ldap_server_info *)); 286 287 if (*server_info == NULL) { 288 st = ENOMEM; 289 goto cleanup; 290 } 291 292 if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section, 293 "ldap_servers", NULL, &tempval)) != 0) { 294 krb5_set_error_message (context, st, gettext("Error reading 'ldap_servers' attribute")); 295 goto cleanup; 296 } 297 298 if (tempval == NULL) { 299 300 (*server_info)[ele] = (krb5_ldap_server_info *)calloc(1, 301 sizeof(krb5_ldap_server_info)); 302 303 if ((*server_info)[ele] == NULL) { 304 st = ENOMEM; 305 goto cleanup; 306 } 307 (*server_info)[ele]->server_name = strdup("ldapi://"); 308 if ((*server_info)[ele]->server_name == NULL) { 309 st = ENOMEM; 310 goto cleanup; 311 } 312 (*server_info)[ele]->server_status = NOTSET; 313 } else { 314 char *item=NULL; 315 316 item = strtok_r(tempval,delims,&save_ptr); 317 while (item != NULL && ele<SERV_COUNT) { 318 (*server_info)[ele] = (krb5_ldap_server_info *)calloc(1, 319 sizeof(krb5_ldap_server_info)); 320 if ((*server_info)[ele] == NULL) { 321 st = ENOMEM; 322 goto cleanup; 323 } 324 (*server_info)[ele]->server_name = strdup(item); 325 if ((*server_info)[ele]->server_name == NULL) { 326 st = ENOMEM; 327 goto cleanup; 328 } 329 330 (*server_info)[ele]->server_status = NOTSET; 331 item = strtok_r(NULL,delims,&save_ptr); 332 ++ele; 333 } 334 profile_release_string(tempval); 335 } 336 } 337 338 cleanup: 339 return(st); 340 } 341 342 /* 343 * This function frees the krb5_ldap_context structure members. 344 */ 345 346 krb5_error_code 347 krb5_ldap_free_server_params(ldap_context) 348 krb5_ldap_context *ldap_context; 349 { 350 int i=0; 351 krb5_ldap_server_handle *ldap_server_handle=NULL, *next_ldap_server_handle=NULL; 352 353 if (ldap_context == NULL) 354 return 0; 355 356 /* Free all ldap servers list and the ldap handles associated with 357 the ldap server. */ 358 if (ldap_context->server_info_list) { 359 while (ldap_context->server_info_list[i]) { 360 if (ldap_context->server_info_list[i]->server_name) { 361 free (ldap_context->server_info_list[i]->server_name); 362 } 363 #ifdef HAVE_EDIRECTORY 364 if (ldap_context->server_info_list[i]->root_certificate_file) { 365 free (ldap_context->server_info_list[i]->root_certificate_file); 366 } 367 #endif 368 if (ldap_context->server_info_list[i]->ldap_server_handles) { 369 ldap_server_handle = ldap_context->server_info_list[i]->ldap_server_handles; 370 while (ldap_server_handle) { 371 ldap_unbind_ext_s(ldap_server_handle->ldap_handle, NULL, NULL); 372 ldap_server_handle->ldap_handle = NULL; 373 next_ldap_server_handle = ldap_server_handle->next; 374 krb5_xfree(ldap_server_handle); 375 ldap_server_handle = next_ldap_server_handle; 376 } 377 } 378 krb5_xfree(ldap_context->server_info_list[i]); 379 i++; 380 } 381 krb5_xfree(ldap_context->server_info_list); 382 } 383 384 if (ldap_context->conf_section != NULL) { 385 krb5_xfree(ldap_context->conf_section); 386 ldap_context->conf_section = NULL; 387 } 388 389 if (ldap_context->bind_dn != NULL) { 390 krb5_xfree(ldap_context->bind_dn); 391 ldap_context->bind_dn = NULL; 392 } 393 394 if (ldap_context->bind_pwd != NULL) { 395 krb5_xfree(ldap_context->bind_pwd); 396 ldap_context->bind_pwd = NULL; 397 } 398 399 if (ldap_context->service_password_file != NULL) { 400 krb5_xfree(ldap_context->service_password_file); 401 ldap_context->service_password_file = NULL; 402 } 403 404 /* Solaris Kerberos */ 405 /* #ifdef HAVE_EDIRECTORY */ 406 if (ldap_context->root_certificate_file != NULL) { 407 krb5_xfree(ldap_context->root_certificate_file); 408 ldap_context->root_certificate_file = NULL; 409 } 410 /* #endif */ 411 412 if (ldap_context->service_cert_path != NULL) { 413 krb5_xfree(ldap_context->service_cert_path); 414 ldap_context->service_cert_path = NULL; 415 } 416 417 if (ldap_context->service_cert_pass != NULL) { 418 krb5_xfree(ldap_context->service_cert_pass); 419 ldap_context->service_cert_pass = NULL; 420 } 421 422 if (ldap_context->certificates) { 423 i=0; 424 while (ldap_context->certificates[i] != NULL) { 425 krb5_xfree(ldap_context->certificates[i]->certificate); 426 krb5_xfree(ldap_context->certificates[i]); 427 ++i; 428 } 429 krb5_xfree(ldap_context->certificates); 430 } 431 432 k5_mutex_destroy(&ldap_context->hndl_lock); 433 434 krb5_xfree(ldap_context); 435 return(0); 436 } 437 438 439 /* 440 * check to see if the principal belongs to the default realm. 441 * The default realm is present in the krb5_ldap_context structure. 442 * The principal has a realm portion. This realm portion is compared with the default realm 443 * to check whether the principal belong to the default realm. 444 * Return 0 if principal belongs to default realm else 1. 445 */ 446 447 krb5_error_code 448 is_principal_in_realm(ldap_context, searchfor) 449 krb5_ldap_context *ldap_context; 450 krb5_const_principal searchfor; 451 { 452 size_t defrealmlen=0; 453 char *defrealm=NULL; 454 455 #define FIND_MAX(a,b) ((a) > (b) ? (a) : (b)) 456 457 defrealmlen = strlen(ldap_context->lrparams->realm_name); 458 defrealm = ldap_context->lrparams->realm_name; 459 460 /* 461 * Care should be taken for inter-realm principals as the default 462 * realm can exist in the realm part of the principal name or can 463 * also exist in the second portion of the name part. However, if 464 * the default realm exist in the second part of the principal 465 * portion, then the first portion of the principal name SHOULD be 466 * "krbtgt". All this check is done in the immediate block. 467 */ 468 if (searchfor->length == 2) 469 if ((strncasecmp(searchfor->data[0].data, "krbtgt", 470 FIND_MAX(searchfor->data[0].length, strlen("krbtgt"))) == 0) && 471 (strncasecmp(searchfor->data[1].data, defrealm, 472 FIND_MAX(searchfor->data[1].length, defrealmlen)) == 0)) 473 return 0; 474 475 /* first check the length, if they are not equal, then they are not same */ 476 if (strlen(defrealm) != searchfor->realm.length) 477 return 1; 478 479 /* if the length is equal, check for the contents */ 480 if (strncmp(defrealm, searchfor->realm.data, 481 searchfor->realm.length) != 0) 482 return 1; 483 /* if we are here, then the realm portions match, return 0 */ 484 return 0; 485 } 486 487 488 /* 489 * Deduce the subtree information from the context. A realm can have 490 * multiple subtrees. 491 * 1. the Realm container 492 * 2. the actual subtrees associated with the Realm 493 * 494 * However, there are some conditions to be considered to deduce the 495 * actual subtree/s associated with the realm. The conditions are as 496 * follows: 497 * 1. If the subtree information of the Realm is [Root] or NULL (that 498 * is internal a [Root]) then the realm has only one subtree 499 * i.e [Root], i.e. whole of the tree. 500 * 2. If the subtree information of the Realm is missing/absent, then the 501 * realm has only one, i.e., the Realm container. NOTE: In all cases 502 * Realm container SHOULD be the one among the subtrees or the only 503 * one subtree. 504 * 3. The subtree information of the realm is overlapping the realm 505 * container of the realm, then the realm has only one subtree and 506 * it is the subtree information associated with the realm. 507 */ 508 krb5_error_code 509 krb5_get_subtree_info(ldap_context, subtreearr, ntree) 510 krb5_ldap_context *ldap_context; 511 char ***subtreearr; 512 unsigned int *ntree; 513 { 514 int st=0, i=0, subtreecount=0; 515 int ncount=0, search_scope=0; 516 char **subtree=NULL, *realm_cont_dn=NULL; 517 char **subtarr=NULL; 518 char *containerref=NULL; 519 char **newsubtree=NULL; 520 521 containerref = ldap_context->lrparams->containerref; 522 subtree = ldap_context->lrparams->subtree; 523 realm_cont_dn = ldap_context->lrparams->realmdn; 524 subtreecount = ldap_context->lrparams->subtreecount; 525 search_scope = ldap_context->lrparams->search_scope; 526 527 subtarr = (char **) malloc(sizeof(char *) * (subtreecount + 1 /*realm dn*/ + 1 /*containerref*/ + 1)); 528 if (subtarr == NULL) { 529 st = ENOMEM; 530 goto cleanup; 531 } 532 memset(subtarr, 0, (sizeof(char *) * (subtreecount+1+1+1))); 533 534 /* get the complete subtree list */ 535 for (i=0; i<subtreecount && subtree[i]!=NULL; i++) { 536 subtarr[i] = strdup(subtree[i]); 537 if (subtarr[i] == NULL) { 538 st = ENOMEM; 539 goto cleanup; 540 } 541 } 542 543 subtarr[i] = strdup(realm_cont_dn); 544 if (subtarr[i++] == NULL) { 545 st = ENOMEM; 546 goto cleanup; 547 } 548 549 if (containerref != NULL) { 550 subtarr[i] = strdup(containerref); 551 if (subtarr[i++] == NULL) { 552 st = ENOMEM; 553 goto cleanup; 554 } 555 } 556 557 ncount = i; 558 newsubtree = (char **) malloc(sizeof(char *) * (ncount + 1)); 559 if (newsubtree == NULL) { 560 st = ENOMEM; 561 goto cleanup; 562 } 563 memset(newsubtree, 0, (sizeof(char *) * (ncount+1))); 564 if ((st = remove_overlapping_subtrees(subtarr, newsubtree, &ncount, 565 search_scope)) != 0) { 566 goto cleanup; 567 } 568 569 *ntree = ncount; 570 *subtreearr = newsubtree; 571 572 cleanup: 573 if (subtarr != NULL) { 574 for (i=0; subtarr[i] != NULL; i++) 575 free(subtarr[i]); 576 free(subtarr); 577 } 578 579 if (st != 0) { 580 if (newsubtree != NULL) { 581 for (i=0; newsubtree[i] != NULL; i++) 582 free(newsubtree[i]); 583 free(newsubtree); 584 } 585 } 586 return st; 587 } 588 589 /* 590 * This function appends the content with a type into the tl_data 591 * structure. Based on the type the length of the content is either 592 * pre-defined or computed from the content. Returns 0 in case of 593 * success and 1 if the type associated with the content is undefined. 594 */ 595 596 krb5_error_code 597 store_tl_data(tl_data, tl_type, value) 598 krb5_tl_data *tl_data; 599 int tl_type; 600 void *value; 601 { 602 unsigned int currlen=0, tldatalen=0; 603 unsigned char *curr=NULL; 604 void *reallocptr=NULL; 605 606 tl_data->tl_data_type = KDB_TL_USER_INFO; 607 switch (tl_type) { 608 case KDB_TL_PRINCCOUNT: 609 case KDB_TL_PRINCTYPE: 610 case KDB_TL_MASK: 611 { 612 int *iptr = (int *)value; 613 int ivalue = *iptr; 614 615 currlen = tl_data->tl_data_length; 616 tl_data->tl_data_length += 1 + 2 + 2; 617 /* allocate required memory */ 618 reallocptr = tl_data->tl_data_contents; 619 tl_data->tl_data_contents = realloc(tl_data->tl_data_contents, 620 tl_data->tl_data_length); 621 if (tl_data->tl_data_contents == NULL) { 622 if (reallocptr) 623 free (reallocptr); 624 return ENOMEM; 625 } 626 curr = (tl_data->tl_data_contents + currlen); 627 628 /* store the tl_type value */ 629 memset(curr, tl_type, 1); 630 curr += 1; 631 /* store the content length */ 632 tldatalen = 2; 633 STORE16_INT(curr, tldatalen); 634 curr += 2; 635 /* store the content */ 636 STORE16_INT(curr, ivalue); 637 curr += 2; 638 break; 639 } 640 641 case KDB_TL_USERDN: 642 case KDB_TL_LINKDN: 643 { 644 char *cptr = (char *)value; 645 646 currlen = tl_data->tl_data_length; 647 tl_data->tl_data_length += 1 + 2 + strlen(cptr); 648 /* allocate required memory */ 649 reallocptr = tl_data->tl_data_contents; 650 tl_data->tl_data_contents = realloc(tl_data->tl_data_contents, 651 tl_data->tl_data_length); 652 if (tl_data->tl_data_contents == NULL) { 653 if (reallocptr) 654 free (reallocptr); 655 return ENOMEM; 656 } 657 curr = (tl_data->tl_data_contents + currlen); 658 659 /* store the tl_type value */ 660 memset(curr, tl_type, 1); 661 curr += 1; 662 /* store the content length */ 663 tldatalen = strlen(cptr); 664 STORE16_INT(curr, tldatalen); 665 curr += 2; 666 /* store the content */ 667 memcpy(curr, cptr, tldatalen); 668 curr += tldatalen; 669 break; 670 } 671 672 default: 673 return 1; 674 675 } 676 return 0; 677 } 678 679 /* 680 * This function scans the tl_data structure to get the value of a 681 * type defined by the tl_type (second parameter). The tl_data 682 * structure has all the data in the tl_data_contents member. The 683 * format of the tl_data_contents is as follows. The first byte 684 * defines the type of the content that follows. The next 2 bytes 685 * define the size n (in terms of bytes) of the content that 686 * follows. The next n bytes define the content itself. 687 */ 688 689 krb5_error_code 690 decode_tl_data(tl_data, tl_type, data) 691 krb5_tl_data *tl_data; 692 int tl_type; 693 void **data; 694 { 695 int subtype=0, i=0, limit=10; 696 unsigned int sublen=0; 697 unsigned char *curr=NULL; 698 int *intptr=NULL; 699 long *longptr=NULL; 700 char *DN=NULL, **DNarr=NULL; 701 krb5_error_code st=-1; 702 703 *data = NULL; 704 705 curr = tl_data->tl_data_contents; 706 while (curr < (tl_data->tl_data_contents + tl_data->tl_data_length)) { 707 708 /* get the type of the content */ 709 subtype = (int) curr[0]; 710 /* forward by 1 byte*/ 711 curr += 1; 712 713 if (subtype == tl_type) { 714 switch (subtype) { 715 716 case KDB_TL_PRINCCOUNT: 717 case KDB_TL_PRINCTYPE: 718 case KDB_TL_MASK: 719 /* get the length of the content */ 720 UNSTORE16_INT(curr, sublen); 721 /* forward by 2 bytes */ 722 curr += 2; 723 /* get the actual content */ 724 if (sublen == 2) { 725 /* intptr = malloc(sublen); */ 726 intptr = malloc(sizeof(krb5_int32)); 727 if (intptr == NULL) 728 return ENOMEM; 729 memset(intptr, 0, sublen); 730 UNSTORE16_INT(curr, (*intptr)); 731 *data = intptr; 732 } else { 733 longptr = malloc(sublen); 734 if (longptr == NULL) 735 return ENOMEM; 736 memset(longptr, 0, sublen); 737 UNSTORE32_INT(curr, (*longptr)); 738 *data = longptr; 739 } 740 curr += sublen; 741 st = 0; 742 return st; 743 /*LINTED*/ 744 break; 745 746 case KDB_TL_CONTAINERDN: 747 case KDB_TL_USERDN: 748 /* get the length of the content */ 749 UNSTORE16_INT(curr, sublen); 750 /* forward by 2 bytes */ 751 curr += 2; 752 DN = malloc (sublen + 1); 753 if (DN == NULL) 754 return ENOMEM; 755 memcpy(DN, curr, sublen); 756 DN[sublen] = 0; 757 *data = DN; 758 curr += sublen; 759 st = 0; 760 return st; 761 /*LINTED*/ 762 break; 763 764 case KDB_TL_LINKDN: 765 if (DNarr == NULL) { 766 DNarr = calloc(limit, sizeof(char *)); 767 if (DNarr == NULL) 768 return ENOMEM; 769 } 770 if (i == limit-1) { 771 limit *= 2; 772 DNarr = realloc(DNarr, sizeof(char *) * (limit)); 773 if (DNarr == NULL) 774 return ENOMEM; 775 } 776 777 /* get the length of the content */ 778 UNSTORE16_INT(curr, sublen); 779 /* forward by 2 bytes */ 780 curr += 2; 781 DNarr[i] = malloc (sublen + 1); 782 if (DNarr[i] == NULL) { 783 int j=0; 784 for (; j<i; j++) 785 free(DNarr[j]); 786 free(DNarr); 787 return ENOMEM; 788 } 789 memcpy(DNarr[i], curr, sublen); 790 DNarr[i][sublen] = 0; 791 ++i; 792 curr += sublen; 793 *data = DNarr; 794 st=0; 795 break; 796 } 797 } else { 798 /* move to the current content block */ 799 UNSTORE16_INT(curr, sublen); 800 curr += 2 + sublen; 801 } 802 } 803 return st; 804 } 805 806 /* 807 * wrapper routines for decode_tl_data 808 */ 809 static krb5_error_code 810 krb5_get_int_from_tl_data(context, entries, type, intval) 811 krb5_context context; 812 krb5_db_entry *entries; 813 int type; 814 int *intval; 815 { 816 krb5_error_code st=0; 817 krb5_tl_data tl_data; 818 void *voidptr=NULL; 819 int *intptr=NULL; 820 821 tl_data.tl_data_type = KDB_TL_USER_INFO; 822 if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0) 823 goto cleanup; 824 825 if (decode_tl_data(&tl_data, type, &voidptr) == 0) { 826 intptr = (int *) voidptr; 827 *intval = *intptr; 828 free(intptr); 829 } 830 831 cleanup: 832 return st; 833 } 834 835 /* 836 * Get the mask representing the attributes set on the directory 837 * object (user, policy ...). 838 */ 839 krb5_error_code 840 krb5_get_attributes_mask(context, entries, mask) 841 krb5_context context; 842 krb5_db_entry *entries; 843 unsigned int *mask; 844 { 845 return krb5_get_int_from_tl_data(context, entries, KDB_TL_MASK, 846 (int *)mask); 847 } 848 849 krb5_error_code 850 krb5_get_princ_type(context, entries, ptype) 851 krb5_context context; 852 krb5_db_entry *entries; 853 int *ptype; 854 { 855 return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCTYPE, ptype); 856 } 857 858 krb5_error_code 859 krb5_get_princ_count(context, entries, pcount) 860 krb5_context context; 861 krb5_db_entry *entries; 862 int *pcount; 863 { 864 return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCCOUNT, pcount); 865 } 866 867 krb5_error_code 868 krb5_get_linkdn(context, entries, link_dn) 869 krb5_context context; 870 krb5_db_entry *entries; 871 char ***link_dn; 872 { 873 krb5_error_code st=0; 874 krb5_tl_data tl_data; 875 void *voidptr=NULL; 876 877 *link_dn = NULL; 878 tl_data.tl_data_type = KDB_TL_USER_INFO; 879 if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0) 880 goto cleanup; 881 882 if (decode_tl_data(&tl_data, KDB_TL_LINKDN, &voidptr) == 0) { 883 *link_dn = (char **) voidptr; 884 } 885 886 cleanup: 887 return st; 888 } 889 890 static krb5_error_code 891 krb5_get_str_from_tl_data(context, entries, type, strval) 892 krb5_context context; 893 krb5_db_entry *entries; 894 int type; 895 char **strval; 896 { 897 krb5_error_code st=0; 898 krb5_tl_data tl_data; 899 void *voidptr=NULL; 900 901 if (type != KDB_TL_USERDN && type != KDB_TL_CONTAINERDN) { 902 st = EINVAL; 903 goto cleanup; 904 } 905 906 tl_data.tl_data_type = KDB_TL_USER_INFO; 907 if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0) 908 goto cleanup; 909 910 if (decode_tl_data(&tl_data, type, &voidptr) == 0) { 911 *strval = (char *) voidptr; 912 } 913 914 cleanup: 915 return st; 916 } 917 918 krb5_error_code 919 krb5_get_userdn(context, entries, userdn) 920 krb5_context context; 921 krb5_db_entry *entries; 922 char **userdn; 923 { 924 *userdn = NULL; 925 return krb5_get_str_from_tl_data(context, entries, KDB_TL_USERDN, userdn); 926 } 927 928 krb5_error_code 929 krb5_get_containerdn(context, entries, containerdn) 930 krb5_context context; 931 krb5_db_entry *entries; 932 char **containerdn; 933 { 934 *containerdn = NULL; 935 return krb5_get_str_from_tl_data(context, entries, KDB_TL_CONTAINERDN, containerdn); 936 } 937 938 /* 939 * This function reads the attribute values (if the attribute is 940 * non-null) from the dn. The read attribute values is compared 941 * aganist the attrvalues passed to the function and a bit mask is set 942 * for all the matching attributes (attributes existing in both list). 943 * The bit to be set is selected such that the index of the attribute 944 * in the attrvalues parameter is the position of the bit. For ex: 945 * the first element in the attrvalues is present in both list shall 946 * set the LSB of the bit mask. 947 * 948 * In case if either the attribute or the attrvalues parameter to the 949 * function is NULL, then the existence of the object is considered 950 * and appropriate status is returned back. 951 */ 952 953 krb5_error_code 954 checkattributevalue (ld, dn, attribute, attrvalues, mask) 955 LDAP *ld; 956 char *dn; 957 char *attribute; 958 char **attrvalues; 959 int *mask; 960 { 961 int st=0, one=1; 962 char **values=NULL, *attributes[2] = {NULL}; 963 LDAPMessage *result=NULL, *entry=NULL; 964 965 if (strlen(dn) == 0) { 966 st = set_ldap_error(0, LDAP_NO_SUCH_OBJECT, OP_SEARCH); 967 return st; 968 } 969 970 attributes[0] = attribute; 971 972 /* read the attribute values from the dn */ 973 if ((st = ldap_search_ext_s(ld, 974 dn, 975 LDAP_SCOPE_BASE, 976 0, 977 attributes, 978 0, 979 NULL, 980 NULL, 981 &timelimit, 982 LDAP_NO_LIMIT, 983 &result)) != LDAP_SUCCESS) { 984 st = set_ldap_error(0, st, OP_SEARCH); 985 return st; 986 } 987 988 /* 989 * If the attribute/attrvalues is NULL, then check for the 990 * existence of the object alone. 991 */ 992 if (attribute == NULL || attrvalues == NULL) 993 goto cleanup; 994 995 /* reset the bit mask */ 996 *mask = 0; 997 998 if ((entry=ldap_first_entry(ld, result)) != NULL) { 999 /* read the attribute values */ 1000 if ((values=ldap_get_values(ld, entry, attribute)) != NULL) { 1001 int i,j; 1002 1003 /* 1004 * Compare the read attribute values with the attrvalues 1005 * array and set the appropriate bit mask. 1006 */ 1007 for (j=0; attrvalues[j]; ++j) { 1008 for (i=0; values[i]; ++i) { 1009 if (strcasecmp(values[i], attrvalues[j]) == 0) { 1010 *mask |= (one<<j); 1011 break; 1012 } 1013 } 1014 } 1015 ldap_value_free(values); 1016 } 1017 } 1018 1019 cleanup: 1020 ldap_msgfree(result); 1021 return st; 1022 } 1023 1024 1025 /* 1026 * This function updates a single attribute with a single value of a 1027 * specified dn. This function is mainly used to update 1028 * krbRealmReferences, krbKdcServers, krbAdminServers... when KDC, 1029 * ADMIN, PASSWD servers are associated with some realms or vice 1030 * versa. 1031 */ 1032 1033 krb5_error_code 1034 updateAttribute (ld, dn, attribute, value) 1035 LDAP *ld; 1036 char *dn; 1037 char *attribute; 1038 char *value; 1039 { 1040 int st=0; 1041 LDAPMod modAttr, *mods[2]={NULL}; 1042 char *values[2]={NULL}; 1043 1044 values[0] = value; 1045 1046 /* data to update the {attr,attrval} combination */ 1047 memset(&modAttr, 0, sizeof(modAttr)); 1048 modAttr.mod_type = attribute; 1049 modAttr.mod_op = LDAP_MOD_ADD; 1050 modAttr.mod_values = values; 1051 mods[0] = &modAttr; 1052 1053 /* ldap modify operation */ 1054 st = ldap_modify_ext_s(ld, dn, mods, NULL, NULL); 1055 1056 /* if the {attr,attrval} combination is already present return a success 1057 * LDAP_ALREADY_EXISTS is for single-valued attribute 1058 * LDAP_TYPE_OR_VALUE_EXISTS is for multi-valued attribute 1059 */ 1060 if (st == LDAP_ALREADY_EXISTS || st == LDAP_TYPE_OR_VALUE_EXISTS) 1061 st = 0; 1062 1063 if (st != 0) { 1064 st = set_ldap_error (0, st, OP_MOD); 1065 } 1066 1067 return st; 1068 } 1069 1070 /* 1071 * This function deletes a single attribute with a single value of a 1072 * specified dn. This function is mainly used to delete 1073 * krbRealmReferences, krbKdcServers, krbAdminServers... when KDC, 1074 * ADMIN, PASSWD servers are disassociated with some realms or vice 1075 * versa. 1076 */ 1077 1078 krb5_error_code 1079 deleteAttribute (ld, dn, attribute, value) 1080 LDAP *ld; 1081 char *dn; 1082 char *attribute; 1083 char *value; 1084 { 1085 krb5_error_code st=0; 1086 LDAPMod modAttr, *mods[2]={NULL}; 1087 char *values[2]={NULL}; 1088 1089 values[0] = value; 1090 1091 /* data to delete the {attr,attrval} combination */ 1092 memset(&modAttr, 0, sizeof(modAttr)); 1093 modAttr.mod_type = attribute; 1094 modAttr.mod_op = LDAP_MOD_DELETE; 1095 modAttr.mod_values = values; 1096 mods[0] = &modAttr; 1097 1098 /* ldap modify operation */ 1099 st = ldap_modify_ext_s(ld, dn, mods, NULL, NULL); 1100 1101 /* if either the attribute or the attribute value is missing return a success */ 1102 if (st == LDAP_NO_SUCH_ATTRIBUTE || st == LDAP_UNDEFINED_TYPE) 1103 st = 0; 1104 1105 if (st != 0) { 1106 st = set_ldap_error (0, st, OP_MOD); 1107 } 1108 1109 return st; 1110 } 1111 1112 1113 /* 1114 * This function takes in 2 string arrays, compares them to remove the 1115 * matching entries. The first array is the original list and the 1116 * second array is the modified list. Removing the matching entries 1117 * will result in a reduced array, where the left over first array 1118 * elements are the deleted entries and the left over second array 1119 * elements are the added entries. These additions and deletions has 1120 * resulted in the modified second array. 1121 */ 1122 1123 krb5_error_code 1124 disjoint_members(src, dest) 1125 char **src; 1126 char **dest; 1127 { 1128 int i=0, j=0, slen=0, dlen=0; 1129 1130 /* validate the input parameters */ 1131 if (src == NULL || dest == NULL) 1132 return 0; 1133 1134 /* compute the first array length */ 1135 for (i=0;src[i]; ++i) 1136 ; 1137 1138 /* return if the length is 0 */ 1139 if (i==0) 1140 return 0; 1141 1142 /* index of the last element and also the length of the array */ 1143 slen = i-1; 1144 1145 /* compute the second array length */ 1146 for (i=0;dest[i]; ++i) 1147 ; 1148 1149 /* return if the length is 0 */ 1150 if (i==0) 1151 return 0; 1152 1153 /* index of the last element and also the length of the array */ 1154 dlen = i-1; 1155 1156 /* check for the similar elements and delete them from both the arrays */ 1157 for (i=0; src[i]; ++i) { 1158 1159 for (j=0; dest[j]; ++j) { 1160 1161 /* if the element are same */ 1162 if (strcasecmp(src[i], dest[j]) == 0) { 1163 /* 1164 * If the matched element is in the middle, then copy 1165 * the last element to the matched index. 1166 */ 1167 if (i != slen) { 1168 free (src[i]); 1169 src[i] = src[slen]; 1170 src[slen] = NULL; 1171 } else { 1172 /* 1173 * If the matched element is the last, free it and 1174 * set it to NULL. 1175 */ 1176 free (src[i]); 1177 src[i] = NULL; 1178 } 1179 /* reduce the array length by 1 */ 1180 slen -= 1; 1181 1182 /* repeat the same processing for the second array too */ 1183 if (j != dlen) { 1184 free(dest[j]); 1185 dest[j] = dest[dlen]; 1186 dest[dlen] = NULL; 1187 } else { 1188 free(dest[j]); 1189 dest[j] = NULL; 1190 } 1191 dlen -=1; 1192 1193 /* 1194 * The source array is reduced by 1, so reduce the 1195 * index variable used for source array by 1. No need 1196 * to adjust the second array index variable as it is 1197 * reset while entering the inner loop. 1198 */ 1199 i -= 1; 1200 break; 1201 } 1202 } 1203 } 1204 return 0; 1205 } 1206 1207 /* 1208 * This function replicates the contents of the src array for later 1209 * use. Mostly the contents of the src array is obtained from a 1210 * ldap_search operation and the contents are required for later use. 1211 */ 1212 1213 krb5_error_code 1214 copy_arrays(src, dest, count) 1215 char **src; 1216 char ***dest; 1217 int count; 1218 { 1219 krb5_error_code st=0; 1220 int i=0; 1221 1222 /* validate the input parameters */ 1223 if (src == NULL || dest == NULL) 1224 return 0; 1225 1226 /* allocate memory for the dest array */ 1227 *dest = (char **) calloc((unsigned) count+1, sizeof(char *)); 1228 if (*dest == NULL) { 1229 st = ENOMEM; 1230 goto cleanup; 1231 } 1232 1233 /* copy the members from src to dest array. */ 1234 for (i=0; i < count && src[i] != NULL; ++i) { 1235 (*dest)[i] = strdup(src[i]); 1236 if ((*dest)[i] == NULL) { 1237 st = ENOMEM; 1238 goto cleanup; 1239 } 1240 } 1241 1242 cleanup: 1243 /* in case of error free up everything and return */ 1244 if (st != 0) { 1245 if (*dest != NULL) { 1246 for (i=0; (*dest)[i]; ++i) { 1247 free ((*dest)[i]); 1248 (*dest)[i] = NULL; 1249 } 1250 free (*dest); 1251 *dest = NULL; 1252 } 1253 } 1254 return st; 1255 } 1256 1257 static krb5_error_code 1258 getepochtime(strtime, epochtime) 1259 char *strtime; 1260 krb5_timestamp *epochtime; 1261 { 1262 struct tm tme; 1263 1264 memset(&tme, 0, sizeof(tme)); 1265 if (strptime(strtime, DATE_FORMAT, &tme) == NULL) { 1266 *epochtime = 0; 1267 return EINVAL; 1268 } 1269 1270 *epochtime = krb5int_gmt_mktime(&tme); 1271 1272 return 0; 1273 } 1274 1275 /* 1276 * krb5_ldap_get_value() - get the integer value of the attribute 1277 * Returns, 0 if the attribute is present, 1 if the attribute is missing. 1278 * The retval is 0 if the attribute is missing. 1279 */ 1280 1281 krb5_error_code 1282 krb5_ldap_get_value(ld, ent, attribute, retval) 1283 LDAP *ld; 1284 LDAPMessage *ent; 1285 char *attribute; 1286 int *retval; 1287 { 1288 char **values=NULL; 1289 1290 *retval = 0; 1291 values=ldap_get_values(ld, ent, attribute); 1292 if (values != NULL) { 1293 if (values[0] != NULL) 1294 *retval = atoi(values[0]); 1295 ldap_value_free(values); 1296 return 0; 1297 } 1298 return 1; 1299 } 1300 1301 /* 1302 * krb5_ldap_get_string() - Returns the first string of the 1303 * attribute. Intended to 1304 * 1305 * 1306 */ 1307 krb5_error_code 1308 krb5_ldap_get_string(ld, ent, attribute, retstr, attr_present) 1309 LDAP *ld; 1310 LDAPMessage *ent; 1311 char *attribute; 1312 char **retstr; 1313 krb5_boolean *attr_present; 1314 { 1315 char **values=NULL; 1316 krb5_error_code st=0; 1317 1318 *retstr = NULL; 1319 if (attr_present != NULL) 1320 *attr_present = FALSE; 1321 1322 values=ldap_get_values(ld, ent, attribute); 1323 if (values != NULL) { 1324 if (values[0] != NULL) { 1325 if (attr_present!= NULL) 1326 *attr_present = TRUE; 1327 *retstr = strdup(values[0]); 1328 if (*retstr == NULL) 1329 st = ENOMEM; 1330 } 1331 ldap_value_free(values); 1332 } 1333 return st; 1334 } 1335 1336 /* 1337 * krb5_ldap_get_strings() - Returns all the values 1338 * of the attribute. 1339 */ 1340 krb5_error_code 1341 krb5_ldap_get_strings(ld, ent, attribute, retarr, attr_present) 1342 LDAP *ld; 1343 LDAPMessage *ent; 1344 char *attribute; 1345 char ***retarr; 1346 krb5_boolean *attr_present; 1347 { 1348 char **values=NULL; 1349 krb5_error_code st=0; 1350 unsigned int i=0, count=0; 1351 1352 *retarr = NULL; 1353 if (attr_present != NULL) 1354 *attr_present = FALSE; 1355 1356 values=ldap_get_values(ld, ent, attribute); 1357 if (values != NULL) { 1358 if (attr_present != NULL) 1359 *attr_present = TRUE; 1360 1361 count = ldap_count_values(values); 1362 *retarr = (char **) calloc(count+1, sizeof(char *)); 1363 if (*retarr == NULL) { 1364 st = ENOMEM; 1365 return st; 1366 } 1367 for (i=0; i< count; ++i) { 1368 (*retarr)[i] = strdup(values[i]); 1369 if ((*retarr)[i] == NULL) { 1370 st = ENOMEM; 1371 goto cleanup; 1372 } 1373 } 1374 ldap_value_free(values); 1375 } 1376 1377 cleanup: 1378 if (st != 0) { 1379 if (*retarr != NULL) { 1380 for (i=0; i< count; ++i) 1381 if ((*retarr)[i] != NULL) 1382 free ((*retarr)[i]); 1383 free (*retarr); 1384 } 1385 } 1386 return st; 1387 } 1388 1389 krb5_error_code 1390 krb5_ldap_get_time(ld, ent, attribute, rettime, attr_present) 1391 LDAP *ld; 1392 LDAPMessage *ent; 1393 char *attribute; 1394 krb5_timestamp *rettime; 1395 krb5_boolean *attr_present; 1396 { 1397 char **values=NULL; 1398 krb5_error_code st=0; 1399 1400 *rettime = 0; 1401 *attr_present = FALSE; 1402 1403 values=ldap_get_values(ld, ent, attribute); 1404 if (values != NULL) { 1405 if (values[0] != NULL) { 1406 *attr_present = TRUE; 1407 st = getepochtime(values[0], rettime); 1408 } 1409 ldap_value_free(values); 1410 } 1411 return st; 1412 } 1413 1414 /* 1415 * Function to allocate, set the values of LDAPMod structure. The 1416 * LDAPMod structure is then added to the array at the ind 1417 */ 1418 1419 krb5_error_code 1420 krb5_add_member(mods, count) 1421 LDAPMod ***mods; 1422 int *count; 1423 { 1424 int i=0; 1425 LDAPMod **lmods=NULL; 1426 1427 if ((*mods) != NULL) { 1428 for (;(*mods)[i] != NULL; ++i) 1429 ; 1430 } 1431 lmods = (LDAPMod **) realloc((*mods), (2+i) * sizeof(LDAPMod *)); 1432 if (lmods == NULL) 1433 return ENOMEM; 1434 1435 *mods = lmods; 1436 (*mods)[i+1] = NULL; 1437 (*mods)[i] = (LDAPMod *) calloc(1, sizeof (LDAPMod)); 1438 if ((*mods)[i] == NULL) { 1439 free(lmods); 1440 *mods = NULL; 1441 return ENOMEM; 1442 } 1443 *count = i; 1444 return 0; 1445 } 1446 1447 krb5_error_code 1448 krb5_add_str_mem_ldap_mod(mods, attribute, op, values) 1449 LDAPMod ***mods; 1450 char *attribute; 1451 int op; 1452 char **values; 1453 1454 { 1455 int i=0, j=0; 1456 krb5_error_code st=0; 1457 1458 if ((st=krb5_add_member(mods, &i)) != 0) 1459 return st; 1460 1461 (*mods)[i]->mod_type = strdup(attribute); 1462 if ((*mods)[i]->mod_type == NULL) 1463 return ENOMEM; 1464 (*mods)[i]->mod_op = op; 1465 1466 (*mods)[i]->mod_values = NULL; 1467 1468 if (values != NULL) { 1469 for (j=0; values[j] != NULL; ++j) 1470 ; 1471 (*mods)[i]->mod_values = malloc (sizeof(char *) * (j+1)); 1472 if ((*mods)[i]->mod_values == NULL) { 1473 free((*mods)[i]->mod_type); 1474 (*mods)[i]->mod_type = NULL; 1475 return ENOMEM; 1476 } 1477 1478 for (j=0; values[j] != NULL; ++j) { 1479 (*mods)[i]->mod_values[j] = strdup(values[j]); 1480 if ((*mods)[i]->mod_values[j] == NULL){ 1481 int k=0; 1482 for (; k<j; k++) { 1483 free((*mods)[i]->mod_values[k]); 1484 (*mods)[i]->mod_values[k] = NULL; 1485 } 1486 return ENOMEM; 1487 } 1488 } 1489 (*mods)[i]->mod_values[j] = NULL; 1490 } 1491 return 0; 1492 } 1493 1494 krb5_error_code 1495 krb5_add_ber_mem_ldap_mod(mods, attribute, op, ber_values) 1496 LDAPMod ***mods; 1497 char *attribute; 1498 int op; 1499 struct berval **ber_values; 1500 1501 { 1502 int i=0, j=0; 1503 krb5_error_code st=0; 1504 1505 if ((st=krb5_add_member(mods, &i)) != 0) 1506 return st; 1507 1508 (*mods)[i]->mod_type = strdup(attribute); 1509 if ((*mods)[i]->mod_type == NULL) 1510 return ENOMEM; 1511 (*mods)[i]->mod_op = op; 1512 1513 for (j=0; ber_values[j] != NULL; ++j) 1514 ; 1515 (*mods)[i]->mod_bvalues = malloc (sizeof(struct berval *) * (j+1)); 1516 if ((*mods)[i]->mod_bvalues == NULL) 1517 return ENOMEM; 1518 1519 for (j=0; ber_values[j] != NULL; ++j) { 1520 (*mods)[i]->mod_bvalues[j] = calloc(1, sizeof(struct berval)); 1521 if ((*mods)[i]->mod_bvalues[j] == NULL) 1522 return ENOMEM; 1523 1524 (*mods)[i]->mod_bvalues[j]->bv_len = ber_values[j]->bv_len; 1525 (*mods)[i]->mod_bvalues[j]->bv_val = malloc((*mods)[i]->mod_bvalues[j]->bv_len); 1526 if ((*mods)[i]->mod_bvalues[j]->bv_val == NULL) 1527 return ENOMEM; 1528 1529 memcpy((*mods)[i]->mod_bvalues[j]->bv_val, ber_values[j]->bv_val, 1530 ber_values[j]->bv_len); 1531 } 1532 (*mods)[i]->mod_bvalues[j] = NULL; 1533 return 0; 1534 } 1535 1536 static inline char * 1537 format_d (int val) 1538 { 1539 char tmpbuf[2+3*sizeof(val)]; 1540 sprintf(tmpbuf, "%d", val); 1541 return strdup(tmpbuf); 1542 } 1543 1544 krb5_error_code 1545 krb5_add_int_arr_mem_ldap_mod(mods, attribute, op, value) 1546 LDAPMod ***mods; 1547 char *attribute; 1548 int op; 1549 int *value; 1550 1551 { 1552 int i=0, j=0; 1553 krb5_error_code st=0; 1554 1555 if ((st=krb5_add_member(mods, &i)) != 0) 1556 return st; 1557 1558 (*mods)[i]->mod_type = strdup(attribute); 1559 if ((*mods)[i]->mod_type == NULL) 1560 return ENOMEM; 1561 (*mods)[i]->mod_op = op; 1562 1563 for (j=0; value[j] != -1; ++j) 1564 ; 1565 1566 (*mods)[i]->mod_values = malloc(sizeof(char *) * (j+1)); 1567 1568 for (j=0; value[j] != -1; ++j) { 1569 if (((*mods)[i]->mod_values[j] = format_d(value[j])) == NULL) 1570 return ENOMEM; 1571 } 1572 (*mods)[i]->mod_values[j] = NULL; 1573 return 0; 1574 } 1575 1576 krb5_error_code 1577 krb5_add_int_mem_ldap_mod(mods, attribute, op, value) 1578 LDAPMod ***mods; 1579 char *attribute; 1580 int op; 1581 int value; 1582 1583 { 1584 int i=0; 1585 krb5_error_code st=0; 1586 1587 if ((st=krb5_add_member(mods, &i)) != 0) 1588 return st; 1589 1590 (*mods)[i]->mod_type = strdup(attribute); 1591 if ((*mods)[i]->mod_type == NULL) 1592 return ENOMEM; 1593 1594 (*mods)[i]->mod_op = op; 1595 (*mods)[i]->mod_values = calloc (2, sizeof(char *)); 1596 if (((*mods)[i]->mod_values[0] = format_d(value)) == NULL) 1597 return ENOMEM; 1598 return 0; 1599 } 1600 1601 /*ARGSUSED*/ 1602 krb5_error_code 1603 krb5_ldap_set_option(krb5_context kcontext, int option, void *value) 1604 { 1605 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP; 1606 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status)); 1607 return status; 1608 } 1609 1610 /*ARGSUSED*/ 1611 krb5_error_code 1612 krb5_ldap_lock(krb5_context kcontext, int mode) 1613 { 1614 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP; 1615 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status)); 1616 return status; 1617 } 1618 1619 krb5_error_code 1620 krb5_ldap_unlock(krb5_context kcontext) 1621 { 1622 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP; 1623 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status)); 1624 return status; 1625 } 1626 1627 /*ARGSUSED*/ 1628 krb5_error_code 1629 krb5_ldap_supported_realms(krb5_context kcontext, char **realms) 1630 { 1631 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP; 1632 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status)); 1633 return status; 1634 } 1635 1636 /*ARGSUSED*/ 1637 krb5_error_code 1638 krb5_ldap_free_supported_realms(krb5_context kcontext, char **realms) 1639 { 1640 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP; 1641 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status)); 1642 return status; 1643 } 1644 1645 const char * 1646 krb5_ldap_errcode_2_string(krb5_context kcontext, long err_code) 1647 { 1648 return krb5_get_error_message(kcontext, err_code); 1649 } 1650 1651 void 1652 krb5_ldap_release_errcode_string(krb5_context kcontext, const char *msg) 1653 { 1654 krb5_free_error_message(kcontext, msg); 1655 } 1656 1657 1658 /* 1659 * Get the number of times an object has been referred to in a realm. this is 1660 * needed to find out if deleting the attribute will cause dangling links. 1661 * 1662 * An LDAP handle may be optionally specified to prevent race condition - there 1663 * are a limited number of LDAP handles. 1664 */ 1665 krb5_error_code 1666 krb5_ldap_get_reference_count (krb5_context context, char *dn, char *refattr, 1667 int *count, LDAP *ld) 1668 { 1669 int st = 0, tempst = 0, gothandle = 0; 1670 unsigned int i, ntrees; 1671 char *refcntattr[2]; 1672 char *filter = NULL; 1673 char **subtree = NULL, *ptr = NULL; 1674 kdb5_dal_handle *dal_handle = NULL; 1675 krb5_ldap_context *ldap_context = NULL; 1676 krb5_ldap_server_handle *ldap_server_handle = NULL; 1677 LDAPMessage *result = NULL; 1678 1679 1680 if (dn == NULL || refattr == NULL) { 1681 st = EINVAL; 1682 goto cleanup; 1683 } 1684 1685 SETUP_CONTEXT(); 1686 if (ld == NULL) { 1687 GET_HANDLE(); 1688 gothandle = 1; 1689 } 1690 1691 refcntattr [0] = refattr; 1692 refcntattr [1] = NULL; 1693 1694 ptr = ldap_filter_correct (dn); 1695 if (ptr == NULL) { 1696 st = ENOMEM; 1697 goto cleanup; 1698 } 1699 1700 filter = (char *) malloc (strlen (refattr) + strlen (ptr) + 2); 1701 if (filter == NULL) { 1702 st = ENOMEM; 1703 goto cleanup; 1704 } 1705 1706 /*LINTED*/ 1707 sprintf (filter, "%s=%s", refattr, ptr); 1708 1709 if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0) 1710 goto cleanup; 1711 1712 for (i = 0, *count = 0; i < ntrees; i++) { 1713 int n; 1714 1715 LDAP_SEARCH(subtree[i], 1716 LDAP_SCOPE_SUBTREE, 1717 filter, 1718 refcntattr); 1719 n = ldap_count_entries (ld, result); 1720 if (n == -1) { 1721 int ret, errcode = 0; 1722 ret = ldap_parse_result (ld, result, &errcode, NULL, NULL, NULL, NULL, 0); 1723 if (ret != LDAP_SUCCESS) 1724 errcode = ret; 1725 st = translate_ldap_error (errcode, OP_SEARCH); 1726 goto cleanup; 1727 } 1728 1729 ldap_msgfree(result); 1730 result = NULL; 1731 1732 *count += n; 1733 } 1734 1735 cleanup: 1736 if (filter != NULL) 1737 free (filter); 1738 1739 if (result != NULL) 1740 ldap_msgfree (result); 1741 1742 if (subtree != NULL) { 1743 for (i = 0; i < ntrees; i++) 1744 free (subtree[i]); 1745 free (subtree); 1746 } 1747 1748 if (ptr != NULL) 1749 free (ptr); 1750 1751 if (gothandle == 1) 1752 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); 1753 1754 return st; 1755 } 1756 1757 /* 1758 * For now, policy objects are expected to be directly under the realm 1759 * container. 1760 */ 1761 krb5_error_code krb5_ldap_policydn_to_name (context, policy_dn, name) 1762 krb5_context context; 1763 char *policy_dn; 1764 char **name; 1765 { 1766 int len1, len2; 1767 krb5_error_code st = 0; 1768 kdb5_dal_handle *dal_handle=NULL; 1769 krb5_ldap_context *ldap_context=NULL; 1770 1771 SETUP_CONTEXT(); 1772 1773 if (ldap_context->lrparams->realmdn == NULL) { 1774 st = EINVAL; 1775 goto cleanup; 1776 } 1777 1778 len1 = strlen (ldap_context->lrparams->realmdn); 1779 len2 = strlen (policy_dn); 1780 if (len1 == 0 || len2 == 0 || len1 > len2) { 1781 st = EINVAL; 1782 goto cleanup; 1783 } 1784 1785 if (strcmp (ldap_context->lrparams->realmdn, policy_dn + (len2 - len1)) != 0) { 1786 st = EINVAL; 1787 goto cleanup; 1788 } 1789 1790 #if defined HAVE_LDAP_STR2DN 1791 { 1792 char *rdn; 1793 LDAPDN dn; 1794 rdn = strndup(policy_dn, len2 - len1 - 1); /* 1 character for ',' */ 1795 1796 if (ldap_str2dn (rdn, &dn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PEDANTIC) != 0) { 1797 st = EINVAL; 1798 goto cleanup; 1799 } 1800 if (dn[0] == NULL || dn[1] != NULL) 1801 st = EINVAL; 1802 else if (strcasecmp (dn[0][0]->la_attr.bv_val, "cn") != 0) 1803 st = EINVAL; 1804 else { 1805 *name = strndup(dn[0][0]->la_value.bv_val, dn[0][0]->la_value.bv_len); 1806 if (*name == NULL) 1807 st = EINVAL; 1808 } 1809 1810 ldap_memfree (dn); 1811 } 1812 #elif defined HAVE_LDAP_EXPLODE_DN 1813 { 1814 char **parsed_dn; 1815 1816 /* 1 = return DN components without type prefix */ 1817 parsed_dn = ldap_explode_dn(policy_dn, 1); 1818 if (parsed_dn == NULL) { 1819 st = EINVAL; 1820 } else { 1821 *name = strdup(parsed_dn[0]); 1822 if (*name == NULL) 1823 st = EINVAL; 1824 1825 ldap_value_free(parsed_dn); 1826 } 1827 } 1828 #else 1829 st = EINVAL; 1830 #endif 1831 1832 cleanup: 1833 return st; 1834 } 1835 1836 krb5_error_code krb5_ldap_name_to_policydn (context, name, policy_dn) 1837 krb5_context context; 1838 char *name; 1839 char **policy_dn; 1840 { 1841 int len; 1842 char *ptr = NULL; 1843 krb5_error_code st = 0; 1844 kdb5_dal_handle *dal_handle=NULL; 1845 krb5_ldap_context *ldap_context=NULL; 1846 1847 *policy_dn = NULL; 1848 1849 /* validate the input parameters */ 1850 if (name == NULL) { 1851 st = EINVAL; 1852 goto cleanup; 1853 } 1854 1855 /* Used for removing policy reference from an object */ 1856 if (name[0] == '\0') { 1857 if ((*policy_dn = strdup ("")) == NULL) 1858 st = ENOMEM; 1859 goto cleanup; 1860 } 1861 1862 SETUP_CONTEXT(); 1863 1864 if (ldap_context->lrparams->realmdn == NULL) { 1865 st = EINVAL; 1866 goto cleanup; 1867 } 1868 len = strlen (ldap_context->lrparams->realmdn); 1869 1870 ptr = ldap_filter_correct (name); 1871 if (ptr == NULL) { 1872 st = ENOMEM; 1873 goto cleanup; 1874 } 1875 len += strlen (ptr); 1876 1877 len += sizeof ("cn=") + 3; 1878 1879 *policy_dn = (char *) malloc (len); 1880 if (*policy_dn == NULL) { 1881 st = ENOMEM; 1882 goto cleanup; 1883 } 1884 1885 /*LINTED*/ 1886 sprintf (*policy_dn, "cn=%s,%s", ptr, ldap_context->lrparams->realmdn); 1887 1888 cleanup: 1889 if (ptr != NULL) 1890 free (ptr); 1891 return st; 1892 } 1893 1894 /* remove overlapping and repeated subtree entries from the list of subtrees */ 1895 static krb5_error_code 1896 remove_overlapping_subtrees(char **listin, char **listop, int *subtcount, int sscope) 1897 { 1898 int slen=0, k=0, j=0, lendiff=0; 1899 int count = *subtcount; 1900 char **subtree = listop; 1901 1902 slen = count-1; 1903 for (k=0; k<=slen && listin[k]!=NULL ; k++) { 1904 for (j=k+1; j<=slen && listin[j]!=NULL ;j++) { 1905 lendiff = strlen(listin[k]) - strlen(listin[j]); 1906 if (sscope == 2) { 1907 if ((lendiff > 0) && (strcasecmp((listin[k])+lendiff, listin[j])==0)) { 1908 if (k != slen) { 1909 free(listin[k]); 1910 listin[k] = listin[slen]; 1911 listin[slen] = NULL; 1912 } else { 1913 free(listin[k]); 1914 listin[k] = NULL; 1915 } 1916 slen-=1; 1917 k-=1; 1918 break; 1919 } else if ((lendiff < 0) && (strcasecmp((listin[j])+abs(lendiff), listin[k])==0)) { 1920 if (j != slen) { 1921 free(listin[j]); 1922 listin[j] = listin[slen]; 1923 listin[slen]=NULL; 1924 } else { 1925 free(listin[j]); 1926 listin[j] = NULL; 1927 } 1928 slen-=1; 1929 j-=1; 1930 } 1931 } 1932 if ((lendiff == 0) && (strcasecmp(listin[j], listin[k])==0)) { 1933 if (j != slen) { 1934 free(listin[j]); 1935 listin[j] = listin[slen]; 1936 listin[slen]=NULL; 1937 } else { 1938 free(listin[j]); 1939 listin[j] = NULL; 1940 } 1941 slen -=1; 1942 j-=1; 1943 } 1944 } 1945 } 1946 *subtcount=slen+1; 1947 for (k=0; k<*subtcount && listin[k]!=NULL; k++) { 1948 subtree[k] = strdup(listin[k]); 1949 if (subtree[k] == NULL) { 1950 return ENOMEM; 1951 } 1952 } 1953 return 0; 1954 } 1955 1956 /* 1957 * Fill out a krb5_db_entry princ entry struct given a LDAP message containing 1958 * the results of a principal search of the directory. 1959 */ 1960 krb5_error_code 1961 populate_krb5_db_entry (krb5_context context, 1962 krb5_ldap_context *ldap_context, 1963 LDAP *ld, 1964 LDAPMessage *ent, 1965 krb5_const_principal princ, 1966 krb5_db_entry *entry) 1967 { 1968 krb5_error_code st = 0; 1969 unsigned int mask = 0; 1970 krb5_boolean attr_present = FALSE; 1971 char **values = NULL, *policydn = NULL, *pwdpolicydn = NULL; 1972 char *polname = NULL, *tktpolname = NULL; 1973 struct berval **bvalues = NULL; 1974 krb5_tl_data userinfo_tl_data = {0}; 1975 /* Solaris Kerberos: added next line to fix memleak */ 1976 krb5_tl_data kadm_tl_data = {NULL}; 1977 char **link_references = NULL; 1978 char *DN = NULL; 1979 1980 if (princ == NULL) { 1981 st = EINVAL; 1982 goto cleanup; 1983 } else { 1984 if ((st=krb5_copy_principal(context, princ, &(entry->princ))) != 0) 1985 goto cleanup; 1986 } 1987 /* get the associated directory user information */ 1988 if ((values = ldap_get_values(ld, ent, "krbprincipalname")) != NULL) { 1989 int i, pcount=0, kerberos_principal_object_type=0; 1990 char *user; 1991 1992 if ((st=krb5_unparse_name(context, princ, &user)) != 0) 1993 goto cleanup; 1994 1995 for (i=0; values[i] != NULL; ++i) { 1996 if (strcasecmp(values[i], user) == 0) { 1997 pcount = ldap_count_values(values); 1998 break; 1999 } 2000 } 2001 ldap_value_free(values); 2002 free(user); 2003 2004 if ((DN = ldap_get_dn(ld, ent)) == NULL) { 2005 ldap_get_option(ld, LDAP_OPT_RESULT_CODE, &st); 2006 st = set_ldap_error(context, st, 0); 2007 goto cleanup; 2008 } 2009 2010 if ((values=ldap_get_values(ld, ent, "objectclass")) != NULL) { 2011 for (i=0; values[i] != NULL; ++i) 2012 if (strcasecmp(values[i], "krbprincipal") == 0) { 2013 kerberos_principal_object_type = KDB_STANDALONE_PRINCIPAL_OBJECT; 2014 if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCTYPE, 2015 &kerberos_principal_object_type)) != 0) 2016 goto cleanup; 2017 break; 2018 } 2019 ldap_value_free(values); 2020 } 2021 2022 /* add principalcount, DN and principaltype user information to tl_data */ 2023 if (((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCCOUNT, &pcount)) != 0) || 2024 ((st=store_tl_data(&userinfo_tl_data, KDB_TL_USERDN, DN)) != 0)) 2025 goto cleanup; 2026 } 2027 2028 /* read all the kerberos attributes */ 2029 2030 /* KRBLASTSUCCESSFULAUTH */ 2031 if ((st=krb5_ldap_get_time(ld, ent, "krbLastSuccessfulAuth", 2032 &(entry->last_success), &attr_present)) != 0) 2033 goto cleanup; 2034 if (attr_present == TRUE) 2035 mask |= KDB_LAST_SUCCESS_ATTR; 2036 2037 /* KRBLASTFAILEDAUTH */ 2038 if ((st=krb5_ldap_get_time(ld, ent, "krbLastFailedAuth", 2039 &(entry->last_failed), &attr_present)) != 0) 2040 goto cleanup; 2041 if (attr_present == TRUE) 2042 mask |= KDB_LAST_FAILED_ATTR; 2043 2044 /* KRBLOGINFAILEDCOUNT */ 2045 if (krb5_ldap_get_value(ld, ent, "krbLoginFailedCount", 2046 /* Solaris kerberos: need the cast */ 2047 (int *)&(entry->fail_auth_count)) == 0) 2048 mask |= KDB_FAIL_AUTH_COUNT_ATTR; 2049 2050 /* KRBMAXTICKETLIFE */ 2051 if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", &(entry->max_life)) == 0) 2052 mask |= KDB_MAX_LIFE_ATTR; 2053 2054 /* KRBMAXRENEWABLEAGE */ 2055 if (krb5_ldap_get_value(ld, ent, "krbmaxrenewableage", 2056 &(entry->max_renewable_life)) == 0) 2057 mask |= KDB_MAX_RLIFE_ATTR; 2058 2059 /* KRBTICKETFLAGS */ 2060 if (krb5_ldap_get_value(ld, ent, "krbticketflags", &(entry->attributes)) == 0) 2061 mask |= KDB_TKT_FLAGS_ATTR; 2062 2063 /* PRINCIPAL EXPIRATION TIME */ 2064 if ((st=krb5_ldap_get_time(ld, ent, "krbprincipalexpiration", &(entry->expiration), 2065 &attr_present)) != 0) 2066 goto cleanup; 2067 if (attr_present == TRUE) 2068 mask |= KDB_PRINC_EXPIRE_TIME_ATTR; 2069 2070 /* PASSWORD EXPIRATION TIME */ 2071 if ((st=krb5_ldap_get_time(ld, ent, "krbpasswordexpiration", &(entry->pw_expiration), 2072 &attr_present)) != 0) 2073 goto cleanup; 2074 if (attr_present == TRUE) 2075 mask |= KDB_PWD_EXPIRE_TIME_ATTR; 2076 2077 /* KRBPOLICYREFERENCE */ 2078 2079 if ((st=krb5_ldap_get_string(ld, ent, "krbticketpolicyreference", &policydn, 2080 &attr_present)) != 0) 2081 goto cleanup; 2082 if (attr_present == TRUE) { 2083 mask |= KDB_POL_REF_ATTR; 2084 /* Ensure that the policy is inside the realm container */ 2085 if ((st = krb5_ldap_policydn_to_name (context, policydn, &tktpolname)) != 0) 2086 goto cleanup; 2087 } 2088 2089 /* KRBPWDPOLICYREFERENCE */ 2090 if ((st=krb5_ldap_get_string(ld, ent, "krbpwdpolicyreference", &pwdpolicydn, 2091 &attr_present)) != 0) 2092 goto cleanup; 2093 if (attr_present == TRUE) { 2094 /* Solaris Kerberos: changed this to fix memleak */ 2095 /* krb5_tl_data kadm_tl_data; */ 2096 2097 mask |= KDB_PWD_POL_REF_ATTR; 2098 2099 /* Ensure that the policy is inside the realm container */ 2100 if ((st = krb5_ldap_policydn_to_name (context, pwdpolicydn, &polname)) != 0) 2101 goto cleanup; 2102 2103 /* Solaris Kerberos: adding support for key history in LDAP KDB */ 2104 if ((st = krb5_update_tl_kadm_data(polname, &kadm_tl_data, entry->tl_data)) != 0) { 2105 goto cleanup; 2106 } 2107 krb5_dbe_update_tl_data(context, entry, &kadm_tl_data); 2108 } 2109 2110 /* KRBSECRETKEY */ 2111 if ((bvalues=ldap_get_values_len(ld, ent, "krbprincipalkey")) != NULL) { 2112 mask |= KDB_SECRET_KEY_ATTR; 2113 if ((st=krb5_decode_krbsecretkey(context, entry, bvalues)) != 0) 2114 goto cleanup; 2115 } 2116 2117 /* LAST PASSWORD CHANGE */ 2118 { 2119 krb5_timestamp lstpwdchng=0; 2120 if ((st=krb5_ldap_get_time(ld, ent, "krbLastPwdChange", 2121 &lstpwdchng, &attr_present)) != 0) 2122 goto cleanup; 2123 if (attr_present == TRUE) { 2124 if ((st=krb5_dbe_update_last_pwd_change(context, entry, 2125 lstpwdchng))) 2126 goto cleanup; 2127 mask |= KDB_LAST_PWD_CHANGE_ATTR; 2128 } 2129 } 2130 2131 /* KRBOBJECTREFERENCES */ 2132 { 2133 int i=0; 2134 2135 if ((st = krb5_ldap_get_strings(ld, ent, "krbobjectreferences", 2136 &link_references, &attr_present)) != 0) 2137 goto cleanup; 2138 if (link_references != NULL) { 2139 for (i=0; link_references[i] != NULL; ++i) { 2140 if ((st = store_tl_data(&userinfo_tl_data, KDB_TL_LINKDN, 2141 link_references[i])) != 0) 2142 goto cleanup; 2143 } 2144 } 2145 } 2146 2147 /* Set tl_data */ 2148 { 2149 int i; 2150 struct berval **ber_tl_data = NULL; 2151 krb5_tl_data *ptr = NULL; 2152 2153 if ((ber_tl_data = ldap_get_values_len (ld, ent, "krbExtraData")) != NULL) { 2154 for (i = 0; ber_tl_data[i] != NULL; i++) { 2155 if ((st = berval2tl_data (ber_tl_data[i], &ptr)) != 0) 2156 break; 2157 if ((st = krb5_dbe_update_tl_data(context, entry, ptr)) != 0) 2158 break; 2159 /* Solaris kerberos: fix memory leak */ 2160 if (ptr) { 2161 if (ptr->tl_data_contents) 2162 free(ptr->tl_data_contents); 2163 free(ptr); 2164 ptr = NULL; 2165 } 2166 } 2167 ldap_value_free_len (ber_tl_data); 2168 if (st != 0) 2169 goto cleanup; 2170 mask |= KDB_EXTRA_DATA_ATTR; 2171 } 2172 } 2173 2174 /* update the mask of attributes present on the directory object to the tl_data */ 2175 if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_MASK, &mask)) != 0) 2176 goto cleanup; 2177 if ((st=krb5_dbe_update_tl_data(context, entry, &userinfo_tl_data)) != 0) 2178 goto cleanup; 2179 2180 #ifdef HAVE_EDIRECTORY 2181 { 2182 krb5_timestamp expiretime=0; 2183 char *is_login_disabled=NULL; 2184 2185 /* LOGIN EXPIRATION TIME */ 2186 if ((st=krb5_ldap_get_time(ld, ent, "loginexpirationtime", &expiretime, 2187 &attr_present)) != 0) 2188 goto cleanup; 2189 2190 if (attr_present == TRUE) { 2191 if ((mask & KDB_PRINC_EXPIRE_TIME_ATTR) == 1) { 2192 if (expiretime < entry->expiration) 2193 entry->expiration = expiretime; 2194 } else { 2195 entry->expiration = expiretime; 2196 } 2197 } 2198 2199 /* LOGIN DISABLED */ 2200 if ((st=krb5_ldap_get_string(ld, ent, "logindisabled", &is_login_disabled, 2201 &attr_present)) != 0) 2202 goto cleanup; 2203 if (attr_present == TRUE) { 2204 if (strcasecmp(is_login_disabled, "TRUE")== 0) 2205 entry->attributes |= KRB5_KDB_DISALLOW_ALL_TIX; 2206 free (is_login_disabled); 2207 } 2208 } 2209 #endif 2210 2211 if ((st=krb5_read_tkt_policy (context, ldap_context, entry, tktpolname)) !=0) 2212 goto cleanup; 2213 2214 /* We already know that the policy is inside the realm container. */ 2215 if (polname) { 2216 osa_policy_ent_t pwdpol; 2217 int cnt=0; 2218 krb5_timestamp last_pw_changed; 2219 krb5_ui_4 pw_max_life; 2220 2221 memset(&pwdpol, 0, sizeof(pwdpol)); 2222 2223 if ((st=krb5_ldap_get_password_policy(context, polname, &pwdpol, &cnt)) != 0) 2224 goto cleanup; 2225 pw_max_life = pwdpol->pw_max_life; 2226 /* Solaris Kerberos: fix memory leak */ 2227 krb5_ldap_free_password_policy(context, pwdpol); 2228 2229 if (pw_max_life > 0) { 2230 if ((st=krb5_dbe_lookup_last_pwd_change(context, entry, &last_pw_changed)) != 0) 2231 goto cleanup; 2232 2233 if ((mask & KDB_PWD_EXPIRE_TIME_ATTR) == 1) { 2234 if ((last_pw_changed + pw_max_life) < entry->pw_expiration) 2235 entry->pw_expiration = last_pw_changed + pw_max_life; 2236 } else 2237 entry->pw_expiration = last_pw_changed + pw_max_life; 2238 } 2239 } 2240 /* XXX so krb5_encode_princ_contents() will be happy */ 2241 entry->len = KRB5_KDB_V1_BASE_LENGTH; 2242 2243 cleanup: 2244 2245 if (DN != NULL) 2246 ldap_memfree(DN); 2247 2248 if (userinfo_tl_data.tl_data_contents != NULL) 2249 free(userinfo_tl_data.tl_data_contents); 2250 2251 /* Solaris Kerberos: added this to fix memleak */ 2252 if (kadm_tl_data.tl_data_contents != NULL) 2253 free(kadm_tl_data.tl_data_contents); 2254 2255 if (pwdpolicydn != NULL) 2256 free(pwdpolicydn); 2257 2258 if (polname != NULL) 2259 free(polname); 2260 2261 if (tktpolname != NULL) 2262 free (tktpolname); 2263 2264 if (policydn != NULL) 2265 free(policydn); 2266 2267 if (link_references) { 2268 int i; 2269 for (i=0; link_references[i] != NULL; ++i) 2270 free (link_references[i]); 2271 free (link_references); 2272 } 2273 2274 return (st); 2275 } 2276 2277 /* 2278 * Solaris libldap does not provide the following functions which are in 2279 * OpenLDAP. Note, Solaris Kerberos added the use_SSL to do a SSL init. Also 2280 * added errstr to return specific error if it isn't NULL. Yes, this is ugly 2281 * and no, the errstr should not be free()'ed. 2282 */ 2283 #ifndef HAVE_LDAP_INITIALIZE 2284 int 2285 ldap_initialize(LDAP **ldp, char *url, int use_SSL, char **errstr) 2286 { 2287 int rc = LDAP_SUCCESS; 2288 LDAP *ld = NULL; 2289 LDAPURLDesc *ludp = NULL; 2290 2291 /* For now, we don't use any DN that may be provided. And on 2292 Solaris (based on Mozilla's LDAP client code), we need the 2293 _nodn form to parse "ldap://host" without a trailing slash. 2294 2295 Also, this version won't handle an input string which contains 2296 multiple URLs, unlike the OpenLDAP ldap_initialize. See 2297 https://bugzilla.mozilla.org/show_bug.cgi?id=353336#c1 . */ 2298 2299 /* to avoid reinit and leaking handles, *ldp must be NULL */ 2300 if (*ldp != NULL) 2301 return LDAP_SUCCESS; 2302 2303 #ifdef HAVE_LDAP_URL_PARSE_NODN 2304 rc = ldap_url_parse_nodn(url, &ludp); 2305 #else 2306 rc = ldap_url_parse(url, &ludp); 2307 #endif 2308 if (rc == 0) { 2309 if (use_SSL == SSL_ON) 2310 ld = ldapssl_init(ludp->lud_host, ludp->lud_port, 1); 2311 else 2312 ld = ldap_init(ludp->lud_host, ludp->lud_port); 2313 2314 if (ld != NULL) 2315 *ldp = ld; 2316 else { 2317 if (errstr != NULL) 2318 *errstr = strerror(errno); 2319 rc = LDAP_OPERATIONS_ERROR; 2320 } 2321 2322 ldap_free_urldesc(ludp); 2323 } else { 2324 /* report error from ldap url parsing */ 2325 if (errstr != NULL) 2326 *errstr = ldap_err2string(rc); 2327 /* convert to generic LDAP error */ 2328 rc = LDAP_OPERATIONS_ERROR; 2329 } 2330 return rc; 2331 } 2332 #endif /* HAVE_LDAP_INITIALIZE */ 2333 2334 #ifndef HAVE_LDAP_UNBIND_EXT_S 2335 int 2336 ldap_unbind_ext_s(LDAP *ld, LDAPControl **sctrls, LDAPControl **cctrls) 2337 { 2338 return ldap_unbind_ext(ld, sctrls, cctrls); 2339 } 2340 #endif /* HAVE_LDAP_UNBIND_EXT_S */ 2341