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