1 #pragma ident "%Z%%M% %I% %E% SMI" 2 /* 3 * lib/kdb/kdb_ldap/ldap_misc.c 4 * 5 * Copyright (c) 2004-2005, Novell, Inc. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * * Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * * The copyright holder's name is not used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /* 32 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 33 * Use is subject to license terms. 34 */ 35 #include <string.h> 36 #include <time.h> 37 #include <k5-platform.h> 38 #include "ldap_main.h" 39 #include "ldap_err.h" 40 #include "ldap_principal.h" 41 #include "princ_xdr.h" 42 #include "ldap_pwd_policy.h" 43 #include <libintl.h> 44 45 #ifdef NEED_STRPTIME_PROTO 46 extern char *strptime (const char *, const char *, struct tm *); 47 #endif 48 49 static krb5_error_code 50 remove_overlapping_subtrees(char **listin, char **listop, int *subtcount, 51 int sscope); 52 53 /* Linux (GNU Libc) provides a length-limited variant of strdup. 54 But all the world's not Linux. */ 55 #undef strndup 56 #define strndup my_strndup 57 #ifdef HAVE_LDAP_STR2DN 58 static char *my_strndup (const char *input, size_t limit) 59 { 60 size_t len = strlen(input); 61 char *result; 62 if (len > limit) { 63 result = malloc(1 + limit); 64 if (result != NULL) { 65 memcpy(result, input, limit); 66 result[limit] = 0; 67 } 68 return result; 69 } else 70 return strdup(input); 71 } 72 #endif 73 74 /* Get integer or string values from the config section, falling back 75 to the default section, then to hard-coded values. */ 76 static errcode_t 77 prof_get_integer_def(krb5_context ctx, const char *conf_section, 78 const char *name, int dfl, krb5_ui_4 *out) 79 { 80 errcode_t err; 81 int out_temp = 0; 82 83 err = profile_get_integer (ctx->profile, 84 KDB_MODULE_SECTION, conf_section, name, 85 0, &out_temp); 86 if (err) { 87 krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"), 88 name, error_message(err)); 89 return err; 90 } 91 if (out_temp != 0) { 92 *out = out_temp; 93 return 0; 94 } 95 err = profile_get_integer (ctx->profile, 96 KDB_MODULE_DEF_SECTION, name, 0, 97 dfl, &out_temp); 98 if (err) { 99 krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"), 100 name, error_message(err)); 101 return err; 102 } 103 *out = out_temp; 104 return 0; 105 } 106 107 /* We don't have non-null defaults in any of our calls, so don't 108 bother with the extra argument. */ 109 static errcode_t 110 prof_get_string_def(krb5_context ctx, const char *conf_section, 111 const char *name, char **out) 112 { 113 errcode_t err; 114 115 err = profile_get_string (ctx->profile, 116 KDB_MODULE_SECTION, conf_section, name, 117 0, out); 118 if (err) { 119 krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"), 120 name, error_message(err)); 121 return err; 122 } 123 if (*out != 0) 124 return 0; 125 err = profile_get_string (ctx->profile, 126 KDB_MODULE_DEF_SECTION, name, 0, 127 0, out); 128 if (err) { 129 krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"), 130 name, error_message(err)); 131 return err; 132 } 133 return 0; 134 } 135 136 137 138 /* 139 * This function reads the parameters from the krb5.conf file. The 140 * parameters read here are DAL-LDAP specific attributes. Some of 141 * these are ldap_server .... 142 */ 143 krb5_error_code 144 krb5_ldap_read_server_params(context, conf_section, srv_type) 145 krb5_context context; 146 char *conf_section; 147 int srv_type; 148 { 149 char *tempval=NULL, *save_ptr=NULL; 150 const char *delims="\t\n\f\v\r ,"; 151 krb5_error_code st=0; 152 kdb5_dal_handle *dal_handle=NULL; 153 krb5_ldap_context *ldap_context=NULL; 154 krb5_ldap_server_info ***server_info=NULL; 155 156 dal_handle = (kdb5_dal_handle *) context->db_context; 157 ldap_context = (krb5_ldap_context *) dal_handle->db_context; 158 159 /* copy the conf_section into ldap_context for later use */ 160 if (conf_section) { 161 ldap_context->conf_section = strdup (conf_section); 162 if (ldap_context->conf_section == NULL) { 163 st = ENOMEM; 164 goto cleanup; 165 } 166 } 167 168 /* initialize the mutexs and condition variable */ 169 /* this portion logically doesn't fit here should be moved appropriately */ 170 171 /* this mutex is used in ldap reconnection pool */ 172 if (k5_mutex_init(&(ldap_context->hndl_lock)) != 0) { 173 st = KRB5_KDB_SERVER_INTERNAL_ERR; 174 #if 0 175 st = -1; 176 krb5_ldap_dal_err_funcp(context, krb5_err_have_str, st, 177 "k5_mutex_init failed"); 178 #endif 179 goto cleanup; 180 } 181 182 /* 183 * If max_server_conns is not set read it from database module 184 * section of conf file this parameter defines maximum ldap 185 * connections per ldap server. 186 */ 187 if (ldap_context->max_server_conns == 0) { 188 st = prof_get_integer_def (context, conf_section, 189 "ldap_conns_per_server", 190 DEFAULT_CONNS_PER_SERVER, 191 &ldap_context->max_server_conns); 192 if (st) 193 goto cleanup; 194 } 195 196 if (ldap_context->max_server_conns < 2) { 197 st = EINVAL; 198 krb5_set_error_message (context, st, 199 gettext("Minimum connections required per server is 2")); 200 goto cleanup; 201 } 202 203 /* 204 * If the bind dn is not set read it from the database module 205 * section of conf file this paramter is populated by one of the 206 * KDC, ADMIN or PASSWD dn to be used to connect to LDAP 207 * server. The srv_type decides which dn to read. 208 */ 209 if (ldap_context->bind_dn == NULL) { 210 char *name = 0; 211 if (srv_type == KRB5_KDB_SRV_TYPE_KDC) 212 name = "ldap_kdc_dn"; 213 else if (srv_type == KRB5_KDB_SRV_TYPE_ADMIN) 214 name = "ldap_kadmind_dn"; 215 else if (srv_type == KRB5_KDB_SRV_TYPE_PASSWD) 216 name = "ldap_kpasswdd_dn"; 217 218 if (name) { 219 st = prof_get_string_def (context, conf_section, name, 220 &ldap_context->bind_dn); 221 if (st) 222 goto cleanup; 223 } 224 } 225 226 /* 227 * Read service_password_file parameter from database module 228 * section of conf file this file contains stashed passwords of 229 * the KDC, ADMIN and PASSWD dns. 230 */ 231 if (ldap_context->service_password_file == NULL) { 232 /* 233 * Solaris Kerberos: providing a default. 234 */ 235 st = profile_get_string (context->profile, KDB_MODULE_SECTION, 236 conf_section, 237 "ldap_service_password_file", 238 NULL, 239 &ldap_context->service_password_file); 240 241 if (st) 242 goto cleanup; 243 244 if (ldap_context->service_password_file == NULL) { 245 st = profile_get_string (context->profile, KDB_MODULE_DEF_SECTION, 246 "ldap_service_password_file", 247 NULL, 248 DEF_SERVICE_PASSWD_FILE, 249 &ldap_context->service_password_file); 250 if (st) 251 goto cleanup; 252 } 253 } 254 255 /* 256 * Solaris Kerberos: we must use root_certificate_file 257 * 258 * Note, I've changed the ldap_root_certificate_file config parameter to 259 * ldap_cert_path which is more appropriate for that parameter. 260 */ 261 /* #ifdef HAVE_EDIRECTORY */ 262 /* 263 * If root certificate file is not set read it from database 264 * module section of conf file this is the trusted root 265 * certificate of the Directory. 266 */ 267 if (ldap_context->root_certificate_file == NULL) { 268 st = prof_get_string_def (context, conf_section, 269 "ldap_cert_path", 270 &ldap_context->root_certificate_file); 271 if (st) 272 goto cleanup; 273 } 274 /* #endif */ 275 276 /* 277 * If the ldap server parameter is not set read the list of ldap 278 * servers from the database module section of the conf file. 279 */ 280 281 if (ldap_context->server_info_list == NULL) { 282 unsigned int ele=0; 283 284 server_info = &(ldap_context->server_info_list); 285 *server_info = (krb5_ldap_server_info **) calloc (SERV_COUNT+1, 286 sizeof (krb5_ldap_server_info *)); 287 288 if (*server_info == NULL) { 289 st = ENOMEM; 290 goto cleanup; 291 } 292 293 if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section, 294 "ldap_servers", NULL, &tempval)) != 0) { 295 krb5_set_error_message (context, st, gettext("Error reading 'ldap_servers' attribute")); 296 goto cleanup; 297 } 298 299 if (tempval == NULL) { 300 301 (*server_info)[ele] = (krb5_ldap_server_info *)calloc(1, 302 sizeof(krb5_ldap_server_info)); 303 304 if ((*server_info)[ele] == NULL) { 305 st = ENOMEM; 306 goto cleanup; 307 } 308 (*server_info)[ele]->server_name = strdup("ldapi://"); 309 if ((*server_info)[ele]->server_name == NULL) { 310 st = ENOMEM; 311 goto cleanup; 312 } 313 (*server_info)[ele]->server_status = NOTSET; 314 } else { 315 char *item=NULL; 316 317 item = strtok_r(tempval,delims,&save_ptr); 318 while (item != NULL && ele<SERV_COUNT) { 319 (*server_info)[ele] = (krb5_ldap_server_info *)calloc(1, 320 sizeof(krb5_ldap_server_info)); 321 if ((*server_info)[ele] == NULL) { 322 st = ENOMEM; 323 goto cleanup; 324 } 325 (*server_info)[ele]->server_name = strdup(item); 326 if ((*server_info)[ele]->server_name == NULL) { 327 st = ENOMEM; 328 goto cleanup; 329 } 330 331 (*server_info)[ele]->server_status = NOTSET; 332 item = strtok_r(NULL,delims,&save_ptr); 333 ++ele; 334 } 335 profile_release_string(tempval); 336 } 337 } 338 339 cleanup: 340 return(st); 341 } 342 343 /* 344 * This function frees the krb5_ldap_context structure members. 345 */ 346 347 krb5_error_code 348 krb5_ldap_free_server_params(ldap_context) 349 krb5_ldap_context *ldap_context; 350 { 351 int i=0; 352 krb5_ldap_server_handle *ldap_server_handle=NULL, *next_ldap_server_handle=NULL; 353 354 if (ldap_context == NULL) 355 return 0; 356 357 /* Free all ldap servers list and the ldap handles associated with 358 the ldap server. */ 359 if (ldap_context->server_info_list) { 360 while (ldap_context->server_info_list[i]) { 361 if (ldap_context->server_info_list[i]->server_name) { 362 free (ldap_context->server_info_list[i]->server_name); 363 } 364 #ifdef HAVE_EDIRECTORY 365 if (ldap_context->server_info_list[i]->root_certificate_file) { 366 free (ldap_context->server_info_list[i]->root_certificate_file); 367 } 368 #endif 369 if (ldap_context->server_info_list[i]->ldap_server_handles) { 370 ldap_server_handle = ldap_context->server_info_list[i]->ldap_server_handles; 371 while (ldap_server_handle) { 372 ldap_unbind_ext_s(ldap_server_handle->ldap_handle, NULL, NULL); 373 ldap_server_handle->ldap_handle = NULL; 374 next_ldap_server_handle = ldap_server_handle->next; 375 krb5_xfree(ldap_server_handle); 376 ldap_server_handle = next_ldap_server_handle; 377 } 378 } 379 krb5_xfree(ldap_context->server_info_list[i]); 380 i++; 381 } 382 krb5_xfree(ldap_context->server_info_list); 383 } 384 385 if (ldap_context->conf_section != NULL) { 386 krb5_xfree(ldap_context->conf_section); 387 ldap_context->conf_section = NULL; 388 } 389 390 if (ldap_context->bind_dn != NULL) { 391 krb5_xfree(ldap_context->bind_dn); 392 ldap_context->bind_dn = NULL; 393 } 394 395 if (ldap_context->bind_pwd != NULL) { 396 krb5_xfree(ldap_context->bind_pwd); 397 ldap_context->bind_pwd = NULL; 398 } 399 400 if (ldap_context->service_password_file != NULL) { 401 krb5_xfree(ldap_context->service_password_file); 402 ldap_context->service_password_file = NULL; 403 } 404 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 /* Solaris kerberos: don't have krb5int_gmt_mktime at this point */ 1270 #if 0 /************** Begin IFDEF'ed OUT *******************************/ 1271 *epochtime = krb5int_gmt_mktime(&tme); 1272 #else 1273 *epochtime = gmt_mktime(&tme); 1274 #endif /**************** END IFDEF'ed OUT *******************************/ 1275 return 0; 1276 } 1277 1278 /* 1279 * krb5_ldap_get_value() - get the integer value of the attribute 1280 * Returns, 0 if the attribute is present, 1 if the attribute is missing. 1281 * The retval is 0 if the attribute is missing. 1282 */ 1283 1284 krb5_error_code 1285 krb5_ldap_get_value(ld, ent, attribute, retval) 1286 LDAP *ld; 1287 LDAPMessage *ent; 1288 char *attribute; 1289 int *retval; 1290 { 1291 char **values=NULL; 1292 1293 *retval = 0; 1294 values=ldap_get_values(ld, ent, attribute); 1295 if (values != NULL) { 1296 if (values[0] != NULL) 1297 *retval = atoi(values[0]); 1298 ldap_value_free(values); 1299 return 0; 1300 } 1301 return 1; 1302 } 1303 1304 /* 1305 * krb5_ldap_get_string() - Returns the first string of the 1306 * attribute. Intended to 1307 * 1308 * 1309 */ 1310 krb5_error_code 1311 krb5_ldap_get_string(ld, ent, attribute, retstr, attr_present) 1312 LDAP *ld; 1313 LDAPMessage *ent; 1314 char *attribute; 1315 char **retstr; 1316 krb5_boolean *attr_present; 1317 { 1318 char **values=NULL; 1319 krb5_error_code st=0; 1320 1321 *retstr = NULL; 1322 if (attr_present != NULL) 1323 *attr_present = FALSE; 1324 1325 values=ldap_get_values(ld, ent, attribute); 1326 if (values != NULL) { 1327 if (values[0] != NULL) { 1328 if (attr_present!= NULL) 1329 *attr_present = TRUE; 1330 *retstr = strdup(values[0]); 1331 if (*retstr == NULL) 1332 st = ENOMEM; 1333 } 1334 ldap_value_free(values); 1335 } 1336 return st; 1337 } 1338 1339 /* 1340 * krb5_ldap_get_strings() - Returns all the values 1341 * of the attribute. 1342 */ 1343 krb5_error_code 1344 krb5_ldap_get_strings(ld, ent, attribute, retarr, attr_present) 1345 LDAP *ld; 1346 LDAPMessage *ent; 1347 char *attribute; 1348 char ***retarr; 1349 krb5_boolean *attr_present; 1350 { 1351 char **values=NULL; 1352 krb5_error_code st=0; 1353 unsigned int i=0, count=0; 1354 1355 *retarr = NULL; 1356 if (attr_present != NULL) 1357 *attr_present = FALSE; 1358 1359 values=ldap_get_values(ld, ent, attribute); 1360 if (values != NULL) { 1361 if (attr_present != NULL) 1362 *attr_present = TRUE; 1363 1364 count = ldap_count_values(values); 1365 *retarr = (char **) calloc(count+1, sizeof(char *)); 1366 if (*retarr == NULL) { 1367 st = ENOMEM; 1368 return st; 1369 } 1370 for (i=0; i< count; ++i) { 1371 (*retarr)[i] = strdup(values[i]); 1372 if ((*retarr)[i] == NULL) { 1373 st = ENOMEM; 1374 goto cleanup; 1375 } 1376 } 1377 ldap_value_free(values); 1378 } 1379 1380 cleanup: 1381 if (st != 0) { 1382 if (*retarr != NULL) { 1383 for (i=0; i< count; ++i) 1384 if ((*retarr)[i] != NULL) 1385 free ((*retarr)[i]); 1386 free (*retarr); 1387 } 1388 } 1389 return st; 1390 } 1391 1392 krb5_error_code 1393 krb5_ldap_get_time(ld, ent, attribute, rettime, attr_present) 1394 LDAP *ld; 1395 LDAPMessage *ent; 1396 char *attribute; 1397 krb5_timestamp *rettime; 1398 krb5_boolean *attr_present; 1399 { 1400 char **values=NULL; 1401 krb5_error_code st=0; 1402 1403 *rettime = 0; 1404 *attr_present = FALSE; 1405 1406 values=ldap_get_values(ld, ent, attribute); 1407 if (values != NULL) { 1408 if (values[0] != NULL) { 1409 *attr_present = TRUE; 1410 st = getepochtime(values[0], rettime); 1411 } 1412 ldap_value_free(values); 1413 } 1414 return st; 1415 } 1416 1417 /* 1418 * Function to allocate, set the values of LDAPMod structure. The 1419 * LDAPMod structure is then added to the array at the ind 1420 */ 1421 1422 krb5_error_code 1423 krb5_add_member(mods, count) 1424 LDAPMod ***mods; 1425 int *count; 1426 { 1427 int i=0; 1428 LDAPMod **lmods=NULL; 1429 1430 if ((*mods) != NULL) { 1431 for (;(*mods)[i] != NULL; ++i) 1432 ; 1433 } 1434 lmods = (LDAPMod **) realloc((*mods), (2+i) * sizeof(LDAPMod *)); 1435 if (lmods == NULL) 1436 return ENOMEM; 1437 1438 *mods = lmods; 1439 (*mods)[i+1] = NULL; 1440 (*mods)[i] = (LDAPMod *) calloc(1, sizeof (LDAPMod)); 1441 if ((*mods)[i] == NULL) { 1442 free(lmods); 1443 *mods = NULL; 1444 return ENOMEM; 1445 } 1446 *count = i; 1447 return 0; 1448 } 1449 1450 krb5_error_code 1451 krb5_add_str_mem_ldap_mod(mods, attribute, op, values) 1452 LDAPMod ***mods; 1453 char *attribute; 1454 int op; 1455 char **values; 1456 1457 { 1458 int i=0, j=0; 1459 krb5_error_code st=0; 1460 1461 if ((st=krb5_add_member(mods, &i)) != 0) 1462 return st; 1463 1464 (*mods)[i]->mod_type = strdup(attribute); 1465 if ((*mods)[i]->mod_type == NULL) 1466 return ENOMEM; 1467 (*mods)[i]->mod_op = op; 1468 1469 (*mods)[i]->mod_values = NULL; 1470 1471 if (values != NULL) { 1472 for (j=0; values[j] != NULL; ++j) 1473 ; 1474 (*mods)[i]->mod_values = malloc (sizeof(char *) * (j+1)); 1475 if ((*mods)[i]->mod_values == NULL) { 1476 free((*mods)[i]->mod_type); 1477 (*mods)[i]->mod_type = NULL; 1478 return ENOMEM; 1479 } 1480 1481 for (j=0; values[j] != NULL; ++j) { 1482 (*mods)[i]->mod_values[j] = strdup(values[j]); 1483 if ((*mods)[i]->mod_values[j] == NULL){ 1484 int k=0; 1485 for (; k<j; k++) { 1486 free((*mods)[i]->mod_values[k]); 1487 (*mods)[i]->mod_values[k] = NULL; 1488 } 1489 return ENOMEM; 1490 } 1491 } 1492 (*mods)[i]->mod_values[j] = NULL; 1493 } 1494 return 0; 1495 } 1496 1497 krb5_error_code 1498 krb5_add_ber_mem_ldap_mod(mods, attribute, op, ber_values) 1499 LDAPMod ***mods; 1500 char *attribute; 1501 int op; 1502 struct berval **ber_values; 1503 1504 { 1505 int i=0, j=0; 1506 krb5_error_code st=0; 1507 1508 if ((st=krb5_add_member(mods, &i)) != 0) 1509 return st; 1510 1511 (*mods)[i]->mod_type = strdup(attribute); 1512 if ((*mods)[i]->mod_type == NULL) 1513 return ENOMEM; 1514 (*mods)[i]->mod_op = op; 1515 1516 for (j=0; ber_values[j] != NULL; ++j) 1517 ; 1518 (*mods)[i]->mod_bvalues = malloc (sizeof(struct berval *) * (j+1)); 1519 if ((*mods)[i]->mod_bvalues == NULL) 1520 return ENOMEM; 1521 1522 for (j=0; ber_values[j] != NULL; ++j) { 1523 (*mods)[i]->mod_bvalues[j] = calloc(1, sizeof(struct berval)); 1524 if ((*mods)[i]->mod_bvalues[j] == NULL) 1525 return ENOMEM; 1526 1527 (*mods)[i]->mod_bvalues[j]->bv_len = ber_values[j]->bv_len; 1528 (*mods)[i]->mod_bvalues[j]->bv_val = malloc((*mods)[i]->mod_bvalues[j]->bv_len); 1529 if ((*mods)[i]->mod_bvalues[j]->bv_val == NULL) 1530 return ENOMEM; 1531 1532 memcpy((*mods)[i]->mod_bvalues[j]->bv_val, ber_values[j]->bv_val, 1533 ber_values[j]->bv_len); 1534 } 1535 (*mods)[i]->mod_bvalues[j] = NULL; 1536 return 0; 1537 } 1538 1539 static inline char * 1540 format_d (int val) 1541 { 1542 char tmpbuf[2+3*sizeof(val)]; 1543 sprintf(tmpbuf, "%d", val); 1544 return strdup(tmpbuf); 1545 } 1546 1547 krb5_error_code 1548 krb5_add_int_arr_mem_ldap_mod(mods, attribute, op, value) 1549 LDAPMod ***mods; 1550 char *attribute; 1551 int op; 1552 int *value; 1553 1554 { 1555 int i=0, j=0; 1556 krb5_error_code st=0; 1557 1558 if ((st=krb5_add_member(mods, &i)) != 0) 1559 return st; 1560 1561 (*mods)[i]->mod_type = strdup(attribute); 1562 if ((*mods)[i]->mod_type == NULL) 1563 return ENOMEM; 1564 (*mods)[i]->mod_op = op; 1565 1566 for (j=0; value[j] != -1; ++j) 1567 ; 1568 1569 (*mods)[i]->mod_values = malloc(sizeof(char *) * (j+1)); 1570 1571 for (j=0; value[j] != -1; ++j) { 1572 if (((*mods)[i]->mod_values[j] = format_d(value[j])) == NULL) 1573 return ENOMEM; 1574 } 1575 (*mods)[i]->mod_values[j] = NULL; 1576 return 0; 1577 } 1578 1579 krb5_error_code 1580 krb5_add_int_mem_ldap_mod(mods, attribute, op, value) 1581 LDAPMod ***mods; 1582 char *attribute; 1583 int op; 1584 int value; 1585 1586 { 1587 int i=0; 1588 krb5_error_code st=0; 1589 1590 if ((st=krb5_add_member(mods, &i)) != 0) 1591 return st; 1592 1593 (*mods)[i]->mod_type = strdup(attribute); 1594 if ((*mods)[i]->mod_type == NULL) 1595 return ENOMEM; 1596 1597 (*mods)[i]->mod_op = op; 1598 (*mods)[i]->mod_values = calloc (2, sizeof(char *)); 1599 if (((*mods)[i]->mod_values[0] = format_d(value)) == NULL) 1600 return ENOMEM; 1601 return 0; 1602 } 1603 1604 /*ARGSUSED*/ 1605 krb5_error_code 1606 krb5_ldap_set_option(krb5_context kcontext, int option, void *value) 1607 { 1608 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP; 1609 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status)); 1610 return status; 1611 } 1612 1613 /*ARGSUSED*/ 1614 krb5_error_code 1615 krb5_ldap_lock(krb5_context kcontext, int mode) 1616 { 1617 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP; 1618 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status)); 1619 return status; 1620 } 1621 1622 krb5_error_code 1623 krb5_ldap_unlock(krb5_context kcontext) 1624 { 1625 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP; 1626 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status)); 1627 return status; 1628 } 1629 1630 /*ARGSUSED*/ 1631 krb5_error_code 1632 krb5_ldap_supported_realms(krb5_context kcontext, char **realms) 1633 { 1634 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP; 1635 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status)); 1636 return status; 1637 } 1638 1639 /*ARGSUSED*/ 1640 krb5_error_code 1641 krb5_ldap_free_supported_realms(krb5_context kcontext, char **realms) 1642 { 1643 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP; 1644 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status)); 1645 return status; 1646 } 1647 1648 const char * 1649 krb5_ldap_errcode_2_string(krb5_context kcontext, long err_code) 1650 { 1651 return krb5_get_error_message(kcontext, err_code); 1652 } 1653 1654 void 1655 krb5_ldap_release_errcode_string(krb5_context kcontext, const char *msg) 1656 { 1657 krb5_free_error_message(kcontext, msg); 1658 } 1659 1660 1661 /* 1662 * Get the number of times an object has been referred to in a realm. this is 1663 * needed to find out if deleting the attribute will cause dangling links. 1664 * 1665 * An LDAP handle may be optionally specified to prevent race condition - there 1666 * are a limited number of LDAP handles. 1667 */ 1668 krb5_error_code 1669 krb5_ldap_get_reference_count (krb5_context context, char *dn, char *refattr, 1670 int *count, LDAP *ld) 1671 { 1672 int st = 0, tempst = 0, gothandle = 0; 1673 unsigned int i, ntrees; 1674 char *refcntattr[2]; 1675 char *filter = NULL; 1676 char **subtree = NULL, *ptr = NULL; 1677 kdb5_dal_handle *dal_handle = NULL; 1678 krb5_ldap_context *ldap_context = NULL; 1679 krb5_ldap_server_handle *ldap_server_handle = NULL; 1680 LDAPMessage *result = NULL; 1681 1682 1683 if (dn == NULL || refattr == NULL) { 1684 st = EINVAL; 1685 goto cleanup; 1686 } 1687 1688 SETUP_CONTEXT(); 1689 if (ld == NULL) { 1690 GET_HANDLE(); 1691 gothandle = 1; 1692 } 1693 1694 refcntattr [0] = refattr; 1695 refcntattr [1] = NULL; 1696 1697 ptr = ldap_filter_correct (dn); 1698 if (ptr == NULL) { 1699 st = ENOMEM; 1700 goto cleanup; 1701 } 1702 1703 filter = (char *) malloc (strlen (refattr) + strlen (ptr) + 2); 1704 if (filter == NULL) { 1705 st = ENOMEM; 1706 goto cleanup; 1707 } 1708 1709 /*LINTED*/ 1710 sprintf (filter, "%s=%s", refattr, ptr); 1711 1712 if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0) 1713 goto cleanup; 1714 1715 for (i = 0, *count = 0; i < ntrees; i++) { 1716 int n; 1717 1718 LDAP_SEARCH(subtree[i], 1719 LDAP_SCOPE_SUBTREE, 1720 filter, 1721 refcntattr); 1722 n = ldap_count_entries (ld, result); 1723 if (n == -1) { 1724 int ret, errcode = 0; 1725 ret = ldap_parse_result (ld, result, &errcode, NULL, NULL, NULL, NULL, 0); 1726 if (ret != LDAP_SUCCESS) 1727 errcode = ret; 1728 st = translate_ldap_error (errcode, OP_SEARCH); 1729 goto cleanup; 1730 } 1731 1732 ldap_msgfree(result); 1733 result = NULL; 1734 1735 *count += n; 1736 } 1737 1738 cleanup: 1739 if (filter != NULL) 1740 free (filter); 1741 1742 if (result != NULL) 1743 ldap_msgfree (result); 1744 1745 if (subtree != NULL) { 1746 for (i = 0; i < ntrees; i++) 1747 free (subtree[i]); 1748 free (subtree); 1749 } 1750 1751 if (ptr != NULL) 1752 free (ptr); 1753 1754 if (gothandle == 1) 1755 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); 1756 1757 return st; 1758 } 1759 1760 /* 1761 * For now, policy objects are expected to be directly under the realm 1762 * container. 1763 */ 1764 krb5_error_code krb5_ldap_policydn_to_name (context, policy_dn, name) 1765 krb5_context context; 1766 char *policy_dn; 1767 char **name; 1768 { 1769 int len1, len2; 1770 krb5_error_code st = 0; 1771 kdb5_dal_handle *dal_handle=NULL; 1772 krb5_ldap_context *ldap_context=NULL; 1773 1774 SETUP_CONTEXT(); 1775 1776 if (ldap_context->lrparams->realmdn == NULL) { 1777 st = EINVAL; 1778 goto cleanup; 1779 } 1780 1781 len1 = strlen (ldap_context->lrparams->realmdn); 1782 len2 = strlen (policy_dn); 1783 if (len1 == 0 || len2 == 0 || len1 > len2) { 1784 st = EINVAL; 1785 goto cleanup; 1786 } 1787 1788 if (strcmp (ldap_context->lrparams->realmdn, policy_dn + (len2 - len1)) != 0) { 1789 st = EINVAL; 1790 goto cleanup; 1791 } 1792 1793 #if defined HAVE_LDAP_STR2DN 1794 { 1795 char *rdn; 1796 LDAPDN dn; 1797 rdn = strndup(policy_dn, len2 - len1 - 1); /* 1 character for ',' */ 1798 1799 if (ldap_str2dn (rdn, &dn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PEDANTIC) != 0) { 1800 st = EINVAL; 1801 goto cleanup; 1802 } 1803 if (dn[0] == NULL || dn[1] != NULL) 1804 st = EINVAL; 1805 else if (strcasecmp (dn[0][0]->la_attr.bv_val, "cn") != 0) 1806 st = EINVAL; 1807 else { 1808 *name = strndup(dn[0][0]->la_value.bv_val, dn[0][0]->la_value.bv_len); 1809 if (*name == NULL) 1810 st = EINVAL; 1811 } 1812 1813 ldap_memfree (dn); 1814 } 1815 #elif defined HAVE_LDAP_EXPLODE_DN 1816 { 1817 char **parsed_dn; 1818 1819 /* 1 = return DN components without type prefix */ 1820 parsed_dn = ldap_explode_dn(policy_dn, 1); 1821 if (parsed_dn == NULL) { 1822 st = EINVAL; 1823 } else { 1824 *name = strdup(parsed_dn[0]); 1825 if (*name == NULL) 1826 st = EINVAL; 1827 1828 ldap_value_free(parsed_dn); 1829 } 1830 } 1831 #else 1832 st = EINVAL; 1833 #endif 1834 1835 cleanup: 1836 return st; 1837 } 1838 1839 krb5_error_code krb5_ldap_name_to_policydn (context, name, policy_dn) 1840 krb5_context context; 1841 char *name; 1842 char **policy_dn; 1843 { 1844 int len; 1845 char *ptr = NULL; 1846 krb5_error_code st = 0; 1847 kdb5_dal_handle *dal_handle=NULL; 1848 krb5_ldap_context *ldap_context=NULL; 1849 1850 *policy_dn = NULL; 1851 1852 /* validate the input parameters */ 1853 if (name == NULL) { 1854 st = EINVAL; 1855 goto cleanup; 1856 } 1857 1858 /* Used for removing policy reference from an object */ 1859 if (name[0] == '\0') { 1860 if ((*policy_dn = strdup ("")) == NULL) 1861 st = ENOMEM; 1862 goto cleanup; 1863 } 1864 1865 SETUP_CONTEXT(); 1866 1867 if (ldap_context->lrparams->realmdn == NULL) { 1868 st = EINVAL; 1869 goto cleanup; 1870 } 1871 len = strlen (ldap_context->lrparams->realmdn); 1872 1873 ptr = ldap_filter_correct (name); 1874 if (ptr == NULL) { 1875 st = ENOMEM; 1876 goto cleanup; 1877 } 1878 len += strlen (ptr); 1879 1880 len += sizeof ("cn=") + 3; 1881 1882 *policy_dn = (char *) malloc (len); 1883 if (*policy_dn == NULL) { 1884 st = ENOMEM; 1885 goto cleanup; 1886 } 1887 1888 /*LINTED*/ 1889 sprintf (*policy_dn, "cn=%s,%s", ptr, ldap_context->lrparams->realmdn); 1890 1891 cleanup: 1892 if (ptr != NULL) 1893 free (ptr); 1894 return st; 1895 } 1896 1897 /* remove overlapping and repeated subtree entries from the list of subtrees */ 1898 static krb5_error_code 1899 remove_overlapping_subtrees(char **listin, char **listop, int *subtcount, int sscope) 1900 { 1901 int slen=0, k=0, j=0, lendiff=0; 1902 int count = *subtcount; 1903 char **subtree = listop; 1904 1905 slen = count-1; 1906 for (k=0; k<=slen && listin[k]!=NULL ; k++) { 1907 for (j=k+1; j<=slen && listin[j]!=NULL ;j++) { 1908 lendiff = strlen(listin[k]) - strlen(listin[j]); 1909 if (sscope == 2) { 1910 if ((lendiff > 0) && (strcasecmp((listin[k])+lendiff, listin[j])==0)) { 1911 if (k != slen) { 1912 free(listin[k]); 1913 listin[k] = listin[slen]; 1914 listin[slen] = NULL; 1915 } else { 1916 free(listin[k]); 1917 listin[k] = NULL; 1918 } 1919 slen-=1; 1920 k-=1; 1921 break; 1922 } else if ((lendiff < 0) && (strcasecmp((listin[j])+abs(lendiff), listin[k])==0)) { 1923 if (j != slen) { 1924 free(listin[j]); 1925 listin[j] = listin[slen]; 1926 listin[slen]=NULL; 1927 } else { 1928 free(listin[j]); 1929 listin[j] = NULL; 1930 } 1931 slen-=1; 1932 j-=1; 1933 } 1934 } 1935 if ((lendiff == 0) && (strcasecmp(listin[j], listin[k])==0)) { 1936 if (j != slen) { 1937 free(listin[j]); 1938 listin[j] = listin[slen]; 1939 listin[slen]=NULL; 1940 } else { 1941 free(listin[j]); 1942 listin[j] = NULL; 1943 } 1944 slen -=1; 1945 j-=1; 1946 } 1947 } 1948 } 1949 *subtcount=slen+1; 1950 for (k=0; k<*subtcount && listin[k]!=NULL; k++) { 1951 subtree[k] = strdup(listin[k]); 1952 if (subtree[k] == NULL) { 1953 return ENOMEM; 1954 } 1955 } 1956 return 0; 1957 } 1958 1959 /* 1960 * Fill out a krb5_db_entry princ entry struct given a LDAP message containing 1961 * the results of a principal search of the directory. 1962 */ 1963 krb5_error_code 1964 populate_krb5_db_entry (krb5_context context, 1965 krb5_ldap_context *ldap_context, 1966 LDAP *ld, 1967 LDAPMessage *ent, 1968 krb5_const_principal princ, 1969 krb5_db_entry *entry) 1970 { 1971 krb5_error_code st = 0; 1972 unsigned int mask = 0; 1973 krb5_boolean attr_present = FALSE; 1974 char **values = NULL, *policydn = NULL, *pwdpolicydn = NULL; 1975 char *polname = NULL, *tktpolname = NULL; 1976 struct berval **bvalues = NULL; 1977 krb5_tl_data userinfo_tl_data = {0}; 1978 /* Solaris Kerberos: added next line to fix memleak */ 1979 krb5_tl_data kadm_tl_data = {NULL}; 1980 char **link_references = NULL; 1981 char *DN = NULL; 1982 1983 if (princ == NULL) { 1984 st = EINVAL; 1985 goto cleanup; 1986 } else { 1987 if ((st=krb5_copy_principal(context, princ, &(entry->princ))) != 0) 1988 goto cleanup; 1989 } 1990 /* get the associated directory user information */ 1991 if ((values = ldap_get_values(ld, ent, "krbprincipalname")) != NULL) { 1992 int i, pcount=0, kerberos_principal_object_type=0; 1993 char *user; 1994 1995 if ((st=krb5_unparse_name(context, princ, &user)) != 0) 1996 goto cleanup; 1997 1998 for (i=0; values[i] != NULL; ++i) { 1999 if (strcasecmp(values[i], user) == 0) { 2000 pcount = ldap_count_values(values); 2001 break; 2002 } 2003 } 2004 ldap_value_free(values); 2005 free(user); 2006 2007 if ((DN = ldap_get_dn(ld, ent)) == NULL) { 2008 ldap_get_option(ld, LDAP_OPT_RESULT_CODE, &st); 2009 st = set_ldap_error(context, st, 0); 2010 goto cleanup; 2011 } 2012 2013 if ((values=ldap_get_values(ld, ent, "objectclass")) != NULL) { 2014 for (i=0; values[i] != NULL; ++i) 2015 if (strcasecmp(values[i], "krbprincipal") == 0) { 2016 kerberos_principal_object_type = KDB_STANDALONE_PRINCIPAL_OBJECT; 2017 if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCTYPE, 2018 &kerberos_principal_object_type)) != 0) 2019 goto cleanup; 2020 break; 2021 } 2022 ldap_value_free(values); 2023 } 2024 2025 /* add principalcount, DN and principaltype user information to tl_data */ 2026 if (((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCCOUNT, &pcount)) != 0) || 2027 ((st=store_tl_data(&userinfo_tl_data, KDB_TL_USERDN, DN)) != 0)) 2028 goto cleanup; 2029 } 2030 2031 /* read all the kerberos attributes */ 2032 2033 /* KRBLASTSUCCESSFULAUTH */ 2034 if ((st=krb5_ldap_get_time(ld, ent, "krbLastSuccessfulAuth", 2035 &(entry->last_success), &attr_present)) != 0) 2036 goto cleanup; 2037 if (attr_present == TRUE) 2038 mask |= KDB_LAST_SUCCESS_ATTR; 2039 2040 /* KRBLASTFAILEDAUTH */ 2041 if ((st=krb5_ldap_get_time(ld, ent, "krbLastFailedAuth", 2042 &(entry->last_failed), &attr_present)) != 0) 2043 goto cleanup; 2044 if (attr_present == TRUE) 2045 mask |= KDB_LAST_FAILED_ATTR; 2046 2047 /* KRBLOGINFAILEDCOUNT */ 2048 if (krb5_ldap_get_value(ld, ent, "krbLoginFailedCount", 2049 /* Solaris kerberos: need the cast */ 2050 (int *)&(entry->fail_auth_count)) == 0) 2051 mask |= KDB_FAIL_AUTH_COUNT_ATTR; 2052 2053 /* KRBMAXTICKETLIFE */ 2054 if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", &(entry->max_life)) == 0) 2055 mask |= KDB_MAX_LIFE_ATTR; 2056 2057 /* KRBMAXRENEWABLEAGE */ 2058 if (krb5_ldap_get_value(ld, ent, "krbmaxrenewableage", 2059 &(entry->max_renewable_life)) == 0) 2060 mask |= KDB_MAX_RLIFE_ATTR; 2061 2062 /* KRBTICKETFLAGS */ 2063 if (krb5_ldap_get_value(ld, ent, "krbticketflags", &(entry->attributes)) == 0) 2064 mask |= KDB_TKT_FLAGS_ATTR; 2065 2066 /* PRINCIPAL EXPIRATION TIME */ 2067 if ((st=krb5_ldap_get_time(ld, ent, "krbprincipalexpiration", &(entry->expiration), 2068 &attr_present)) != 0) 2069 goto cleanup; 2070 if (attr_present == TRUE) 2071 mask |= KDB_PRINC_EXPIRE_TIME_ATTR; 2072 2073 /* PASSWORD EXPIRATION TIME */ 2074 if ((st=krb5_ldap_get_time(ld, ent, "krbpasswordexpiration", &(entry->pw_expiration), 2075 &attr_present)) != 0) 2076 goto cleanup; 2077 if (attr_present == TRUE) 2078 mask |= KDB_PWD_EXPIRE_TIME_ATTR; 2079 2080 /* KRBPOLICYREFERENCE */ 2081 2082 if ((st=krb5_ldap_get_string(ld, ent, "krbticketpolicyreference", &policydn, 2083 &attr_present)) != 0) 2084 goto cleanup; 2085 if (attr_present == TRUE) { 2086 mask |= KDB_POL_REF_ATTR; 2087 /* Ensure that the policy is inside the realm container */ 2088 if ((st = krb5_ldap_policydn_to_name (context, policydn, &tktpolname)) != 0) 2089 goto cleanup; 2090 } 2091 2092 /* KRBPWDPOLICYREFERENCE */ 2093 if ((st=krb5_ldap_get_string(ld, ent, "krbpwdpolicyreference", &pwdpolicydn, 2094 &attr_present)) != 0) 2095 goto cleanup; 2096 if (attr_present == TRUE) { 2097 /* Solaris Kerberos: changed this to fix memleak */ 2098 /* krb5_tl_data kadm_tl_data; */ 2099 2100 mask |= KDB_PWD_POL_REF_ATTR; 2101 2102 /* Ensure that the policy is inside the realm container */ 2103 if ((st = krb5_ldap_policydn_to_name (context, pwdpolicydn, &polname)) != 0) 2104 goto cleanup; 2105 2106 /* Solaris Kerberos: adding support for key history in LDAP KDB */ 2107 if ((st = krb5_update_tl_kadm_data(polname, &kadm_tl_data, entry->tl_data)) != 0) { 2108 goto cleanup; 2109 } 2110 krb5_dbe_update_tl_data(context, entry, &kadm_tl_data); 2111 } 2112 2113 /* KRBSECRETKEY */ 2114 if ((bvalues=ldap_get_values_len(ld, ent, "krbprincipalkey")) != NULL) { 2115 mask |= KDB_SECRET_KEY_ATTR; 2116 if ((st=krb5_decode_krbsecretkey(context, entry, bvalues)) != 0) 2117 goto cleanup; 2118 } 2119 2120 /* LAST PASSWORD CHANGE */ 2121 { 2122 krb5_timestamp lstpwdchng=0; 2123 if ((st=krb5_ldap_get_time(ld, ent, "krbLastPwdChange", 2124 &lstpwdchng, &attr_present)) != 0) 2125 goto cleanup; 2126 if (attr_present == TRUE) { 2127 if ((st=krb5_dbe_update_last_pwd_change(context, entry, 2128 lstpwdchng))) 2129 goto cleanup; 2130 mask |= KDB_LAST_PWD_CHANGE_ATTR; 2131 } 2132 } 2133 2134 /* KRBOBJECTREFERENCES */ 2135 { 2136 int i=0; 2137 2138 if ((st = krb5_ldap_get_strings(ld, ent, "krbobjectreferences", 2139 &link_references, &attr_present)) != 0) 2140 goto cleanup; 2141 if (link_references != NULL) { 2142 for (i=0; link_references[i] != NULL; ++i) { 2143 if ((st = store_tl_data(&userinfo_tl_data, KDB_TL_LINKDN, 2144 link_references[i])) != 0) 2145 goto cleanup; 2146 } 2147 } 2148 } 2149 2150 /* Set tl_data */ 2151 { 2152 int i; 2153 struct berval **ber_tl_data = NULL; 2154 krb5_tl_data *ptr = NULL; 2155 2156 if ((ber_tl_data = ldap_get_values_len (ld, ent, "krbExtraData")) != NULL) { 2157 for (i = 0; ber_tl_data[i] != NULL; i++) { 2158 if ((st = berval2tl_data (ber_tl_data[i], &ptr)) != 0) 2159 break; 2160 if ((st = krb5_dbe_update_tl_data(context, entry, ptr)) != 0) 2161 break; 2162 /* Solaris kerberos: fix memory leak */ 2163 if (ptr) { 2164 if (ptr->tl_data_contents) 2165 free(ptr->tl_data_contents); 2166 free(ptr); 2167 ptr = NULL; 2168 } 2169 } 2170 ldap_value_free_len (ber_tl_data); 2171 if (st != 0) 2172 goto cleanup; 2173 mask |= KDB_EXTRA_DATA_ATTR; 2174 } 2175 } 2176 2177 /* update the mask of attributes present on the directory object to the tl_data */ 2178 if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_MASK, &mask)) != 0) 2179 goto cleanup; 2180 if ((st=krb5_dbe_update_tl_data(context, entry, &userinfo_tl_data)) != 0) 2181 goto cleanup; 2182 2183 #ifdef HAVE_EDIRECTORY 2184 { 2185 krb5_timestamp expiretime=0; 2186 char *is_login_disabled=NULL; 2187 2188 /* LOGIN EXPIRATION TIME */ 2189 if ((st=krb5_ldap_get_time(ld, ent, "loginexpirationtime", &expiretime, 2190 &attr_present)) != 0) 2191 goto cleanup; 2192 2193 if (attr_present == TRUE) { 2194 if ((mask & KDB_PRINC_EXPIRE_TIME_ATTR) == 1) { 2195 if (expiretime < entry->expiration) 2196 entry->expiration = expiretime; 2197 } else { 2198 entry->expiration = expiretime; 2199 } 2200 } 2201 2202 /* LOGIN DISABLED */ 2203 if ((st=krb5_ldap_get_string(ld, ent, "logindisabled", &is_login_disabled, 2204 &attr_present)) != 0) 2205 goto cleanup; 2206 if (attr_present == TRUE) { 2207 if (strcasecmp(is_login_disabled, "TRUE")== 0) 2208 entry->attributes |= KRB5_KDB_DISALLOW_ALL_TIX; 2209 free (is_login_disabled); 2210 } 2211 } 2212 #endif 2213 2214 if ((st=krb5_read_tkt_policy (context, ldap_context, entry, tktpolname)) !=0) 2215 goto cleanup; 2216 2217 /* We already know that the policy is inside the realm container. */ 2218 if (polname) { 2219 osa_policy_ent_t pwdpol; 2220 int cnt=0; 2221 krb5_timestamp last_pw_changed; 2222 krb5_ui_4 pw_max_life; 2223 2224 memset(&pwdpol, 0, sizeof(pwdpol)); 2225 2226 if ((st=krb5_ldap_get_password_policy(context, polname, &pwdpol, &cnt)) != 0) 2227 goto cleanup; 2228 pw_max_life = pwdpol->pw_max_life; 2229 /* Solaris Kerberos: fix memory leak */ 2230 krb5_ldap_free_password_policy(context, pwdpol); 2231 2232 if (pw_max_life > 0) { 2233 if ((st=krb5_dbe_lookup_last_pwd_change(context, entry, &last_pw_changed)) != 0) 2234 goto cleanup; 2235 2236 if ((mask & KDB_PWD_EXPIRE_TIME_ATTR) == 1) { 2237 if ((last_pw_changed + pw_max_life) < entry->pw_expiration) 2238 entry->pw_expiration = last_pw_changed + pw_max_life; 2239 } else 2240 entry->pw_expiration = last_pw_changed + pw_max_life; 2241 } 2242 } 2243 /* XXX so krb5_encode_princ_contents() will be happy */ 2244 entry->len = KRB5_KDB_V1_BASE_LENGTH; 2245 2246 cleanup: 2247 2248 if (DN != NULL) 2249 ldap_memfree(DN); 2250 2251 if (userinfo_tl_data.tl_data_contents != NULL) 2252 free(userinfo_tl_data.tl_data_contents); 2253 2254 /* Solaris Kerberos: added this to fix memleak */ 2255 if (kadm_tl_data.tl_data_contents != NULL) 2256 free(kadm_tl_data.tl_data_contents); 2257 2258 if (pwdpolicydn != NULL) 2259 free(pwdpolicydn); 2260 2261 if (polname != NULL) 2262 free(polname); 2263 2264 if (tktpolname != NULL) 2265 free (tktpolname); 2266 2267 if (policydn != NULL) 2268 free(policydn); 2269 2270 if (link_references) { 2271 int i; 2272 for (i=0; link_references[i] != NULL; ++i) 2273 free (link_references[i]); 2274 free (link_references); 2275 } 2276 2277 return (st); 2278 } 2279 2280 /* 2281 * Solaris libldap does not provide the following functions which are in 2282 * OpenLDAP. Note, Solaris Kerberos added the use_SSL to do a SSL init. Also 2283 * added errstr to return specific error if it isn't NULL. Yes, this is ugly 2284 * and no, the errstr should not be free()'ed. 2285 */ 2286 #ifndef HAVE_LDAP_INITIALIZE 2287 int 2288 ldap_initialize(LDAP **ldp, char *url, int use_SSL, char **errstr) 2289 { 2290 int rc = LDAP_SUCCESS; 2291 LDAP *ld = NULL; 2292 LDAPURLDesc *ludp = NULL; 2293 2294 /* For now, we don't use any DN that may be provided. And on 2295 Solaris (based on Mozilla's LDAP client code), we need the 2296 _nodn form to parse "ldap://host" without a trailing slash. 2297 2298 Also, this version won't handle an input string which contains 2299 multiple URLs, unlike the OpenLDAP ldap_initialize. See 2300 https://bugzilla.mozilla.org/show_bug.cgi?id=353336#c1 . */ 2301 2302 /* to avoid reinit and leaking handles, *ldp must be NULL */ 2303 if (*ldp != NULL) 2304 return LDAP_SUCCESS; 2305 2306 #ifdef HAVE_LDAP_URL_PARSE_NODN 2307 rc = ldap_url_parse_nodn(url, &ludp); 2308 #else 2309 rc = ldap_url_parse(url, &ludp); 2310 #endif 2311 if (rc == 0) { 2312 if (use_SSL == SSL_ON) 2313 ld = ldapssl_init(ludp->lud_host, ludp->lud_port, 1); 2314 else 2315 ld = ldap_init(ludp->lud_host, ludp->lud_port); 2316 2317 if (ld != NULL) 2318 *ldp = ld; 2319 else { 2320 if (errstr != NULL) 2321 *errstr = strerror(errno); 2322 rc = LDAP_OPERATIONS_ERROR; 2323 } 2324 2325 ldap_free_urldesc(ludp); 2326 } else { 2327 /* report error from ldap url parsing */ 2328 if (errstr != NULL) 2329 *errstr = ldap_err2string(rc); 2330 /* convert to generic LDAP error */ 2331 rc = LDAP_OPERATIONS_ERROR; 2332 } 2333 return rc; 2334 } 2335 #endif /* HAVE_LDAP_INITIALIZE */ 2336 2337 #ifndef HAVE_LDAP_UNBIND_EXT_S 2338 int 2339 ldap_unbind_ext_s(LDAP *ld, LDAPControl **sctrls, LDAPControl **cctrls) 2340 { 2341 return ldap_unbind_ext(ld, sctrls, cctrls); 2342 } 2343 #endif /* HAVE_LDAP_UNBIND_EXT_S */ 2344