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