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