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