1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2019 Nexenta Systems, Inc. All rights reserved. 24 * Copyright 2023 RackTop Systems, Inc. 25 */ 26 27 28 /* 29 * Config routines common to idmap(8) and idmapd(8) 30 */ 31 32 #include <stdlib.h> 33 #include <strings.h> 34 #include <libintl.h> 35 #include <ctype.h> 36 #include <errno.h> 37 #include <stdio.h> 38 #include <stdarg.h> 39 #include <uuid/uuid.h> 40 #include <pthread.h> 41 #include <port.h> 42 #include <sys/socket.h> 43 #include <net/route.h> 44 #include <sys/u8_textprep.h> 45 #include <netinet/in.h> 46 #include <arpa/inet.h> 47 #include <netdb.h> 48 #include <note.h> 49 #include <limits.h> 50 #include "idmapd.h" 51 #include "addisc.h" 52 53 #define MACHINE_SID_LEN (9 + 3 * 11) 54 #define FMRI_BASE "svc:/system/idmap" 55 #define CONFIG_PG "config" 56 #define DEBUG_PG "debug" 57 #define RECONFIGURE 1 58 #define POKE_AUTO_DISCOVERY 2 59 #define KICK_AUTO_DISCOVERY 3 60 61 /* 62 * Default cache timeouts. Can override via svccfg 63 * config/id_cache_timeout = count: seconds 64 * config/name_cache_timeout = count: seconds 65 */ 66 #define ID_CACHE_TMO_DEFAULT 86400 67 #define NAME_CACHE_TMO_DEFAULT 604800 68 69 /* 70 * Default maximum time between rediscovery runs. 71 * config/rediscovery_interval = count: seconds 72 */ 73 #define REDISCOVERY_INTERVAL_DEFAULT 3600 74 75 /* 76 * Minimum time between rediscovery runs, in case adutils gives us a 77 * really short TTL (which it never should, but be defensive) 78 * (not configurable) seconds. 79 */ 80 #define MIN_REDISCOVERY_INTERVAL 60 81 82 /* 83 * Max number of concurrent door calls 84 */ 85 #define MAX_THREADS_DEFAULT 40 86 87 /* 88 * Number of failed discovery attempts before we mark the service degraded. 89 */ 90 #define DISCOVERY_RETRY_DEGRADE_CUTOFF 6 91 92 /* 93 * Default maximum time between discovery attempts when we don't have a DC. 94 * config/discovery_retry_max_delay = count: seconds 95 */ 96 #define DISCOVERY_RETRY_MAX_DELAY_DEFAULT 30 97 98 /* 99 * Initial retry delay when discovery fails. Doubles on every failure. 100 */ 101 #define DISCOVERY_RETRY_INITIAL_DELAY 1 102 103 enum event_type { 104 EVENT_NOTHING, /* Woke up for no good reason */ 105 EVENT_TIMEOUT, /* Timeout expired */ 106 EVENT_ROUTING, /* An interesting routing event happened */ 107 EVENT_POKED, /* Requested from degrade_svc() */ 108 EVENT_KICKED, /* Force rediscovery, i.e. DC failed. */ 109 EVENT_REFRESH, /* SMF refresh */ 110 }; 111 112 113 static void idmapd_set_krb5_realm(char *); 114 115 static pthread_t update_thread_handle = 0; 116 117 static int idmapd_ev_port = -1; 118 static int rt_sock = -1; 119 120 struct enum_lookup_map directory_mapping_map[] = { 121 { DIRECTORY_MAPPING_NONE, "none" }, 122 { DIRECTORY_MAPPING_NAME, "name" }, 123 { DIRECTORY_MAPPING_IDMU, "idmu" }, 124 { 0, NULL }, 125 }; 126 127 struct enum_lookup_map trust_dir_map[] = { 128 { 1, "they trust us" }, 129 { 2, "we trust them" }, 130 { 3, "we trust each other" }, 131 { 0, NULL }, 132 }; 133 134 static int 135 generate_machine_uuid(char **machine_uuid) 136 { 137 uuid_t uu; 138 139 *machine_uuid = calloc(1, UUID_PRINTABLE_STRING_LENGTH + 1); 140 if (*machine_uuid == NULL) { 141 idmapdlog(LOG_ERR, "Out of memory"); 142 return (-1); 143 } 144 145 uuid_clear(uu); 146 uuid_generate_time(uu); 147 uuid_unparse(uu, *machine_uuid); 148 149 return (0); 150 } 151 152 static int 153 generate_machine_sid(char **machine_sid, char *machine_uuid) 154 { 155 union { 156 uuid_t uu; 157 uint32_t v[4]; 158 } uv; 159 int len; 160 161 /* 162 * Split the 128-bit machine UUID into three 32-bit values 163 * we'll use as the "sub-authorities" of the machine SID. 164 * The machine_sid will have the form S-1-5-21-J-K-L 165 * (that's four sub-authorities altogether) where: 166 * J = last 4 bytes of node_addr, 167 * K = time_mid, time_hi_and_version 168 * L = time_low 169 * (see struct uuid) 170 */ 171 172 (void) memset(&uv, 0, sizeof (uv)); 173 (void) uuid_parse(machine_uuid, uv.uu); 174 175 len = asprintf(machine_sid, "S-1-5-21-%u-%u-%u", 176 uv.v[3], uv.v[0], uv.v[1]); 177 178 if (len == -1 || *machine_sid == NULL) { 179 idmapdlog(LOG_ERR, "Out of memory"); 180 return (-1); 181 } 182 183 return (0); 184 } 185 186 187 /* In the case of error, exists is set to FALSE anyway */ 188 static int 189 prop_exists(idmap_cfg_handles_t *handles, const char *name, boolean_t *exists) 190 { 191 192 scf_property_t *scf_prop; 193 194 *exists = B_FALSE; 195 196 scf_prop = scf_property_create(handles->main); 197 if (scf_prop == NULL) { 198 idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 199 scf_strerror(scf_error())); 200 return (-1); 201 } 202 203 if (scf_pg_get_property(handles->config_pg, name, scf_prop) == 0) 204 *exists = B_TRUE; 205 206 scf_property_destroy(scf_prop); 207 208 return (0); 209 } 210 211 static int 212 get_debug(idmap_cfg_handles_t *handles, const char *name) 213 { 214 int64_t i64 = 0; 215 216 scf_property_t *scf_prop; 217 scf_value_t *value; 218 219 scf_prop = scf_property_create(handles->main); 220 if (scf_prop == NULL) { 221 idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 222 scf_strerror(scf_error())); 223 abort(); 224 } 225 value = scf_value_create(handles->main); 226 if (value == NULL) { 227 idmapdlog(LOG_ERR, "scf_value_create() failed: %s", 228 scf_strerror(scf_error())); 229 abort(); 230 } 231 232 if (scf_pg_get_property(handles->debug_pg, name, scf_prop) < 0) { 233 /* this is OK: the property is just undefined */ 234 goto destruction; 235 } 236 237 238 if (scf_property_get_value(scf_prop, value) < 0) { 239 /* It is still OK when a property doesn't have any value */ 240 goto destruction; 241 } 242 243 if (scf_value_get_integer(value, &i64) != 0) { 244 idmapdlog(LOG_ERR, "Can not retrieve %s/%s: %s", 245 DEBUG_PG, name, scf_strerror(scf_error())); 246 abort(); 247 } 248 249 destruction: 250 scf_value_destroy(value); 251 scf_property_destroy(scf_prop); 252 253 return ((int)i64); 254 } 255 256 static int 257 get_val_bool(idmap_cfg_handles_t *handles, const char *name, 258 boolean_t *val, boolean_t default_val) 259 { 260 int rc = 0; 261 262 scf_property_t *scf_prop; 263 scf_value_t *value; 264 265 *val = default_val; 266 267 scf_prop = scf_property_create(handles->main); 268 if (scf_prop == NULL) { 269 idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 270 scf_strerror(scf_error())); 271 return (-1); 272 } 273 value = scf_value_create(handles->main); 274 if (value == NULL) { 275 idmapdlog(LOG_ERR, "scf_value_create() failed: %s", 276 scf_strerror(scf_error())); 277 scf_property_destroy(scf_prop); 278 return (-1); 279 } 280 281 /* It is OK if the property is undefined */ 282 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) 283 goto destruction; 284 285 286 /* It is still OK when a property doesn't have any value */ 287 if (scf_property_get_value(scf_prop, value) < 0) 288 goto destruction; 289 290 uint8_t b; 291 rc = scf_value_get_boolean(value, &b); 292 293 if (rc == 0) 294 *val = (boolean_t)b; 295 296 destruction: 297 scf_value_destroy(value); 298 scf_property_destroy(scf_prop); 299 300 return (rc); 301 } 302 303 static int 304 get_val_int(idmap_cfg_handles_t *handles, const char *name, 305 void *val, scf_type_t type) 306 { 307 int rc = 0; 308 309 scf_property_t *scf_prop; 310 scf_value_t *value; 311 312 switch (type) { 313 case SCF_TYPE_COUNT: 314 *(uint64_t *)val = 0; 315 break; 316 case SCF_TYPE_INTEGER: 317 *(int64_t *)val = 0; 318 break; 319 default: 320 idmapdlog(LOG_ERR, "Invalid scf integer type (%d)", 321 type); 322 abort(); 323 } 324 325 scf_prop = scf_property_create(handles->main); 326 if (scf_prop == NULL) { 327 idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 328 scf_strerror(scf_error())); 329 return (-1); 330 } 331 value = scf_value_create(handles->main); 332 if (value == NULL) { 333 idmapdlog(LOG_ERR, "scf_value_create() failed: %s", 334 scf_strerror(scf_error())); 335 scf_property_destroy(scf_prop); 336 return (-1); 337 } 338 339 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) 340 /* this is OK: the property is just undefined */ 341 goto destruction; 342 343 344 if (scf_property_get_value(scf_prop, value) < 0) 345 /* It is still OK when a property doesn't have any value */ 346 goto destruction; 347 348 switch (type) { 349 case SCF_TYPE_COUNT: 350 rc = scf_value_get_count(value, val); 351 break; 352 case SCF_TYPE_INTEGER: 353 rc = scf_value_get_integer(value, val); 354 break; 355 default: 356 abort(); /* tested above */ 357 /* NOTREACHED */ 358 } 359 360 if (rc != 0) { 361 idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s", 362 name, scf_strerror(scf_error())); 363 } 364 365 destruction: 366 scf_value_destroy(value); 367 scf_property_destroy(scf_prop); 368 369 return (rc); 370 } 371 372 static char * 373 scf_value2string(const char *name, scf_value_t *value) 374 { 375 static size_t max_val = 0; 376 377 if (max_val == 0) 378 max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 379 380 char buf[max_val + 1]; 381 if (scf_value_get_astring(value, buf, max_val + 1) < 0) { 382 idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s", 383 name, scf_strerror(scf_error())); 384 return (NULL); 385 } 386 387 char *s = strdup(buf); 388 if (s == NULL) 389 idmapdlog(LOG_ERR, "Out of memory"); 390 391 return (s); 392 } 393 394 static int 395 get_val_ds(idmap_cfg_handles_t *handles, const char *name, int defport, 396 ad_disc_ds_t **val) 397 { 398 char port_str[8]; 399 struct addrinfo hints; 400 struct addrinfo *ai; 401 ad_disc_ds_t *servers = NULL; 402 scf_property_t *scf_prop; 403 scf_value_t *value; 404 scf_iter_t *iter; 405 char *host, *portstr; 406 int err, len, i; 407 int count = 0; 408 int rc = -1; 409 410 *val = NULL; 411 412 restart: 413 scf_prop = scf_property_create(handles->main); 414 if (scf_prop == NULL) { 415 idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 416 scf_strerror(scf_error())); 417 return (-1); 418 } 419 420 value = scf_value_create(handles->main); 421 if (value == NULL) { 422 idmapdlog(LOG_ERR, "scf_value_create() failed: %s", 423 scf_strerror(scf_error())); 424 scf_property_destroy(scf_prop); 425 return (-1); 426 } 427 428 iter = scf_iter_create(handles->main); 429 if (iter == NULL) { 430 idmapdlog(LOG_ERR, "scf_iter_create() failed: %s", 431 scf_strerror(scf_error())); 432 scf_value_destroy(value); 433 scf_property_destroy(scf_prop); 434 return (-1); 435 } 436 437 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) { 438 /* this is OK: the property is just undefined */ 439 rc = 0; 440 goto destruction; 441 } 442 443 if (scf_iter_property_values(iter, scf_prop) < 0) { 444 idmapdlog(LOG_ERR, 445 "scf_iter_property_values(%s) failed: %s", 446 name, scf_strerror(scf_error())); 447 goto destruction; 448 } 449 450 /* Workaround scf bugs -- can't reset an iteration */ 451 if (count == 0) { 452 while (scf_iter_next_value(iter, value) > 0) 453 count++; 454 455 if (count == 0) { 456 /* no values */ 457 rc = 0; 458 goto destruction; 459 } 460 461 scf_value_destroy(value); 462 scf_iter_destroy(iter); 463 scf_property_destroy(scf_prop); 464 goto restart; 465 } 466 467 if ((servers = calloc(count + 1, sizeof (*servers))) == NULL) { 468 idmapdlog(LOG_ERR, "Out of memory"); 469 goto destruction; 470 } 471 472 (void) memset(&hints, 0, sizeof (hints)); 473 hints.ai_protocol = IPPROTO_TCP; 474 hints.ai_socktype = SOCK_STREAM; 475 host = NULL; 476 477 i = 0; 478 while (i < count && scf_iter_next_value(iter, value) > 0) { 479 if (host) { 480 free(host); 481 host = NULL; 482 } 483 servers[i].priority = 0; 484 servers[i].weight = 100; 485 servers[i].port = defport; 486 if ((host = scf_value2string(name, value)) == NULL) 487 continue; 488 if ((portstr = strchr(host, ':')) != NULL) { 489 *portstr++ = '\0'; 490 servers[i].port = strtol(portstr, 491 (char **)NULL, 10); 492 if (servers[i].port == 0) 493 servers[i].port = defport; 494 } 495 496 /* 497 * Ignore this server if the hostname is too long 498 * or empty (continue without i++) 499 */ 500 len = strlen(host); 501 if (len == 0) { 502 if (DBG(CONFIG, 1)) { 503 idmapdlog(LOG_INFO, "%s host=\"\"", name); 504 } 505 continue; 506 } 507 if (len >= sizeof (servers->host)) { 508 idmapdlog(LOG_ERR, "Host name too long: %s", host); 509 idmapdlog(LOG_ERR, "ignoring %s value", name); 510 continue; 511 } 512 513 /* 514 * Get the host address too. If we can't, then 515 * log an error and skip this host. 516 */ 517 (void) snprintf(port_str, sizeof (port_str), 518 "%d", servers[i].port); 519 ai = NULL; 520 err = getaddrinfo(host, port_str, &hints, &ai); 521 if (err != 0) { 522 idmapdlog(LOG_ERR, "No address for host: %s (%s)", 523 host, gai_strerror(err)); 524 idmapdlog(LOG_ERR, "ignoring %s value", name); 525 continue; 526 } 527 528 (void) strlcpy(servers[i].host, host, 529 sizeof (servers->host)); 530 (void) memcpy(&servers[i].addr, ai->ai_addr, ai->ai_addrlen); 531 freeaddrinfo(ai); 532 533 /* Added a DS to the array. */ 534 i++; 535 } 536 free(host); 537 538 if (i == 0) { 539 if (DBG(CONFIG, 1)) { 540 idmapdlog(LOG_INFO, "%s is empty", name); 541 } 542 free(servers); 543 servers = NULL; 544 } 545 *val = servers; 546 547 rc = 0; 548 549 destruction: 550 scf_value_destroy(value); 551 scf_iter_destroy(iter); 552 scf_property_destroy(scf_prop); 553 554 if (rc < 0) { 555 if (servers) 556 free(servers); 557 *val = NULL; 558 } 559 560 return (rc); 561 } 562 563 static int 564 get_val_astring(idmap_cfg_handles_t *handles, const char *name, char **val) 565 { 566 int rc = 0; 567 568 scf_property_t *scf_prop; 569 scf_value_t *value; 570 571 scf_prop = scf_property_create(handles->main); 572 if (scf_prop == NULL) { 573 idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 574 scf_strerror(scf_error())); 575 return (-1); 576 } 577 value = scf_value_create(handles->main); 578 if (value == NULL) { 579 idmapdlog(LOG_ERR, "scf_value_create() failed: %s", 580 scf_strerror(scf_error())); 581 scf_property_destroy(scf_prop); 582 return (-1); 583 } 584 585 *val = NULL; 586 587 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) 588 /* this is OK: the property is just undefined */ 589 goto destruction; 590 591 if (scf_property_get_value(scf_prop, value) < 0) { 592 idmapdlog(LOG_ERR, 593 "scf_property_get_value(%s) failed: %s", 594 name, scf_strerror(scf_error())); 595 rc = -1; 596 goto destruction; 597 } 598 599 *val = scf_value2string(name, value); 600 if (*val == NULL) 601 rc = -1; 602 603 destruction: 604 scf_value_destroy(value); 605 scf_property_destroy(scf_prop); 606 607 if (rc < 0) { 608 if (*val) 609 free(*val); 610 *val = NULL; 611 } 612 613 return (rc); 614 } 615 616 617 static int 618 del_val( 619 idmap_cfg_handles_t *handles, 620 scf_propertygroup_t *pg, 621 const char *name) 622 { 623 int rc = -1; 624 int ret; 625 scf_transaction_t *tx = NULL; 626 scf_transaction_entry_t *ent = NULL; 627 628 if ((tx = scf_transaction_create(handles->main)) == NULL) { 629 idmapdlog(LOG_ERR, 630 "scf_transaction_create() failed: %s", 631 scf_strerror(scf_error())); 632 goto destruction; 633 } 634 if ((ent = scf_entry_create(handles->main)) == NULL) { 635 idmapdlog(LOG_ERR, 636 "scf_entry_create() failed: %s", 637 scf_strerror(scf_error())); 638 goto destruction; 639 } 640 641 do { 642 if (scf_pg_update(pg) == -1) { 643 idmapdlog(LOG_ERR, 644 "scf_pg_update(%s) failed: %s", 645 name, scf_strerror(scf_error())); 646 goto destruction; 647 } 648 if (scf_transaction_start(tx, pg) != 0) { 649 idmapdlog(LOG_ERR, 650 "scf_transaction_start(%s) failed: %s", 651 name, scf_strerror(scf_error())); 652 goto destruction; 653 } 654 655 if (scf_transaction_property_delete(tx, ent, name) != 0) { 656 /* Don't complain if it already doesn't exist. */ 657 if (scf_error() != SCF_ERROR_NOT_FOUND) { 658 idmapdlog(LOG_ERR, 659 "scf_transaction_property_delete() failed:" 660 " %s", 661 scf_strerror(scf_error())); 662 } 663 goto destruction; 664 } 665 666 ret = scf_transaction_commit(tx); 667 668 if (ret == 0) 669 scf_transaction_reset(tx); 670 } while (ret == 0); 671 672 if (ret == -1) { 673 idmapdlog(LOG_ERR, 674 "scf_transaction_commit(%s) failed: %s", 675 name, scf_strerror(scf_error())); 676 goto destruction; 677 } 678 679 rc = 0; 680 681 destruction: 682 if (ent != NULL) 683 scf_entry_destroy(ent); 684 if (tx != NULL) 685 scf_transaction_destroy(tx); 686 return (rc); 687 } 688 689 690 static int 691 set_val( 692 idmap_cfg_handles_t *handles, 693 scf_propertygroup_t *pg, 694 const char *name, 695 scf_value_t *value) 696 { 697 int rc = -1; 698 int i; 699 scf_property_t *prop = NULL; 700 scf_transaction_t *tx = NULL; 701 scf_transaction_entry_t *ent = NULL; 702 703 if ((prop = scf_property_create(handles->main)) == NULL || 704 (tx = scf_transaction_create(handles->main)) == NULL || 705 (ent = scf_entry_create(handles->main)) == NULL) { 706 idmapdlog(LOG_ERR, "Unable to set property %s", 707 name, scf_strerror(scf_error())); 708 goto destruction; 709 } 710 711 for (i = 0; i < MAX_TRIES; i++) { 712 int ret; 713 714 if (scf_pg_update(pg) == -1) { 715 idmapdlog(LOG_ERR, 716 "scf_pg_update() failed: %s", 717 scf_strerror(scf_error())); 718 goto destruction; 719 } 720 721 if (scf_transaction_start(tx, pg) == -1) { 722 idmapdlog(LOG_ERR, 723 "scf_transaction_start(%s) failed: %s", 724 name, scf_strerror(scf_error())); 725 goto destruction; 726 } 727 728 ret = scf_pg_get_property(pg, name, prop); 729 if (ret == SCF_SUCCESS) { 730 if (scf_transaction_property_change_type(tx, ent, name, 731 scf_value_type(value)) < 0) { 732 idmapdlog(LOG_ERR, 733 "scf_transaction_property_change_type(%s)" 734 " failed: %s", 735 name, scf_strerror(scf_error())); 736 goto destruction; 737 } 738 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 739 if (scf_transaction_property_new(tx, ent, name, 740 scf_value_type(value)) < 0) { 741 idmapdlog(LOG_ERR, 742 "scf_transaction_property_new() failed: %s", 743 scf_strerror(scf_error())); 744 goto destruction; 745 } 746 } else { 747 idmapdlog(LOG_ERR, 748 "scf_pg_get_property(%s) failed: %s", 749 name, scf_strerror(scf_error())); 750 goto destruction; 751 } 752 753 if (scf_entry_add_value(ent, value) == -1) { 754 idmapdlog(LOG_ERR, 755 "scf_entry_add_value() failed: %s", 756 scf_strerror(scf_error())); 757 goto destruction; 758 } 759 760 ret = scf_transaction_commit(tx); 761 if (ret == 0) { 762 /* 763 * Property group set in scf_transaction_start() 764 * is not the most recent. Update pg, reset tx and 765 * retry tx. 766 */ 767 idmapdlog(LOG_WARNING, 768 "scf_transaction_commit(%s) failed: %s", 769 name, scf_strerror(scf_error())); 770 scf_transaction_reset(tx); 771 continue; 772 } 773 if (ret != 1) { 774 idmapdlog(LOG_ERR, 775 "scf_transaction_commit(%s) failed: %s", 776 name, scf_strerror(scf_error())); 777 goto destruction; 778 } 779 /* Success! */ 780 rc = 0; 781 break; 782 } 783 784 destruction: 785 scf_entry_destroy(ent); 786 scf_transaction_destroy(tx); 787 scf_property_destroy(prop); 788 return (rc); 789 } 790 791 static int 792 set_val_integer( 793 idmap_cfg_handles_t *handles, 794 scf_propertygroup_t *pg, 795 const char *name, 796 int64_t val) 797 { 798 scf_value_t *value = NULL; 799 int rc; 800 801 if ((value = scf_value_create(handles->main)) == NULL) { 802 idmapdlog(LOG_ERR, "Unable to set property %s", 803 name, scf_strerror(scf_error())); 804 return (-1); 805 } 806 807 scf_value_set_integer(value, val); 808 809 rc = set_val(handles, pg, name, value); 810 811 scf_value_destroy(value); 812 813 return (rc); 814 } 815 816 817 static int 818 set_val_astring( 819 idmap_cfg_handles_t *handles, 820 scf_propertygroup_t *pg, 821 const char *name, 822 const char *val) 823 { 824 scf_value_t *value = NULL; 825 int rc = -1; 826 827 if ((value = scf_value_create(handles->main)) == NULL) { 828 idmapdlog(LOG_ERR, "Unable to set property %s", 829 name, scf_strerror(scf_error())); 830 goto out; 831 } 832 833 if (scf_value_set_astring(value, val) == -1) { 834 idmapdlog(LOG_ERR, 835 "scf_value_set_astring() failed: %s", 836 scf_strerror(scf_error())); 837 goto out; 838 } 839 840 rc = set_val(handles, pg, name, value); 841 842 out: 843 scf_value_destroy(value); 844 return (rc); 845 } 846 847 848 849 /* 850 * This function updates a boolean value. 851 * If nothing has changed it returns 0 else 1 852 */ 853 static int 854 update_bool(boolean_t *value, boolean_t *new, char *name) 855 { 856 if (*value == *new) 857 return (0); 858 859 if (DBG(CONFIG, 1)) { 860 idmapdlog(LOG_INFO, "change %s=%s", name, 861 *new ? "true" : "false"); 862 } 863 864 *value = *new; 865 return (1); 866 } 867 868 /* 869 * This function updates a uint64_t value. 870 * If nothing has changed it returns 0 else 1 871 */ 872 static int 873 update_uint64(uint64_t *value, uint64_t *new, char *name) 874 { 875 if (*value == *new) 876 return (0); 877 878 if (DBG(CONFIG, 1)) 879 idmapdlog(LOG_INFO, "change %s=%llu", name, *new); 880 881 *value = *new; 882 return (1); 883 } 884 885 /* 886 * This function updates a string value. 887 * If nothing has changed it returns 0 else 1 888 */ 889 static int 890 update_string(char **value, char **new, char *name) 891 { 892 int changed; 893 894 if (*new == NULL && *value != NULL) 895 changed = 1; 896 else if (*new != NULL && *value == NULL) 897 changed = 1; 898 else if (*new != NULL && *value != NULL && strcmp(*new, *value) != 0) 899 changed = 1; 900 else 901 changed = 0; 902 903 /* 904 * Note that even if unchanged we can't just return; we must free one 905 * of the values. 906 */ 907 908 if (DBG(CONFIG, 1) && changed) 909 idmapdlog(LOG_INFO, "change %s=%s", name, CHECK_NULL(*new)); 910 911 free(*value); 912 *value = *new; 913 *new = NULL; 914 return (changed); 915 } 916 917 static int 918 update_enum(int *value, int *new, char *name, struct enum_lookup_map *map) 919 { 920 if (*value == *new) 921 return (0); 922 923 if (DBG(CONFIG, 1)) { 924 idmapdlog(LOG_INFO, "change %s=%s", name, 925 enum_lookup(*new, map)); 926 } 927 928 *value = *new; 929 930 return (1); 931 } 932 933 /* 934 * This function updates a directory service structure. 935 * If nothing has changed it returns 0 else 1 936 */ 937 static int 938 update_dirs(ad_disc_ds_t **value, ad_disc_ds_t **new, char *name) 939 { 940 941 if (*value == *new) 942 /* Nothing to do */ 943 return (0); 944 945 if (*value != NULL && *new != NULL && 946 ad_disc_compare_ds(*value, *new) == 0) { 947 free(*new); 948 *new = NULL; 949 return (0); 950 } 951 952 if (*value != NULL) 953 free(*value); 954 955 *value = *new; 956 *new = NULL; 957 958 if (*value == NULL) { 959 /* We're unsetting this DS property */ 960 if (DBG(CONFIG, 1)) 961 idmapdlog(LOG_INFO, "change %s=<none>", name); 962 return (1); 963 } 964 965 if (DBG(CONFIG, 1)) { 966 /* List all the new DSs */ 967 char buf[64]; 968 ad_disc_ds_t *ds; 969 for (ds = *value; ds->host[0] != '\0'; ds++) { 970 if (ad_disc_getnameinfo(buf, sizeof (buf), &ds->addr)) 971 (void) strlcpy(buf, "?", sizeof (buf)); 972 idmapdlog(LOG_INFO, "change %s=%s addr=%s port=%d", 973 name, ds->host, buf, ds->port); 974 } 975 } 976 return (1); 977 } 978 979 /* 980 * This function updates a trusted domains structure. 981 * If nothing has changed it returns 0 else 1 982 */ 983 static int 984 update_trusted_domains(ad_disc_trusteddomains_t **value, 985 ad_disc_trusteddomains_t **new, char *name) 986 { 987 int i; 988 989 if (*value == *new) 990 /* Nothing to do */ 991 return (0); 992 993 if (*value != NULL && *new != NULL && 994 ad_disc_compare_trusteddomains(*value, *new) == 0) { 995 free(*new); 996 *new = NULL; 997 return (0); 998 } 999 1000 if (*value != NULL) 1001 free(*value); 1002 1003 *value = *new; 1004 *new = NULL; 1005 1006 if (*value == NULL) { 1007 /* We're unsetting this DS property */ 1008 if (DBG(CONFIG, 1)) 1009 idmapdlog(LOG_INFO, "change %s=<none>", name); 1010 return (1); 1011 } 1012 1013 if (DBG(CONFIG, 1)) { 1014 /* List all the new domains */ 1015 for (i = 0; (*value)[i].domain[0] != '\0'; i++) { 1016 idmapdlog(LOG_INFO, "change %s=%s direction=%s", name, 1017 (*value)[i].domain, 1018 enum_lookup((*value)[i].direction, trust_dir_map)); 1019 } 1020 } 1021 return (1); 1022 } 1023 1024 1025 /* 1026 * This function updates a domains in a forest structure. 1027 * If nothing has changed it returns 0 else 1 1028 */ 1029 static int 1030 update_domains_in_forest(ad_disc_domainsinforest_t **value, 1031 ad_disc_domainsinforest_t **new, char *name) 1032 { 1033 int i; 1034 1035 if (*value == *new) 1036 /* Nothing to do */ 1037 return (0); 1038 1039 if (*value != NULL && *new != NULL && 1040 ad_disc_compare_domainsinforest(*value, *new) == 0) { 1041 free(*new); 1042 *new = NULL; 1043 return (0); 1044 } 1045 1046 if (*value != NULL) 1047 free(*value); 1048 1049 *value = *new; 1050 *new = NULL; 1051 1052 if (*value == NULL) { 1053 /* We're unsetting this DS property */ 1054 if (DBG(CONFIG, 1)) 1055 idmapdlog(LOG_INFO, "change %s=<none>", name); 1056 return (1); 1057 } 1058 1059 if (DBG(CONFIG, 1)) { 1060 /* List all the new domains */ 1061 for (i = 0; (*value)[i].domain[0] != '\0'; i++) { 1062 idmapdlog(LOG_INFO, "change %s=%s", name, 1063 (*value)[i].domain); 1064 } 1065 } 1066 return (1); 1067 } 1068 1069 1070 static void 1071 free_trusted_forests(idmap_trustedforest_t **value, int *num_values) 1072 { 1073 int i; 1074 1075 for (i = 0; i < *num_values; i++) { 1076 free((*value)[i].forest_name); 1077 free((*value)[i].global_catalog); 1078 free((*value)[i].domains_in_forest); 1079 } 1080 free(*value); 1081 *value = NULL; 1082 *num_values = 0; 1083 } 1084 1085 1086 static int 1087 compare_trusteddomainsinforest(ad_disc_domainsinforest_t *df1, 1088 ad_disc_domainsinforest_t *df2) 1089 { 1090 int i, j; 1091 int num_df1 = 0; 1092 int num_df2 = 0; 1093 boolean_t match; 1094 1095 for (i = 0; df1[i].domain[0] != '\0'; i++) 1096 if (df1[i].trusted) 1097 num_df1++; 1098 1099 for (j = 0; df2[j].domain[0] != '\0'; j++) 1100 if (df2[j].trusted) 1101 num_df2++; 1102 1103 if (num_df1 != num_df2) 1104 return (1); 1105 1106 for (i = 0; df1[i].domain[0] != '\0'; i++) { 1107 if (df1[i].trusted) { 1108 match = B_FALSE; 1109 for (j = 0; df2[j].domain[0] != '\0'; j++) { 1110 if (df2[j].trusted && 1111 domain_eq(df1[i].domain, df2[j].domain) && 1112 strcmp(df1[i].sid, df2[j].sid) == 0) { 1113 match = B_TRUE; 1114 break; 1115 } 1116 } 1117 if (!match) 1118 return (1); 1119 } 1120 } 1121 return (0); 1122 } 1123 1124 1125 1126 /* 1127 * This function updates trusted forest structure. 1128 * If nothing has changed it returns 0 else 1 1129 */ 1130 static int 1131 update_trusted_forest(idmap_trustedforest_t **value, int *num_value, 1132 idmap_trustedforest_t **new, int *num_new, char *name) 1133 { 1134 int i, j; 1135 boolean_t match; 1136 1137 if (*value == *new) 1138 /* Nothing to do */ 1139 return (0); 1140 1141 if (*value != NULL && *new != NULL) { 1142 if (*num_value != *num_new) 1143 goto not_equal; 1144 for (i = 0; i < *num_value; i++) { 1145 match = B_FALSE; 1146 for (j = 0; j < *num_new; j++) { 1147 if (strcmp((*value)[i].forest_name, 1148 (*new)[j].forest_name) == 0 && 1149 ad_disc_compare_ds( 1150 (*value)[i].global_catalog, 1151 (*new)[j].global_catalog) == 0 && 1152 compare_trusteddomainsinforest( 1153 (*value)[i].domains_in_forest, 1154 (*new)[j].domains_in_forest) == 0) { 1155 match = B_TRUE; 1156 break; 1157 } 1158 } 1159 if (!match) 1160 goto not_equal; 1161 } 1162 free_trusted_forests(new, num_new); 1163 return (0); 1164 } 1165 not_equal: 1166 if (*value != NULL) 1167 free_trusted_forests(value, num_value); 1168 *value = *new; 1169 *num_value = *num_new; 1170 *new = NULL; 1171 *num_new = 0; 1172 1173 if (*value == NULL) { 1174 /* We're unsetting this DS property */ 1175 if (DBG(CONFIG, 1)) 1176 idmapdlog(LOG_INFO, "change %s=<none>", name); 1177 return (1); 1178 } 1179 1180 if (DBG(CONFIG, 1)) { 1181 /* List all the trusted forests */ 1182 for (i = 0; i < *num_value; i++) { 1183 idmap_trustedforest_t *f = &(*value)[i]; 1184 for (j = 0; 1185 f->domains_in_forest[j].domain[0] != '\0'; 1186 j++) { 1187 /* List trusted Domains in the forest. */ 1188 if (f->domains_in_forest[j].trusted) 1189 idmapdlog(LOG_INFO, 1190 "change %s=%s domain=%s", 1191 name, f->forest_name, 1192 f->domains_in_forest[j].domain); 1193 } 1194 /* List the hosts */ 1195 for (j = 0; 1196 f->global_catalog[j].host[0] != '\0'; 1197 j++) { 1198 idmapdlog(LOG_INFO, 1199 "change %s=%s host=%s port=%d", 1200 name, f->forest_name, 1201 f->global_catalog[j].host, 1202 f->global_catalog[j].port); 1203 } 1204 } 1205 } 1206 return (1); 1207 } 1208 1209 const char * 1210 enum_lookup(int value, struct enum_lookup_map *map) 1211 { 1212 for (; map->string != NULL; map++) { 1213 if (value == map->value) { 1214 return (map->string); 1215 } 1216 } 1217 return ("(invalid)"); 1218 } 1219 1220 /* 1221 * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the 1222 * interfaces. 1223 * 1224 * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON. 1225 */ 1226 static 1227 boolean_t 1228 pfroute_event_is_interesting(int rt_sock) 1229 { 1230 int nbytes; 1231 int64_t msg[2048 / 8]; 1232 struct rt_msghdr *rtm; 1233 boolean_t is_interesting = B_FALSE; 1234 1235 for (;;) { 1236 if ((nbytes = read(rt_sock, msg, sizeof (msg))) <= 0) 1237 break; 1238 rtm = (struct rt_msghdr *)msg; 1239 if (rtm->rtm_version != RTM_VERSION) 1240 continue; 1241 if (nbytes < rtm->rtm_msglen) 1242 continue; 1243 switch (rtm->rtm_type) { 1244 case RTM_NEWADDR: 1245 case RTM_DELADDR: 1246 case RTM_IFINFO: 1247 is_interesting = B_TRUE; 1248 break; 1249 default: 1250 break; 1251 } 1252 } 1253 return (is_interesting); 1254 } 1255 1256 /* 1257 * Wait for an event, and report what kind of event occurred. 1258 * 1259 * Note that there are cases where we are awoken but don't care about 1260 * the lower-level event. We can't just loop here because we can't 1261 * readily calculate how long to sleep the next time. We return 1262 * EVENT_NOTHING and let the caller loop. 1263 */ 1264 static 1265 enum event_type 1266 wait_for_event(struct timespec *timeoutp) 1267 { 1268 port_event_t pe; 1269 1270 (void) memset(&pe, 0, sizeof (pe)); 1271 if (port_get(idmapd_ev_port, &pe, timeoutp) != 0) { 1272 switch (errno) { 1273 case EINTR: 1274 return (EVENT_NOTHING); 1275 case ETIME: 1276 /* Timeout */ 1277 return (EVENT_TIMEOUT); 1278 default: 1279 /* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */ 1280 idmapdlog(LOG_ERR, "Event port failed: %s", 1281 strerror(errno)); 1282 exit(1); 1283 /* NOTREACHED */ 1284 } 1285 } 1286 1287 1288 switch (pe.portev_source) { 1289 case 0: 1290 /* 1291 * This isn't documented, but seems to be what you get if 1292 * the timeout is zero seconds and there are no events 1293 * pending. 1294 */ 1295 return (EVENT_TIMEOUT); 1296 1297 case PORT_SOURCE_USER: 1298 switch (pe.portev_events) { 1299 case RECONFIGURE: 1300 return (EVENT_REFRESH); 1301 case POKE_AUTO_DISCOVERY: 1302 return (EVENT_POKED); 1303 case KICK_AUTO_DISCOVERY: 1304 return (EVENT_KICKED); 1305 } 1306 return (EVENT_NOTHING); 1307 1308 case PORT_SOURCE_FD: 1309 if (pe.portev_object == rt_sock) { 1310 /* 1311 * PF_ROUTE socket read event: 1312 * re-associate fd 1313 * handle event 1314 */ 1315 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, 1316 rt_sock, POLLIN, NULL) != 0) { 1317 idmapdlog(LOG_ERR, "Failed to re-associate the " 1318 "routing socket with the event port: %s", 1319 strerror(errno)); 1320 abort(); 1321 } 1322 /* 1323 * The network configuration may still be in flux. 1324 * No matter, the resolver will re-transmit and 1325 * timeout if need be. 1326 */ 1327 if (pfroute_event_is_interesting(rt_sock)) { 1328 if (DBG(CONFIG, 1)) { 1329 idmapdlog(LOG_DEBUG, 1330 "Interesting routing event"); 1331 } 1332 return (EVENT_ROUTING); 1333 } else { 1334 if (DBG(CONFIG, 2)) { 1335 idmapdlog(LOG_DEBUG, 1336 "Boring routing event"); 1337 } 1338 return (EVENT_NOTHING); 1339 } 1340 } 1341 /* Event on an FD other than the routing FD? Ignore it. */ 1342 break; 1343 } 1344 1345 return (EVENT_NOTHING); 1346 } 1347 1348 void * 1349 idmap_cfg_update_thread(void *arg) 1350 { 1351 NOTE(ARGUNUSED(arg)) 1352 idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg; 1353 const ad_disc_t ad_ctx = _idmapdstate.cfg->handles.ad_ctx; 1354 int flags = CFG_DISCOVER; 1355 uint_t retry_count = 0; 1356 1357 for (;;) { 1358 struct timespec timeout; 1359 struct timespec *timeoutp; 1360 int rc; 1361 int ttl, max_ttl; 1362 1363 (void) ad_disc_SubnetChanged(ad_ctx); 1364 1365 rc = idmap_cfg_load(_idmapdstate.cfg, flags); 1366 if (rc < -1) { 1367 idmapdlog(LOG_ERR, "Fatal errors while reading " 1368 "SMF properties"); 1369 exit(1); 1370 } else if (rc == -1) { 1371 idmapdlog(LOG_WARNING, 1372 "Errors re-loading configuration may cause AD " 1373 "lookups to fail"); 1374 } 1375 1376 /* 1377 * If we don't know our domain name, we're not in a domain; 1378 * don't bother with rediscovery until the next config change. 1379 * Avoids hourly noise in workgroup mode. 1380 * 1381 * If we don't have a DC currently, use a greatly reduced TTL 1382 * until we get one. Degrade if that takes too long. 1383 */ 1384 if (pgcfg->domain_name == NULL) { 1385 ttl = -1; 1386 /* We don't need a DC if we're no longer in a domain. */ 1387 if (retry_count >= DISCOVERY_RETRY_DEGRADE_CUTOFF) 1388 restore_svc(); 1389 retry_count = 0; 1390 } else if (pgcfg->domain_controller == NULL || 1391 pgcfg->global_catalog == NULL) { 1392 if (retry_count == 0) 1393 ttl = DISCOVERY_RETRY_INITIAL_DELAY; 1394 else 1395 ttl *= 2; 1396 1397 if (ttl > pgcfg->discovery_retry_max_delay) 1398 ttl = pgcfg->discovery_retry_max_delay; 1399 1400 if (++retry_count >= DISCOVERY_RETRY_DEGRADE_CUTOFF) { 1401 degrade_svc(B_FALSE, 1402 "Too many DC discovery failures"); 1403 } 1404 } else { 1405 ttl = ad_disc_get_TTL(ad_ctx); 1406 max_ttl = (int)pgcfg->rediscovery_interval; 1407 if (ttl > max_ttl) 1408 ttl = max_ttl; 1409 if (ttl < MIN_REDISCOVERY_INTERVAL) 1410 ttl = MIN_REDISCOVERY_INTERVAL; 1411 if (retry_count >= DISCOVERY_RETRY_DEGRADE_CUTOFF) 1412 restore_svc(); 1413 retry_count = 0; 1414 } 1415 1416 /* 1417 * Wait for an interesting event. Note that we might get 1418 * boring events between interesting events. If so, we loop. 1419 */ 1420 flags = CFG_DISCOVER; 1421 for (;;) { 1422 if (ttl < 0) { 1423 timeoutp = NULL; 1424 } else { 1425 timeout.tv_sec = ttl; 1426 timeout.tv_nsec = 0; 1427 timeoutp = &timeout; 1428 } 1429 1430 if (DBG(CONFIG, 1)) 1431 idmapdlog(LOG_DEBUG, 1432 "_cfg_update_thread waiting"); 1433 1434 switch (wait_for_event(timeoutp)) { 1435 case EVENT_NOTHING: 1436 if (DBG(CONFIG, 2)) 1437 idmapdlog(LOG_DEBUG, "Boring event."); 1438 continue; 1439 case EVENT_REFRESH: 1440 if (DBG(CONFIG, 1)) 1441 idmapdlog(LOG_INFO, "SMF refresh"); 1442 /* 1443 * Forget any DC we had previously. 1444 */ 1445 flags |= CFG_FORGET_DC; 1446 1447 /* 1448 * Blow away the ccache, we might have 1449 * re-joined the domain or joined a new one 1450 */ 1451 (void) unlink(IDMAP_CACHEDIR "/ccache"); 1452 break; 1453 case EVENT_POKED: 1454 if (DBG(CONFIG, 1)) 1455 idmapdlog(LOG_DEBUG, "poked"); 1456 break; 1457 case EVENT_KICKED: 1458 if (DBG(CONFIG, 1)) 1459 idmapdlog(LOG_DEBUG, "kicked"); 1460 flags |= CFG_FORGET_DC; 1461 break; 1462 case EVENT_TIMEOUT: 1463 if (DBG(CONFIG, 1)) 1464 idmapdlog(LOG_DEBUG, "TTL expired"); 1465 break; 1466 case EVENT_ROUTING: 1467 /* Already logged to DEBUG */ 1468 break; 1469 } 1470 /* An interesting event! */ 1471 break; 1472 } 1473 } 1474 /* 1475 * Lint isn't happy with the concept of a function declared to 1476 * return something, that doesn't return. Of course, merely adding 1477 * the return isn't enough, because it's never reached... 1478 */ 1479 /*NOTREACHED*/ 1480 return (NULL); 1481 } 1482 1483 int 1484 idmap_cfg_start_updates(void) 1485 { 1486 if ((idmapd_ev_port = port_create()) < 0) { 1487 idmapdlog(LOG_ERR, "Failed to create event port: %s", 1488 strerror(errno)); 1489 return (-1); 1490 } 1491 1492 if ((rt_sock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 1493 idmapdlog(LOG_ERR, "Failed to open routing socket: %s", 1494 strerror(errno)); 1495 (void) close(idmapd_ev_port); 1496 return (-1); 1497 } 1498 1499 if (fcntl(rt_sock, F_SETFL, O_NDELAY|O_NONBLOCK) < 0) { 1500 idmapdlog(LOG_ERR, "Failed to set routing socket flags: %s", 1501 strerror(errno)); 1502 (void) close(rt_sock); 1503 (void) close(idmapd_ev_port); 1504 return (-1); 1505 } 1506 1507 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, 1508 rt_sock, POLLIN, NULL) != 0) { 1509 idmapdlog(LOG_ERR, "Failed to associate the routing " 1510 "socket with the event port: %s", strerror(errno)); 1511 (void) close(rt_sock); 1512 (void) close(idmapd_ev_port); 1513 return (-1); 1514 } 1515 1516 if ((errno = pthread_create(&update_thread_handle, NULL, 1517 idmap_cfg_update_thread, NULL)) != 0) { 1518 idmapdlog(LOG_ERR, "Failed to start update thread: %s", 1519 strerror(errno)); 1520 (void) port_dissociate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock); 1521 (void) close(rt_sock); 1522 (void) close(idmapd_ev_port); 1523 return (-1); 1524 } 1525 1526 return (0); 1527 } 1528 1529 /* 1530 * Reject attribute names with invalid characters. 1531 */ 1532 static 1533 int 1534 valid_ldap_attr(const char *attr) 1535 { 1536 for (; *attr; attr++) { 1537 if (!isalnum(*attr) && *attr != '-' && 1538 *attr != '_' && *attr != '.' && *attr != ';') 1539 return (0); 1540 } 1541 return (1); 1542 } 1543 1544 static 1545 void 1546 idmapd_set_debug( 1547 idmap_cfg_handles_t *handles, 1548 enum idmapd_debug item, 1549 const char *name) 1550 { 1551 int val; 1552 1553 if (item < 0 || item > IDMAPD_DEBUG_MAX) 1554 return; 1555 1556 val = get_debug(handles, name); 1557 1558 if (val != _idmapdstate.debug[item]) 1559 idmapdlog(LOG_DEBUG, "%s/%s = %d", DEBUG_PG, name, val); 1560 1561 _idmapdstate.debug[item] = val; 1562 } 1563 1564 static 1565 void 1566 check_smf_debug_mode(idmap_cfg_handles_t *handles) 1567 { 1568 idmapd_set_debug(handles, IDMAPD_DEBUG_ALL, "all"); 1569 idmapd_set_debug(handles, IDMAPD_DEBUG_CONFIG, "config"); 1570 idmapd_set_debug(handles, IDMAPD_DEBUG_MAPPING, "mapping"); 1571 idmapd_set_debug(handles, IDMAPD_DEBUG_DISC, "discovery"); 1572 idmapd_set_debug(handles, IDMAPD_DEBUG_DNS, "dns"); 1573 idmapd_set_debug(handles, IDMAPD_DEBUG_LDAP, "ldap"); 1574 1575 adutils_set_debug(AD_DEBUG_ALL, _idmapdstate.debug[IDMAPD_DEBUG_ALL]); 1576 adutils_set_debug(AD_DEBUG_DISC, _idmapdstate.debug[IDMAPD_DEBUG_DISC]); 1577 adutils_set_debug(AD_DEBUG_DNS, _idmapdstate.debug[IDMAPD_DEBUG_DNS]); 1578 adutils_set_debug(AD_DEBUG_LDAP, _idmapdstate.debug[IDMAPD_DEBUG_LDAP]); 1579 } 1580 1581 /* 1582 * This is the half of idmap_cfg_load() that loads property values from 1583 * SMF (using the config/ property group of the idmap FMRI). 1584 * 1585 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures 1586 * -3 -> hard smf config failures 1587 * reading from SMF. 1588 */ 1589 static int 1590 idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg, 1591 int * const errors) 1592 { 1593 int rc; 1594 char *s; 1595 1596 *errors = 0; 1597 1598 if (scf_pg_update(handles->config_pg) < 0) { 1599 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s", 1600 scf_strerror(scf_error())); 1601 return (-2); 1602 } 1603 1604 if (scf_pg_update(handles->debug_pg) < 0) { 1605 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s", 1606 scf_strerror(scf_error())); 1607 return (-2); 1608 } 1609 1610 check_smf_debug_mode(handles); 1611 1612 rc = get_val_bool(handles, "unresolvable_sid_mapping", 1613 &pgcfg->eph_map_unres_sids, B_TRUE); 1614 if (rc != 0) 1615 (*errors)++; 1616 1617 rc = get_val_bool(handles, "use_ads", 1618 &pgcfg->use_ads, B_TRUE); 1619 if (rc != 0) 1620 (*errors)++; 1621 1622 rc = get_val_bool(handles, "use_lsa", 1623 &pgcfg->use_lsa, B_TRUE); 1624 if (rc != 0) 1625 (*errors)++; 1626 1627 rc = get_val_bool(handles, "disable_cross_forest_trusts", 1628 &pgcfg->disable_cross_forest_trusts, B_TRUE); 1629 if (rc != 0) 1630 (*errors)++; 1631 1632 rc = get_val_astring(handles, "directory_based_mapping", &s); 1633 if (rc != 0) 1634 (*errors)++; 1635 else if (s == NULL || strcasecmp(s, "none") == 0) 1636 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE; 1637 else if (strcasecmp(s, "name") == 0) 1638 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NAME; 1639 else if (strcasecmp(s, "idmu") == 0) 1640 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_IDMU; 1641 else { 1642 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE; 1643 idmapdlog(LOG_ERR, 1644 "config/directory_based_mapping: invalid value \"%s\" ignored", 1645 s); 1646 (*errors)++; 1647 } 1648 free(s); 1649 1650 rc = get_val_int(handles, "list_size_limit", 1651 &pgcfg->list_size_limit, SCF_TYPE_COUNT); 1652 if (rc != 0) 1653 (*errors)++; 1654 1655 rc = get_val_int(handles, "max_threads", 1656 &pgcfg->max_threads, SCF_TYPE_COUNT); 1657 if (rc != 0) 1658 (*errors)++; 1659 if (pgcfg->max_threads == 0) 1660 pgcfg->max_threads = MAX_THREADS_DEFAULT; 1661 if (pgcfg->max_threads > UINT_MAX) 1662 pgcfg->max_threads = UINT_MAX; 1663 1664 rc = get_val_int(handles, "discovery_retry_max_delay", 1665 &pgcfg->discovery_retry_max_delay, SCF_TYPE_COUNT); 1666 if (rc != 0) 1667 (*errors)++; 1668 if (pgcfg->discovery_retry_max_delay == 0) 1669 pgcfg->discovery_retry_max_delay = 1670 DISCOVERY_RETRY_MAX_DELAY_DEFAULT; 1671 1672 rc = get_val_int(handles, "id_cache_timeout", 1673 &pgcfg->id_cache_timeout, SCF_TYPE_COUNT); 1674 if (rc != 0) 1675 (*errors)++; 1676 if (pgcfg->id_cache_timeout == 0) 1677 pgcfg->id_cache_timeout = ID_CACHE_TMO_DEFAULT; 1678 1679 rc = get_val_int(handles, "name_cache_timeout", 1680 &pgcfg->name_cache_timeout, SCF_TYPE_COUNT); 1681 if (rc != 0) 1682 (*errors)++; 1683 if (pgcfg->name_cache_timeout == 0) 1684 pgcfg->name_cache_timeout = NAME_CACHE_TMO_DEFAULT; 1685 1686 rc = get_val_int(handles, "rediscovery_interval", 1687 &pgcfg->rediscovery_interval, SCF_TYPE_COUNT); 1688 if (rc != 0) 1689 (*errors)++; 1690 if (pgcfg->rediscovery_interval == 0) 1691 pgcfg->rediscovery_interval = REDISCOVERY_INTERVAL_DEFAULT; 1692 1693 rc = get_val_astring(handles, "domain_name", 1694 &pgcfg->domain_name); 1695 if (rc != 0) 1696 (*errors)++; 1697 else { 1698 if (pgcfg->domain_name != NULL && 1699 pgcfg->domain_name[0] == '\0') { 1700 free(pgcfg->domain_name); 1701 pgcfg->domain_name = NULL; 1702 } 1703 if (pgcfg->domain_name != NULL) 1704 pgcfg->domain_name_auto_disc = B_FALSE; 1705 (void) ad_disc_set_DomainName(handles->ad_ctx, 1706 pgcfg->domain_name); 1707 } 1708 1709 rc = get_val_astring(handles, "default_domain", 1710 &pgcfg->default_domain); 1711 if (rc != 0) { 1712 /* 1713 * SCF failures fetching config/default_domain we treat 1714 * as fatal as they may leave ID mapping rules that 1715 * match unqualified winnames flapping in the wind. 1716 */ 1717 return (-2); 1718 } 1719 1720 if (pgcfg->default_domain == NULL && pgcfg->domain_name != NULL) { 1721 pgcfg->default_domain = strdup(pgcfg->domain_name); 1722 } 1723 1724 rc = get_val_astring(handles, "domain_guid", &s); 1725 if (rc != 0) { 1726 (*errors)++; 1727 } else if (s == NULL || s[0] == '\0') { 1728 /* OK, not set. */ 1729 free(s); 1730 } else { 1731 uuid_t u; 1732 1733 if (uuid_parse(s, u) != 0) { 1734 idmapdlog(LOG_ERR, 1735 "config/domain_guid: invalid value \"%s\" ignored", s); 1736 free(s); 1737 (*errors)++; 1738 } else { 1739 pgcfg->domain_guid = s; 1740 pgcfg->domain_guid_auto_disc = B_FALSE; 1741 (void) ad_disc_set_DomainGUID(handles->ad_ctx, u); 1742 } 1743 } 1744 1745 rc = get_val_astring(handles, "machine_uuid", &pgcfg->machine_uuid); 1746 if (rc != 0) 1747 (*errors)++; 1748 if (pgcfg->machine_uuid == NULL) { 1749 /* If machine_uuid not configured, generate one */ 1750 if (generate_machine_uuid(&pgcfg->machine_uuid) < 0) 1751 return (-2); 1752 rc = set_val_astring(handles, handles->config_pg, 1753 "machine_uuid", pgcfg->machine_uuid); 1754 if (rc != 0) 1755 (*errors)++; 1756 } 1757 1758 rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid); 1759 if (rc != 0) 1760 (*errors)++; 1761 if (pgcfg->machine_sid == NULL) { 1762 /* 1763 * If machine_sid not configured, generate one 1764 * from the machine UUID. 1765 */ 1766 if (generate_machine_sid(&pgcfg->machine_sid, 1767 pgcfg->machine_uuid) < 0) 1768 return (-2); 1769 rc = set_val_astring(handles, handles->config_pg, 1770 "machine_sid", pgcfg->machine_sid); 1771 if (rc != 0) 1772 (*errors)++; 1773 } 1774 1775 rc = get_val_ds(handles, "domain_controller", 389, 1776 &pgcfg->domain_controller); 1777 if (rc != 0) 1778 (*errors)++; 1779 else { 1780 (void) ad_disc_set_DomainController(handles->ad_ctx, 1781 pgcfg->domain_controller); 1782 pgcfg->domain_controller_auto_disc = B_FALSE; 1783 } 1784 1785 rc = get_val_ds(handles, "preferred_dc", 389, 1786 &pgcfg->preferred_dc); 1787 if (rc != 0) 1788 (*errors)++; 1789 else { 1790 (void) ad_disc_set_PreferredDC(handles->ad_ctx, 1791 pgcfg->preferred_dc); 1792 pgcfg->preferred_dc_auto_disc = B_FALSE; 1793 } 1794 1795 rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name); 1796 if (rc != 0) 1797 (*errors)++; 1798 else { 1799 if (pgcfg->forest_name != NULL && 1800 pgcfg->forest_name[0] == '\0') { 1801 free(pgcfg->forest_name); 1802 pgcfg->forest_name = NULL; 1803 } 1804 if (pgcfg->forest_name != NULL) 1805 pgcfg->forest_name_auto_disc = B_FALSE; 1806 (void) ad_disc_set_ForestName(handles->ad_ctx, 1807 pgcfg->forest_name); 1808 } 1809 1810 rc = get_val_astring(handles, "site_name", &pgcfg->site_name); 1811 if (rc != 0) 1812 (*errors)++; 1813 else { 1814 if (pgcfg->site_name != NULL && 1815 pgcfg->site_name[0] == '\0') { 1816 free(pgcfg->site_name); 1817 pgcfg->site_name = NULL; 1818 } 1819 if (pgcfg->site_name != NULL) 1820 pgcfg->site_name_auto_disc = B_FALSE; 1821 (void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name); 1822 } 1823 1824 rc = get_val_ds(handles, "global_catalog", 3268, 1825 &pgcfg->global_catalog); 1826 if (rc != 0) 1827 (*errors)++; 1828 else { 1829 (void) ad_disc_set_GlobalCatalog(handles->ad_ctx, 1830 pgcfg->global_catalog); 1831 pgcfg->global_catalog_auto_disc = B_FALSE; 1832 } 1833 1834 /* Unless we're doing directory-based name mapping, we're done. */ 1835 if (pgcfg->directory_based_mapping != DIRECTORY_MAPPING_NAME) 1836 return (0); 1837 1838 rc = get_val_astring(handles, "ad_unixuser_attr", 1839 &pgcfg->ad_unixuser_attr); 1840 if (rc != 0) 1841 return (-2); 1842 if (pgcfg->ad_unixuser_attr != NULL && 1843 !valid_ldap_attr(pgcfg->ad_unixuser_attr)) { 1844 idmapdlog(LOG_ERR, "config/ad_unixuser_attr=%s is not a " 1845 "valid LDAP attribute name", pgcfg->ad_unixuser_attr); 1846 return (-3); 1847 } 1848 1849 rc = get_val_astring(handles, "ad_unixgroup_attr", 1850 &pgcfg->ad_unixgroup_attr); 1851 if (rc != 0) 1852 return (-2); 1853 if (pgcfg->ad_unixgroup_attr != NULL && 1854 !valid_ldap_attr(pgcfg->ad_unixgroup_attr)) { 1855 idmapdlog(LOG_ERR, "config/ad_unixgroup_attr=%s is not a " 1856 "valid LDAP attribute name", pgcfg->ad_unixgroup_attr); 1857 return (-3); 1858 } 1859 1860 rc = get_val_astring(handles, "nldap_winname_attr", 1861 &pgcfg->nldap_winname_attr); 1862 if (rc != 0) 1863 return (-2); 1864 if (pgcfg->nldap_winname_attr != NULL && 1865 !valid_ldap_attr(pgcfg->nldap_winname_attr)) { 1866 idmapdlog(LOG_ERR, "config/nldap_winname_attr=%s is not a " 1867 "valid LDAP attribute name", pgcfg->nldap_winname_attr); 1868 return (-3); 1869 } 1870 if (pgcfg->ad_unixuser_attr == NULL && 1871 pgcfg->ad_unixgroup_attr == NULL && 1872 pgcfg->nldap_winname_attr == NULL) { 1873 idmapdlog(LOG_ERR, 1874 "If config/directory_based_mapping property is set to " 1875 "\"name\" then at least one of the following name mapping " 1876 "attributes must be specified. (config/ad_unixuser_attr OR " 1877 "config/ad_unixgroup_attr OR config/nldap_winname_attr)"); 1878 return (-3); 1879 } 1880 1881 return (rc); 1882 } 1883 1884 static 1885 void 1886 log_if_unable(const void *val, const char *what) 1887 { 1888 if (val == NULL) { 1889 idmapdlog(LOG_DEBUG, "unable to discover %s", what); 1890 } 1891 } 1892 1893 static 1894 void 1895 discover_trusted_domains(idmap_pg_config_t *pgcfg, ad_disc_t ad_ctx) 1896 { 1897 ad_disc_t trusted_ctx; 1898 int i, j, k, l; 1899 char *forestname; 1900 int num_trusteddomains; 1901 boolean_t new_forest; 1902 char *trusteddomain; 1903 ad_disc_ds_t *globalcatalog; 1904 idmap_trustedforest_t *trustedforests; 1905 ad_disc_domainsinforest_t *domainsinforest; 1906 1907 pgcfg->trusted_domains = 1908 ad_disc_get_TrustedDomains(ad_ctx, NULL); 1909 1910 if (pgcfg->forest_name != NULL && pgcfg->trusted_domains != NULL && 1911 pgcfg->trusted_domains[0].domain[0] != '\0') { 1912 /* 1913 * We have trusted domains. We need to go through every 1914 * one and find its forest. If it is a new forest we then need 1915 * to find its Global Catalog and the domains in the forest 1916 */ 1917 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++) 1918 continue; 1919 num_trusteddomains = i; 1920 1921 trustedforests = calloc(num_trusteddomains, 1922 sizeof (idmap_trustedforest_t)); 1923 j = 0; 1924 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++) { 1925 trusteddomain = pgcfg->trusted_domains[i].domain; 1926 trusted_ctx = ad_disc_init(); 1927 (void) ad_disc_set_DomainName(trusted_ctx, 1928 trusteddomain); 1929 forestname = 1930 ad_disc_get_ForestName(trusted_ctx, NULL); 1931 if (forestname == NULL) { 1932 if (DBG(CONFIG, 1)) { 1933 idmapdlog(LOG_DEBUG, 1934 "unable to discover Forest Name" 1935 " for the trusted domain %s", 1936 trusteddomain); 1937 } 1938 ad_disc_fini(trusted_ctx); 1939 continue; 1940 } 1941 1942 if (strcasecmp(forestname, pgcfg->forest_name) == 0) { 1943 /* 1944 * Ignore the domain as it is part of 1945 * the primary forest 1946 */ 1947 free(forestname); 1948 ad_disc_fini(trusted_ctx); 1949 continue; 1950 } 1951 1952 /* Is this a new forest? */ 1953 new_forest = B_TRUE; 1954 for (k = 0; k < j; k++) { 1955 if (strcasecmp(forestname, 1956 trustedforests[k].forest_name) == 0) { 1957 new_forest = B_FALSE; 1958 domainsinforest = 1959 trustedforests[k].domains_in_forest; 1960 break; 1961 } 1962 } 1963 if (!new_forest) { 1964 /* Mark the domain as trusted */ 1965 for (l = 0; 1966 domainsinforest[l].domain[0] != '\0'; l++) { 1967 if (domain_eq(trusteddomain, 1968 domainsinforest[l].domain)) { 1969 domainsinforest[l].trusted = 1970 TRUE; 1971 break; 1972 } 1973 } 1974 free(forestname); 1975 ad_disc_fini(trusted_ctx); 1976 continue; 1977 } 1978 1979 /* 1980 * Get the Global Catalog and the domains in 1981 * this new forest. 1982 */ 1983 globalcatalog = 1984 ad_disc_get_GlobalCatalog(trusted_ctx, 1985 AD_DISC_PREFER_SITE, NULL); 1986 if (globalcatalog == NULL) { 1987 if (DBG(CONFIG, 1)) { 1988 idmapdlog(LOG_DEBUG, 1989 "unable to discover Global Catalog" 1990 " for the trusted domain %s", 1991 trusteddomain); 1992 } 1993 free(forestname); 1994 ad_disc_fini(trusted_ctx); 1995 continue; 1996 } 1997 domainsinforest = 1998 ad_disc_get_DomainsInForest(trusted_ctx, NULL); 1999 if (domainsinforest == NULL) { 2000 if (DBG(CONFIG, 1)) { 2001 idmapdlog(LOG_DEBUG, 2002 "unable to discover Domains in the" 2003 " Forest for the trusted domain %s", 2004 trusteddomain); 2005 } 2006 free(globalcatalog); 2007 free(forestname); 2008 ad_disc_fini(trusted_ctx); 2009 continue; 2010 } 2011 2012 trustedforests[j].forest_name = forestname; 2013 trustedforests[j].global_catalog = globalcatalog; 2014 trustedforests[j].domains_in_forest = domainsinforest; 2015 j++; 2016 /* Mark the domain as trusted */ 2017 for (l = 0; domainsinforest[l].domain[0] != '\0'; 2018 l++) { 2019 if (domain_eq(trusteddomain, 2020 domainsinforest[l].domain)) { 2021 domainsinforest[l].trusted = TRUE; 2022 break; 2023 } 2024 } 2025 ad_disc_fini(trusted_ctx); 2026 } 2027 if (j > 0) { 2028 pgcfg->num_trusted_forests = j; 2029 pgcfg->trusted_forests = trustedforests; 2030 } else { 2031 free(trustedforests); 2032 } 2033 } 2034 } 2035 2036 /* 2037 * This is the half of idmap_cfg_load() that auto-discovers values of 2038 * discoverable properties that weren't already set via SMF properties. 2039 * 2040 * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it 2041 * needs to be careful not to overwrite any properties set in SMF. 2042 */ 2043 static void 2044 idmap_cfg_discover1(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) 2045 { 2046 ad_disc_t ad_ctx = handles->ad_ctx; 2047 FILE *status_fp = NULL; 2048 time_t t0, t1; 2049 2050 t0 = time(NULL); 2051 if (DBG(CONFIG, 1)) 2052 idmapdlog(LOG_DEBUG, "Running domain discovery."); 2053 2054 (void) unlink(IDMAP_CACHEDIR "/discovery.log"); 2055 status_fp = fopen(IDMAP_CACHEDIR "/discovery.log", "w"); 2056 if (status_fp) { 2057 (void) fchmod(fileno(status_fp), 0644); 2058 ad_disc_set_StatusFP(ad_ctx, status_fp); 2059 } 2060 2061 if (pgcfg->domain_name == NULL) { 2062 idmapdlog(LOG_DEBUG, "No domain name specified."); 2063 if (status_fp) 2064 (void) fprintf(status_fp, "(no domain name)\n"); 2065 goto out; 2066 } 2067 2068 if (pgcfg->domain_controller == NULL) 2069 pgcfg->domain_controller = 2070 ad_disc_get_DomainController(ad_ctx, 2071 AD_DISC_PREFER_SITE, 2072 &pgcfg->domain_controller_auto_disc); 2073 2074 if (pgcfg->domain_guid == NULL) { 2075 char buf[UUID_PRINTABLE_STRING_LENGTH]; 2076 uchar_t *u = ad_disc_get_DomainGUID(ad_ctx, 2077 &pgcfg->domain_guid_auto_disc); 2078 (void) memset(buf, 0, sizeof (buf)); 2079 if (u != NULL) { 2080 uuid_unparse(u, buf); 2081 pgcfg->domain_guid = strdup(buf); 2082 } 2083 } 2084 2085 if (pgcfg->forest_name == NULL) 2086 pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx, 2087 &pgcfg->forest_name_auto_disc); 2088 2089 if (pgcfg->site_name == NULL) 2090 pgcfg->site_name = ad_disc_get_SiteName(ad_ctx, 2091 &pgcfg->site_name_auto_disc); 2092 2093 if (DBG(CONFIG, 1)) { 2094 log_if_unable(pgcfg->domain_name, "Domain Name"); 2095 log_if_unable(pgcfg->domain_controller, 2096 "Domain Controller"); 2097 log_if_unable(pgcfg->domain_guid, "Domain GUID"); 2098 log_if_unable(pgcfg->forest_name, "Forest Name"); 2099 log_if_unable(pgcfg->site_name, "Site Name"); 2100 } 2101 2102 out: 2103 if (status_fp) { 2104 ad_disc_set_StatusFP(ad_ctx, NULL); 2105 (void) fclose(status_fp); 2106 status_fp = NULL; 2107 } 2108 2109 if (DBG(CONFIG, 1)) 2110 idmapdlog(LOG_DEBUG, "Domain discovery done."); 2111 2112 /* 2113 * Log when this took more than 15 sec. 2114 */ 2115 t1 = time(NULL); 2116 if (t1 > (t0 + 15)) { 2117 idmapdlog(LOG_NOTICE, "Domain discovery took %d sec.", 2118 (int)(t1 - t0)); 2119 idmapdlog(LOG_NOTICE, "Check the DNS configuration."); 2120 } 2121 } 2122 2123 /* 2124 * This is the second part of discovery, which can take a while. 2125 * We don't want to hold up parties who just want to know what 2126 * domain controller we're using (like smbd), so this part runs 2127 * after we've updated that info in the "live" config and told 2128 * such consumers to go ahead. 2129 * 2130 * This is a lot like idmap_cfg_discover(), but used LDAP queries 2131 * get the forest information from the global catalog servers. 2132 * 2133 * Note: the previous update_* calls have usually nuked any 2134 * useful information from pgcfg before we get here, so we 2135 * can only use it store discovery results, not to read. 2136 */ 2137 static void 2138 idmap_cfg_discover2(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) 2139 { 2140 ad_disc_t ad_ctx = handles->ad_ctx; 2141 FILE *status_fp = NULL; 2142 time_t t0, t1; 2143 2144 t0 = time(NULL); 2145 if (DBG(CONFIG, 1)) 2146 idmapdlog(LOG_DEBUG, "Running forest discovery."); 2147 2148 status_fp = fopen(IDMAP_CACHEDIR "/discovery.log", "a"); 2149 if (status_fp) 2150 ad_disc_set_StatusFP(ad_ctx, status_fp); 2151 2152 if (pgcfg->global_catalog == NULL) 2153 pgcfg->global_catalog = 2154 ad_disc_get_GlobalCatalog(ad_ctx, 2155 AD_DISC_PREFER_SITE, 2156 &pgcfg->global_catalog_auto_disc); 2157 2158 if (pgcfg->global_catalog != NULL) { 2159 pgcfg->domains_in_forest = 2160 ad_disc_get_DomainsInForest(ad_ctx, NULL); 2161 2162 if (!pgcfg->disable_cross_forest_trusts) 2163 discover_trusted_domains(pgcfg, ad_ctx); 2164 } 2165 2166 if (DBG(CONFIG, 1)) { 2167 log_if_unable(pgcfg->global_catalog, "Global Catalog"); 2168 log_if_unable(pgcfg->domains_in_forest, 2169 "Domains in the Forest"); 2170 /* Empty trusted domains list is OK. */ 2171 } 2172 2173 if (status_fp) { 2174 ad_disc_set_StatusFP(ad_ctx, NULL); 2175 (void) fclose(status_fp); 2176 status_fp = NULL; 2177 } 2178 2179 if (DBG(CONFIG, 1)) 2180 idmapdlog(LOG_DEBUG, "Forest discovery done."); 2181 2182 /* 2183 * Log when this took more than 30 sec. 2184 */ 2185 t1 = time(NULL); 2186 if (t1 > (t0 + 30)) { 2187 idmapdlog(LOG_NOTICE, "Forest discovery took %d sec.", 2188 (int)(t1 - t0)); 2189 idmapdlog(LOG_NOTICE, "Check AD join status."); 2190 } 2191 } 2192 2193 2194 /* 2195 * idmap_cfg_load() is called at startup, and periodically via the 2196 * update thread when the auto-discovery TTLs expire, as well as part of 2197 * the refresh method, to update the current configuration. It always 2198 * reads from SMF, but you still have to refresh the service after 2199 * changing the config pg in order for the changes to take effect. 2200 * 2201 * There is one flag: 2202 * 2203 * - CFG_DISCOVER 2204 * 2205 * If CFG_DISCOVER is set then idmap_cfg_load() calls 2206 * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property 2207 * values that weren't set in SMF. 2208 * 2209 * idmap_cfg_load() will log (to LOG_NOTICE) whether the configuration 2210 * changed. 2211 * 2212 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures 2213 * reading from SMF. 2214 */ 2215 int 2216 idmap_cfg_load(idmap_cfg_t *cfg, int flags) 2217 { 2218 const ad_disc_t ad_ctx = cfg->handles.ad_ctx; 2219 int rc = 0; 2220 int errors; 2221 int changed = 0; 2222 bool_t dc_changed = FALSE; 2223 bool_t gc_changed = FALSE; 2224 idmap_pg_config_t new_pgcfg, *live_pgcfg; 2225 2226 if (DBG(CONFIG, 1)) 2227 idmapdlog(LOG_DEBUG, "Loading configuration."); 2228 2229 live_pgcfg = &cfg->pgcfg; 2230 (void) memset(&new_pgcfg, 0, sizeof (new_pgcfg)); 2231 2232 (void) pthread_mutex_lock(&cfg->handles.mutex); 2233 2234 if ((rc = idmap_cfg_load_smf(&cfg->handles, &new_pgcfg, &errors)) < -1) 2235 goto err; 2236 2237 if (flags & CFG_DISCOVER) { 2238 2239 ad_disc_refresh(ad_ctx); 2240 2241 /* 2242 * Unless we've been asked to forget the current DC, 2243 * give preference (in order) to the preferred DC if 2244 * configured, or the current DC. These preferences 2245 * reduce undesirable DC changes. 2246 */ 2247 if (flags & CFG_FORGET_DC) { 2248 (void) ad_disc_set_PreferredDC(ad_ctx, NULL); 2249 } else if (new_pgcfg.preferred_dc != NULL) { 2250 (void) ad_disc_set_PreferredDC(ad_ctx, 2251 new_pgcfg.preferred_dc); 2252 } else if (live_pgcfg->domain_controller != NULL) { 2253 (void) ad_disc_set_PreferredDC(ad_ctx, 2254 live_pgcfg->domain_controller); 2255 } else { 2256 (void) ad_disc_set_PreferredDC(ad_ctx, NULL); 2257 } 2258 2259 /* 2260 * We want a way to tell adspriv_getdcname_1_svc() 2261 * (and others) that discovery is running and therefore 2262 * they may want to wait a bit or return an error... 2263 */ 2264 (void) mutex_lock(&_idmapdstate.addisc_lk); 2265 _idmapdstate.addisc_st |= ADDISC_ST_RUNNING; 2266 (void) mutex_unlock(&_idmapdstate.addisc_lk); 2267 2268 idmap_cfg_discover1(&cfg->handles, &new_pgcfg); 2269 2270 WRLOCK_CONFIG(); 2271 (void) mutex_lock(&_idmapdstate.addisc_lk); 2272 _idmapdstate.addisc_st = 0; 2273 (void) cond_broadcast(&_idmapdstate.addisc_cv); 2274 (void) mutex_unlock(&_idmapdstate.addisc_lk); 2275 } else { 2276 WRLOCK_CONFIG(); 2277 } 2278 2279 /* Non-discoverable props updated here */ 2280 2281 changed += update_uint64(&live_pgcfg->list_size_limit, 2282 &new_pgcfg.list_size_limit, "list_size_limit"); 2283 2284 changed += update_uint64(&live_pgcfg->max_threads, 2285 &new_pgcfg.max_threads, "max_threads"); 2286 2287 changed += update_uint64(&live_pgcfg->discovery_retry_max_delay, 2288 &new_pgcfg.discovery_retry_max_delay, "discovery_retry_max_delay"); 2289 2290 changed += update_uint64(&live_pgcfg->id_cache_timeout, 2291 &new_pgcfg.id_cache_timeout, "id_cache_timeout"); 2292 2293 changed += update_uint64(&live_pgcfg->name_cache_timeout, 2294 &new_pgcfg.name_cache_timeout, "name_cache_timeout"); 2295 2296 changed += update_uint64(&live_pgcfg->rediscovery_interval, 2297 &new_pgcfg.rediscovery_interval, "rediscovery_interval"); 2298 2299 changed += update_string(&live_pgcfg->machine_sid, 2300 &new_pgcfg.machine_sid, "machine_sid"); 2301 2302 changed += update_bool(&live_pgcfg->eph_map_unres_sids, 2303 &new_pgcfg.eph_map_unres_sids, "unresolvable_sid_mapping"); 2304 2305 changed += update_bool(&live_pgcfg->use_ads, 2306 &new_pgcfg.use_ads, "use_ads"); 2307 2308 changed += update_bool(&live_pgcfg->use_lsa, 2309 &new_pgcfg.use_lsa, "use_lsa"); 2310 2311 changed += update_bool(&live_pgcfg->disable_cross_forest_trusts, 2312 &new_pgcfg.disable_cross_forest_trusts, 2313 "disable_cross_forest_trusts"); 2314 2315 changed += update_enum(&live_pgcfg->directory_based_mapping, 2316 &new_pgcfg.directory_based_mapping, "directory_based_mapping", 2317 directory_mapping_map); 2318 2319 changed += update_string(&live_pgcfg->ad_unixuser_attr, 2320 &new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr"); 2321 2322 changed += update_string(&live_pgcfg->ad_unixgroup_attr, 2323 &new_pgcfg.ad_unixgroup_attr, "ad_unixgroup_attr"); 2324 2325 changed += update_string(&live_pgcfg->nldap_winname_attr, 2326 &new_pgcfg.nldap_winname_attr, "nldap_winname_attr"); 2327 2328 changed += update_string(&live_pgcfg->default_domain, 2329 &new_pgcfg.default_domain, "default_domain"); 2330 2331 changed += update_dirs(&live_pgcfg->preferred_dc, 2332 &new_pgcfg.preferred_dc, "preferred_dc"); 2333 2334 /* Props that can be discovered or set in SMF updated here */ 2335 2336 if (update_string(&live_pgcfg->domain_name, 2337 &new_pgcfg.domain_name, "domain_name")) { 2338 changed++; 2339 dc_changed = TRUE; 2340 gc_changed = TRUE; 2341 idmapd_set_krb5_realm(live_pgcfg->domain_name); 2342 } 2343 live_pgcfg->domain_name_auto_disc = new_pgcfg.domain_name_auto_disc; 2344 2345 changed += update_string(&live_pgcfg->domain_guid, 2346 &new_pgcfg.domain_guid, "domain_guid"); 2347 live_pgcfg->domain_guid_auto_disc = new_pgcfg.domain_guid_auto_disc; 2348 2349 if (update_dirs(&live_pgcfg->domain_controller, 2350 &new_pgcfg.domain_controller, "domain_controller")) { 2351 changed++; 2352 dc_changed = TRUE; 2353 } 2354 live_pgcfg->domain_controller_auto_disc = 2355 new_pgcfg.domain_controller_auto_disc; 2356 2357 changed += update_string(&live_pgcfg->forest_name, 2358 &new_pgcfg.forest_name, "forest_name"); 2359 live_pgcfg->forest_name_auto_disc = new_pgcfg.forest_name_auto_disc; 2360 2361 changed += update_string(&live_pgcfg->site_name, 2362 &new_pgcfg.site_name, "site_name"); 2363 live_pgcfg->site_name_auto_disc = new_pgcfg.site_name_auto_disc; 2364 2365 if (DBG(CONFIG, 1)) { 2366 if (changed) 2367 idmapdlog(LOG_NOTICE, "Configuration changed"); 2368 else 2369 idmapdlog(LOG_NOTICE, "Configuration unchanged"); 2370 } 2371 2372 UNLOCK_CONFIG(); 2373 2374 if (dc_changed) { 2375 notify_dc_changed(); 2376 } 2377 2378 /* 2379 * Discovery2 can take a while. 2380 */ 2381 if (flags & CFG_DISCOVER) { 2382 if (live_pgcfg->domain_name != NULL && 2383 live_pgcfg->forest_name != NULL) 2384 idmap_cfg_discover2(&cfg->handles, &new_pgcfg); 2385 ad_disc_done(ad_ctx); 2386 } 2387 2388 WRLOCK_CONFIG(); 2389 2390 /* More props that can be discovered or set in SMF */ 2391 2392 if (update_dirs(&live_pgcfg->global_catalog, 2393 &new_pgcfg.global_catalog, "global_catalog")) { 2394 changed++; 2395 gc_changed = TRUE; 2396 } 2397 live_pgcfg->global_catalog_auto_disc = 2398 new_pgcfg.global_catalog_auto_disc; 2399 2400 /* Props that are only discovered (never in SMF) */ 2401 2402 if (update_domains_in_forest(&live_pgcfg->domains_in_forest, 2403 &new_pgcfg.domains_in_forest, "domains_in_forest")) { 2404 changed++; 2405 gc_changed = TRUE; 2406 } 2407 2408 if (update_trusted_domains(&live_pgcfg->trusted_domains, 2409 &new_pgcfg.trusted_domains, "trusted_domains")) { 2410 changed++; 2411 if (live_pgcfg->trusted_domains != NULL && 2412 live_pgcfg->trusted_domains[0].domain[0] != '\0') 2413 gc_changed = TRUE; 2414 } 2415 2416 if (update_trusted_forest(&live_pgcfg->trusted_forests, 2417 &live_pgcfg->num_trusted_forests, &new_pgcfg.trusted_forests, 2418 &new_pgcfg.num_trusted_forests, "trusted_forest")) { 2419 changed++; 2420 if (live_pgcfg->trusted_forests != NULL) 2421 gc_changed = TRUE; 2422 } 2423 2424 if (DBG(CONFIG, 1)) { 2425 if (changed) 2426 idmapdlog(LOG_NOTICE, "Configuration changed"); 2427 else 2428 idmapdlog(LOG_NOTICE, "Configuration unchanged"); 2429 } 2430 2431 UNLOCK_CONFIG(); 2432 2433 if (dc_changed) 2434 reload_dcs(); 2435 if (gc_changed) 2436 reload_gcs(); 2437 2438 idmap_cfg_unload(&new_pgcfg); 2439 2440 err: 2441 (void) pthread_mutex_unlock(&cfg->handles.mutex); 2442 2443 if (rc < -1) 2444 return (rc); 2445 2446 return ((errors == 0) ? 0 : -1); 2447 } 2448 2449 /* 2450 * Initialize 'cfg'. 2451 */ 2452 idmap_cfg_t * 2453 idmap_cfg_init() 2454 { 2455 idmap_cfg_handles_t *handles; 2456 2457 /* First the smf repository handles: */ 2458 idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t)); 2459 if (!cfg) { 2460 idmapdlog(LOG_ERR, "Out of memory"); 2461 return (NULL); 2462 } 2463 handles = &cfg->handles; 2464 2465 (void) pthread_mutex_init(&handles->mutex, NULL); 2466 2467 if (!(handles->main = scf_handle_create(SCF_VERSION))) { 2468 idmapdlog(LOG_ERR, "scf_handle_create() failed: %s", 2469 scf_strerror(scf_error())); 2470 goto error; 2471 } 2472 2473 if (scf_handle_bind(handles->main) < 0) { 2474 idmapdlog(LOG_ERR, "scf_handle_bind() failed: %s", 2475 scf_strerror(scf_error())); 2476 goto error; 2477 } 2478 2479 if (!(handles->service = scf_service_create(handles->main)) || 2480 !(handles->instance = scf_instance_create(handles->main)) || 2481 !(handles->config_pg = scf_pg_create(handles->main)) || 2482 !(handles->debug_pg = scf_pg_create(handles->main))) { 2483 idmapdlog(LOG_ERR, "scf handle creation failed: %s", 2484 scf_strerror(scf_error())); 2485 goto error; 2486 } 2487 2488 if (scf_handle_decode_fmri(handles->main, 2489 FMRI_BASE "/:properties/" CONFIG_PG, 2490 NULL, /* scope */ 2491 handles->service, /* service */ 2492 handles->instance, /* instance */ 2493 handles->config_pg, /* pg */ 2494 NULL, /* prop */ 2495 SCF_DECODE_FMRI_EXACT) < 0) { 2496 idmapdlog(LOG_ERR, "scf_handle_decode_fmri() failed: %s", 2497 scf_strerror(scf_error())); 2498 goto error; 2499 } 2500 2501 if (scf_service_get_pg(handles->service, 2502 DEBUG_PG, handles->debug_pg) < 0) { 2503 idmapdlog(LOG_ERR, "Property group \"%s\": %s", 2504 DEBUG_PG, scf_strerror(scf_error())); 2505 goto error; 2506 } 2507 2508 check_smf_debug_mode(handles); 2509 2510 /* Initialize AD Auto Discovery context */ 2511 handles->ad_ctx = ad_disc_init(); 2512 if (handles->ad_ctx == NULL) 2513 goto error; 2514 2515 return (cfg); 2516 2517 error: 2518 (void) idmap_cfg_fini(cfg); 2519 return (NULL); 2520 } 2521 2522 void 2523 idmap_cfg_unload(idmap_pg_config_t *pgcfg) 2524 { 2525 2526 if (pgcfg->default_domain) { 2527 free(pgcfg->default_domain); 2528 pgcfg->default_domain = NULL; 2529 } 2530 if (pgcfg->domain_name) { 2531 free(pgcfg->domain_name); 2532 pgcfg->domain_name = NULL; 2533 } 2534 if (pgcfg->domain_guid) { 2535 free(pgcfg->domain_guid); 2536 pgcfg->domain_guid = NULL; 2537 } 2538 if (pgcfg->machine_sid) { 2539 free(pgcfg->machine_sid); 2540 pgcfg->machine_sid = NULL; 2541 } 2542 if (pgcfg->domain_controller) { 2543 free(pgcfg->domain_controller); 2544 pgcfg->domain_controller = NULL; 2545 } 2546 if (pgcfg->forest_name) { 2547 free(pgcfg->forest_name); 2548 pgcfg->forest_name = NULL; 2549 } 2550 if (pgcfg->site_name) { 2551 free(pgcfg->site_name); 2552 pgcfg->site_name = NULL; 2553 } 2554 if (pgcfg->global_catalog) { 2555 free(pgcfg->global_catalog); 2556 pgcfg->global_catalog = NULL; 2557 } 2558 if (pgcfg->trusted_domains) { 2559 free(pgcfg->trusted_domains); 2560 pgcfg->trusted_domains = NULL; 2561 } 2562 if (pgcfg->trusted_forests) 2563 free_trusted_forests(&pgcfg->trusted_forests, 2564 &pgcfg->num_trusted_forests); 2565 2566 if (pgcfg->ad_unixuser_attr) { 2567 free(pgcfg->ad_unixuser_attr); 2568 pgcfg->ad_unixuser_attr = NULL; 2569 } 2570 if (pgcfg->ad_unixgroup_attr) { 2571 free(pgcfg->ad_unixgroup_attr); 2572 pgcfg->ad_unixgroup_attr = NULL; 2573 } 2574 if (pgcfg->nldap_winname_attr) { 2575 free(pgcfg->nldap_winname_attr); 2576 pgcfg->nldap_winname_attr = NULL; 2577 } 2578 } 2579 2580 int 2581 idmap_cfg_fini(idmap_cfg_t *cfg) 2582 { 2583 idmap_cfg_handles_t *handles = &cfg->handles; 2584 idmap_cfg_unload(&cfg->pgcfg); 2585 2586 (void) pthread_mutex_destroy(&handles->mutex); 2587 scf_pg_destroy(handles->config_pg); 2588 if (handles->debug_pg != NULL) 2589 scf_pg_destroy(handles->debug_pg); 2590 scf_instance_destroy(handles->instance); 2591 scf_service_destroy(handles->service); 2592 scf_handle_destroy(handles->main); 2593 if (handles->ad_ctx != NULL) 2594 ad_disc_fini(handles->ad_ctx); 2595 free(cfg); 2596 2597 return (0); 2598 } 2599 2600 void 2601 idmap_cfg_poke_updates(void) 2602 { 2603 int prev_st; 2604 2605 if (DBG(CONFIG, 1)) { 2606 idmapdlog(LOG_INFO, "idmap_cfg_poke_updates"); 2607 } 2608 2609 (void) mutex_lock(&_idmapdstate.addisc_lk); 2610 prev_st = _idmapdstate.addisc_st; 2611 _idmapdstate.addisc_st |= ADDISC_ST_REQUESTED; 2612 (void) mutex_unlock(&_idmapdstate.addisc_lk); 2613 2614 if (prev_st & ADDISC_ST_REQUESTED) { 2615 idmapdlog(LOG_DEBUG, "already poked"); 2616 } else { 2617 idmapdlog(LOG_DEBUG, "port send poke"); 2618 (void) port_send(idmapd_ev_port, POKE_AUTO_DISCOVERY, NULL); 2619 } 2620 } 2621 2622 void 2623 idmap_cfg_force_rediscovery(void) 2624 { 2625 int prev_st; 2626 2627 if (DBG(CONFIG, 1)) { 2628 idmapdlog(LOG_INFO, "idmap_cfg_force_rediscovery"); 2629 } 2630 2631 (void) mutex_lock(&_idmapdstate.addisc_lk); 2632 prev_st = _idmapdstate.addisc_st; 2633 _idmapdstate.addisc_st |= ADDISC_ST_REQUESTED; 2634 (void) mutex_unlock(&_idmapdstate.addisc_lk); 2635 2636 if (prev_st & ADDISC_ST_REQUESTED) { 2637 idmapdlog(LOG_DEBUG, "already kicked"); 2638 } else { 2639 idmapdlog(LOG_DEBUG, "port send kick"); 2640 (void) port_send(idmapd_ev_port, KICK_AUTO_DISCOVERY, NULL); 2641 } 2642 } 2643 2644 /*ARGSUSED*/ 2645 void 2646 idmap_cfg_hup_handler(int sig) 2647 { 2648 if (idmapd_ev_port >= 0) 2649 (void) port_send(idmapd_ev_port, RECONFIGURE, NULL); 2650 } 2651 2652 /* 2653 * Upgrade the debug flags. 2654 * 2655 * We're replacing a single debug flag with a fine-grained mechanism that 2656 * is also capable of considerably more verbosity. We'll take a stab at 2657 * producing roughly the same level of output. 2658 */ 2659 static 2660 int 2661 upgrade_debug(idmap_cfg_handles_t *handles) 2662 { 2663 boolean_t debug_present; 2664 const char DEBUG_PROP[] = "debug"; 2665 int rc; 2666 2667 rc = prop_exists(handles, DEBUG_PROP, &debug_present); 2668 2669 if (rc != 0) 2670 return (rc); 2671 2672 if (!debug_present) 2673 return (0); 2674 2675 idmapdlog(LOG_INFO, 2676 "Upgrading old %s/%s setting to %s/* settings.", 2677 CONFIG_PG, DEBUG_PROP, DEBUG_PG); 2678 2679 rc = set_val_integer(handles, handles->debug_pg, "config", 1); 2680 if (rc != 0) 2681 return (rc); 2682 rc = set_val_integer(handles, handles->debug_pg, "discovery", 1); 2683 if (rc != 0) 2684 return (rc); 2685 2686 rc = del_val(handles, handles->config_pg, DEBUG_PROP); 2687 if (rc != 0) 2688 return (rc); 2689 2690 return (0); 2691 } 2692 2693 /* 2694 * Upgrade the DS mapping flags. 2695 * 2696 * If the old ds_name_mapping_enabled flag is present, then 2697 * if the new directory_based_mapping value is present, then 2698 * if the two are compatible, delete the old and note it 2699 * else delete the old and warn 2700 * else 2701 * set the new based on the old, and note it 2702 * delete the old 2703 */ 2704 static 2705 int 2706 upgrade_directory_mapping(idmap_cfg_handles_t *handles) 2707 { 2708 boolean_t legacy_ds_name_mapping_present; 2709 const char DS_NAME_MAPPING_ENABLED[] = "ds_name_mapping_enabled"; 2710 const char DIRECTORY_BASED_MAPPING[] = "directory_based_mapping"; 2711 int rc; 2712 2713 rc = prop_exists(handles, DS_NAME_MAPPING_ENABLED, 2714 &legacy_ds_name_mapping_present); 2715 2716 if (rc != 0) 2717 return (rc); 2718 2719 if (!legacy_ds_name_mapping_present) 2720 return (0); 2721 2722 boolean_t legacy_ds_name_mapping_enabled; 2723 rc = get_val_bool(handles, DS_NAME_MAPPING_ENABLED, 2724 &legacy_ds_name_mapping_enabled, B_FALSE); 2725 if (rc != 0) 2726 return (rc); 2727 2728 char *legacy_mode; 2729 char *legacy_bool_string; 2730 if (legacy_ds_name_mapping_enabled) { 2731 legacy_mode = "name"; 2732 legacy_bool_string = "true"; 2733 } else { 2734 legacy_mode = "none"; 2735 legacy_bool_string = "false"; 2736 } 2737 2738 char *directory_based_mapping; 2739 rc = get_val_astring(handles, DIRECTORY_BASED_MAPPING, 2740 &directory_based_mapping); 2741 if (rc != 0) 2742 return (rc); 2743 2744 if (directory_based_mapping == NULL) { 2745 idmapdlog(LOG_INFO, 2746 "Upgrading old %s=%s setting\n" 2747 "to %s=%s.", 2748 DS_NAME_MAPPING_ENABLED, legacy_bool_string, 2749 DIRECTORY_BASED_MAPPING, legacy_mode); 2750 rc = set_val_astring(handles, handles->config_pg, 2751 DIRECTORY_BASED_MAPPING, legacy_mode); 2752 if (rc != 0) 2753 return (rc); 2754 } else { 2755 boolean_t new_name_mapping; 2756 if (strcasecmp(directory_based_mapping, "name") == 0) 2757 new_name_mapping = B_TRUE; 2758 else 2759 new_name_mapping = B_FALSE; 2760 2761 if (legacy_ds_name_mapping_enabled == new_name_mapping) { 2762 idmapdlog(LOG_INFO, 2763 "Automatically removing old %s=%s setting\n" 2764 "in favor of %s=%s.", 2765 DS_NAME_MAPPING_ENABLED, legacy_bool_string, 2766 DIRECTORY_BASED_MAPPING, directory_based_mapping); 2767 } else { 2768 idmapdlog(LOG_WARNING, 2769 "Removing conflicting %s=%s setting\n" 2770 "in favor of %s=%s.", 2771 DS_NAME_MAPPING_ENABLED, legacy_bool_string, 2772 DIRECTORY_BASED_MAPPING, directory_based_mapping); 2773 } 2774 free(directory_based_mapping); 2775 } 2776 2777 rc = del_val(handles, handles->config_pg, DS_NAME_MAPPING_ENABLED); 2778 if (rc != 0) 2779 return (rc); 2780 2781 return (0); 2782 } 2783 2784 /* 2785 * Do whatever is necessary to upgrade idmap's configuration before 2786 * we load it. 2787 */ 2788 int 2789 idmap_cfg_upgrade(idmap_cfg_t *cfg) 2790 { 2791 int rc; 2792 2793 rc = upgrade_directory_mapping(&cfg->handles); 2794 if (rc != 0) 2795 return (rc); 2796 2797 rc = upgrade_debug(&cfg->handles); 2798 if (rc != 0) 2799 return (rc); 2800 2801 return (0); 2802 } 2803 2804 /* 2805 * The LDAP code passes principal names lacking any 2806 * realm information, which causes mech_krb5 to do 2807 * awful things trying to figure out the realm. 2808 * Avoid that by making sure it has a default, 2809 * even when krb5.conf is not configured. 2810 */ 2811 static void 2812 idmapd_set_krb5_realm(char *domain) 2813 { 2814 static char realm[MAXHOSTNAMELEN]; 2815 size_t ilen, olen; 2816 int err; 2817 2818 if (domain == NULL) { 2819 (void) unsetenv("KRB5_DEFAULT_REALM"); 2820 return; 2821 } 2822 2823 /* Convert to upper case, in place. */ 2824 (void) strlcpy(realm, domain, sizeof (realm)); 2825 olen = ilen = strlen(realm); 2826 (void) u8_textprep_str(realm, &ilen, realm, &olen, 2827 U8_TEXTPREP_TOUPPER, U8_UNICODE_LATEST, &err); 2828 2829 (void) setenv("KRB5_DEFAULT_REALM", realm, 1); 2830 } 2831