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 */ 24 25 26 /* 27 * Config routines common to idmap(1M) and idmapd(1M) 28 */ 29 30 #include <stdlib.h> 31 #include <strings.h> 32 #include <libintl.h> 33 #include <ctype.h> 34 #include <errno.h> 35 #include "idmapd.h" 36 #include <stdio.h> 37 #include <stdarg.h> 38 #include <uuid/uuid.h> 39 #include <pthread.h> 40 #include <port.h> 41 #include <net/route.h> 42 #include <sys/u8_textprep.h> 43 #include "addisc.h" 44 45 #define MACHINE_SID_LEN (9 + 3 * 11) 46 #define FMRI_BASE "svc:/system/idmap" 47 #define CONFIG_PG "config" 48 #define GENERAL_PG "general" 49 #define RECONFIGURE 1 50 #define POKE_AUTO_DISCOVERY 2 51 52 enum event_type { 53 EVENT_NOTHING, /* Woke up for no good reason */ 54 EVENT_TIMEOUT, /* Timeout expired */ 55 EVENT_ROUTING, /* An interesting routing event happened */ 56 EVENT_DEGRADE, /* An error occurred in the mainline */ 57 EVENT_REFRESH, /* SMF refresh */ 58 }; 59 60 /*LINTLIBRARY*/ 61 62 63 static pthread_t update_thread_handle = 0; 64 65 static int idmapd_ev_port = -1; 66 static int rt_sock = -1; 67 68 struct enum_lookup_map directory_mapping_map[] = { 69 { DIRECTORY_MAPPING_NONE, "none" }, 70 { DIRECTORY_MAPPING_NAME, "name" }, 71 { DIRECTORY_MAPPING_IDMU, "idmu" }, 72 { 0, NULL }, 73 }; 74 75 static int 76 generate_machine_sid(char **machine_sid) 77 { 78 char *p; 79 uuid_t uu; 80 int i, j, len, rlen; 81 uint32_t rid; 82 83 /* 84 * Generate and split 128-bit UUID into three 32-bit RIDs The 85 * machine_sid will be of the form S-1-5-21-N1-N2-N3 (that's 86 * four RIDs altogether). 87 * 88 * Technically we could use up to 14 random RIDs here, but it 89 * turns out that with some versions of Windows using SIDs with 90 * more than five RIDs in security descriptors causes problems. 91 */ 92 93 *machine_sid = calloc(1, MACHINE_SID_LEN); 94 if (*machine_sid == NULL) { 95 idmapdlog(LOG_ERR, "Out of memory"); 96 return (-1); 97 } 98 (void) strcpy(*machine_sid, "S-1-5-21"); 99 p = *machine_sid + strlen("S-1-5-21"); 100 len = MACHINE_SID_LEN - strlen("S-1-5-21"); 101 102 uuid_clear(uu); 103 uuid_generate_random(uu); 104 105 #if UUID_LEN != 16 106 #error UUID size is not 16! 107 #endif 108 109 for (i = 0; i < 3; i++) { 110 j = i * 4; 111 rid = (uu[j] << 24) | (uu[j + 1] << 16) | 112 (uu[j + 2] << 8) | (uu[j + 3]); 113 rlen = snprintf(p, len, "-%u", rid); 114 p += rlen; 115 len -= rlen; 116 } 117 118 return (0); 119 } 120 121 122 /* In the case of error, exists is set to FALSE anyway */ 123 static int 124 prop_exists(idmap_cfg_handles_t *handles, const char *name, boolean_t *exists) 125 { 126 127 scf_property_t *scf_prop; 128 scf_value_t *value; 129 130 *exists = B_FALSE; 131 132 scf_prop = scf_property_create(handles->main); 133 if (scf_prop == NULL) { 134 idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 135 scf_strerror(scf_error())); 136 return (-1); 137 } 138 value = scf_value_create(handles->main); 139 if (value == NULL) { 140 idmapdlog(LOG_ERR, "scf_value_create() failed: %s", 141 scf_strerror(scf_error())); 142 scf_property_destroy(scf_prop); 143 return (-1); 144 } 145 146 if (scf_pg_get_property(handles->config_pg, name, scf_prop) == 0) 147 *exists = B_TRUE; 148 149 scf_value_destroy(value); 150 scf_property_destroy(scf_prop); 151 152 return (0); 153 } 154 155 /* Check if in the case of failure the original value of *val is preserved */ 156 static int 157 get_val_int(idmap_cfg_handles_t *handles, const char *name, 158 void *val, scf_type_t type) 159 { 160 int rc = 0; 161 162 scf_property_t *scf_prop; 163 scf_value_t *value; 164 uint8_t b; 165 166 switch (type) { 167 case SCF_TYPE_BOOLEAN: 168 *(boolean_t *)val = B_FALSE; 169 break; 170 case SCF_TYPE_COUNT: 171 *(uint64_t *)val = 0; 172 break; 173 case SCF_TYPE_INTEGER: 174 *(int64_t *)val = 0; 175 break; 176 default: 177 idmapdlog(LOG_ERR, "Invalid scf integer type (%d)", 178 type); 179 abort(); 180 } 181 182 scf_prop = scf_property_create(handles->main); 183 if (scf_prop == NULL) { 184 idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 185 scf_strerror(scf_error())); 186 return (-1); 187 } 188 value = scf_value_create(handles->main); 189 if (value == NULL) { 190 idmapdlog(LOG_ERR, "scf_value_create() failed: %s", 191 scf_strerror(scf_error())); 192 scf_property_destroy(scf_prop); 193 return (-1); 194 } 195 196 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) 197 /* this is OK: the property is just undefined */ 198 goto destruction; 199 200 201 if (scf_property_get_value(scf_prop, value) < 0) 202 /* It is still OK when a property doesn't have any value */ 203 goto destruction; 204 205 switch (type) { 206 case SCF_TYPE_BOOLEAN: 207 rc = scf_value_get_boolean(value, &b); 208 *(boolean_t *)val = b; 209 break; 210 case SCF_TYPE_COUNT: 211 rc = scf_value_get_count(value, val); 212 break; 213 case SCF_TYPE_INTEGER: 214 rc = scf_value_get_integer(value, val); 215 break; 216 default: 217 abort(); /* tested above */ 218 /* NOTREACHED */ 219 } 220 221 if (rc != 0) { 222 idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s", 223 name, scf_strerror(scf_error())); 224 } 225 226 destruction: 227 scf_value_destroy(value); 228 scf_property_destroy(scf_prop); 229 230 return (rc); 231 } 232 233 static char * 234 scf_value2string(const char *name, scf_value_t *value) 235 { 236 static size_t max_val = 0; 237 238 if (max_val == 0) 239 max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 240 241 char buf[max_val + 1]; 242 if (scf_value_get_astring(value, buf, max_val + 1) < 0) { 243 idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s", 244 name, scf_strerror(scf_error())); 245 return (NULL); 246 } 247 248 char *s = strdup(buf); 249 if (s == NULL) 250 idmapdlog(LOG_ERR, "Out of memory"); 251 252 return (s); 253 } 254 255 static int 256 get_val_ds(idmap_cfg_handles_t *handles, const char *name, int defport, 257 idmap_ad_disc_ds_t **val) 258 { 259 idmap_ad_disc_ds_t *servers = NULL; 260 scf_property_t *scf_prop; 261 scf_value_t *value; 262 scf_iter_t *iter; 263 char *host, *portstr; 264 int len, i; 265 int count = 0; 266 int rc = -1; 267 268 *val = NULL; 269 270 restart: 271 scf_prop = scf_property_create(handles->main); 272 if (scf_prop == NULL) { 273 idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 274 scf_strerror(scf_error())); 275 return (-1); 276 } 277 278 value = scf_value_create(handles->main); 279 if (value == NULL) { 280 idmapdlog(LOG_ERR, "scf_value_create() failed: %s", 281 scf_strerror(scf_error())); 282 scf_property_destroy(scf_prop); 283 return (-1); 284 } 285 286 iter = scf_iter_create(handles->main); 287 if (iter == NULL) { 288 idmapdlog(LOG_ERR, "scf_iter_create() failed: %s", 289 scf_strerror(scf_error())); 290 scf_value_destroy(value); 291 scf_property_destroy(scf_prop); 292 return (-1); 293 } 294 295 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) { 296 /* this is OK: the property is just undefined */ 297 rc = 0; 298 goto destruction; 299 } 300 301 if (scf_iter_property_values(iter, scf_prop) < 0) { 302 idmapdlog(LOG_ERR, 303 "scf_iter_property_values(%s) failed: %s", 304 name, scf_strerror(scf_error())); 305 goto destruction; 306 } 307 308 /* Workaround scf bugs -- can't reset an iteration */ 309 if (count == 0) { 310 while (scf_iter_next_value(iter, value) > 0) 311 count++; 312 313 if (count == 0) { 314 /* no values */ 315 rc = 0; 316 goto destruction; 317 } 318 319 scf_value_destroy(value); 320 scf_iter_destroy(iter); 321 scf_property_destroy(scf_prop); 322 goto restart; 323 } 324 325 if ((servers = calloc(count + 1, sizeof (*servers))) == NULL) { 326 idmapdlog(LOG_ERR, "Out of memory"); 327 goto destruction; 328 } 329 330 i = 0; 331 while (i < count && scf_iter_next_value(iter, value) > 0) { 332 servers[i].priority = 0; 333 servers[i].weight = 100; 334 servers[i].port = defport; 335 if ((host = scf_value2string(name, value)) == NULL) { 336 goto destruction; 337 } 338 if ((portstr = strchr(host, ':')) != NULL) { 339 *portstr++ = '\0'; 340 servers[i].port = strtol(portstr, 341 (char **)NULL, 10); 342 if (servers[i].port == 0) 343 servers[i].port = defport; 344 } 345 len = strlcpy(servers[i].host, host, 346 sizeof (servers->host)); 347 348 free(host); 349 350 /* Ignore this server if the hostname is too long */ 351 if (len < sizeof (servers->host)) 352 i++; 353 } 354 355 *val = servers; 356 357 rc = 0; 358 359 destruction: 360 scf_value_destroy(value); 361 scf_iter_destroy(iter); 362 scf_property_destroy(scf_prop); 363 364 if (rc < 0) { 365 if (servers) 366 free(servers); 367 *val = NULL; 368 } 369 370 return (rc); 371 } 372 373 374 static int 375 get_val_astring(idmap_cfg_handles_t *handles, const char *name, char **val) 376 { 377 int rc = 0; 378 379 scf_property_t *scf_prop; 380 scf_value_t *value; 381 382 scf_prop = scf_property_create(handles->main); 383 if (scf_prop == NULL) { 384 idmapdlog(LOG_ERR, "scf_property_create() failed: %s", 385 scf_strerror(scf_error())); 386 return (-1); 387 } 388 value = scf_value_create(handles->main); 389 if (value == NULL) { 390 idmapdlog(LOG_ERR, "scf_value_create() failed: %s", 391 scf_strerror(scf_error())); 392 scf_property_destroy(scf_prop); 393 return (-1); 394 } 395 396 *val = NULL; 397 398 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) 399 /* this is OK: the property is just undefined */ 400 goto destruction; 401 402 if (scf_property_get_value(scf_prop, value) < 0) { 403 idmapdlog(LOG_ERR, 404 "scf_property_get_value(%s) failed: %s", 405 name, scf_strerror(scf_error())); 406 rc = -1; 407 goto destruction; 408 } 409 410 *val = scf_value2string(name, value); 411 if (*val == NULL) 412 rc = -1; 413 414 destruction: 415 scf_value_destroy(value); 416 scf_property_destroy(scf_prop); 417 418 if (rc < 0) { 419 if (*val) 420 free(*val); 421 *val = NULL; 422 } 423 424 return (rc); 425 } 426 427 428 static int 429 del_val(idmap_cfg_handles_t *handles, const char *name) 430 { 431 int rc = -1; 432 int ret; 433 scf_transaction_t *tx = NULL; 434 scf_transaction_entry_t *ent = NULL; 435 436 if ((tx = scf_transaction_create(handles->main)) == NULL) { 437 idmapdlog(LOG_ERR, 438 "scf_transaction_create() failed: %s", 439 scf_strerror(scf_error())); 440 goto destruction; 441 } 442 if ((ent = scf_entry_create(handles->main)) == NULL) { 443 idmapdlog(LOG_ERR, 444 "scf_entry_create() failed: %s", 445 scf_strerror(scf_error())); 446 goto destruction; 447 } 448 449 do { 450 if (scf_pg_update(handles->config_pg) == -1) { 451 idmapdlog(LOG_ERR, 452 "scf_pg_update(%s) failed: %s", 453 name, scf_strerror(scf_error())); 454 goto destruction; 455 } 456 if (scf_transaction_start(tx, handles->config_pg) != 0) { 457 idmapdlog(LOG_ERR, 458 "scf_transaction_start(%s) failed: %s", 459 name, scf_strerror(scf_error())); 460 goto destruction; 461 } 462 463 if (scf_transaction_property_delete(tx, ent, name) != 0) { 464 /* Don't complain if it already doesn't exist. */ 465 if (scf_error() != SCF_ERROR_NOT_FOUND) { 466 idmapdlog(LOG_ERR, 467 "scf_transaction_property_delete() failed:" 468 " %s", 469 scf_strerror(scf_error())); 470 } 471 goto destruction; 472 } 473 474 ret = scf_transaction_commit(tx); 475 476 if (ret == 0) 477 scf_transaction_reset(tx); 478 } while (ret == 0); 479 480 if (ret == -1) { 481 idmapdlog(LOG_ERR, 482 "scf_transaction_commit(%s) failed: %s", 483 name, scf_strerror(scf_error())); 484 goto destruction; 485 } 486 487 rc = 0; 488 489 destruction: 490 if (ent != NULL) 491 scf_entry_destroy(ent); 492 if (tx != NULL) 493 scf_transaction_destroy(tx); 494 return (rc); 495 } 496 497 498 static int 499 set_val_astring(idmap_cfg_handles_t *handles, const char *name, const char *val) 500 { 501 int rc = -1; 502 int ret = -2; 503 int i; 504 scf_property_t *scf_prop = NULL; 505 scf_value_t *value = NULL; 506 scf_transaction_t *tx = NULL; 507 scf_transaction_entry_t *ent = NULL; 508 509 if ((scf_prop = scf_property_create(handles->main)) == NULL || 510 (value = scf_value_create(handles->main)) == NULL || 511 (tx = scf_transaction_create(handles->main)) == NULL || 512 (ent = scf_entry_create(handles->main)) == NULL) { 513 idmapdlog(LOG_ERR, "Unable to set property %s", 514 name, scf_strerror(scf_error())); 515 goto destruction; 516 } 517 518 for (i = 0; i < MAX_TRIES && (ret == -2 || ret == 0); i++) { 519 if (scf_transaction_start(tx, handles->config_pg) == -1) { 520 idmapdlog(LOG_ERR, 521 "scf_transaction_start(%s) failed: %s", 522 name, scf_strerror(scf_error())); 523 goto destruction; 524 } 525 526 if (scf_transaction_property_new(tx, ent, name, 527 SCF_TYPE_ASTRING) < 0) { 528 idmapdlog(LOG_ERR, 529 "scf_transaction_property_new() failed: %s", 530 scf_strerror(scf_error())); 531 goto destruction; 532 } 533 534 if (scf_value_set_astring(value, val) == -1) { 535 idmapdlog(LOG_ERR, 536 "scf_value_set_astring() failed: %s", 537 scf_strerror(scf_error())); 538 goto destruction; 539 } 540 541 if (scf_entry_add_value(ent, value) == -1) { 542 idmapdlog(LOG_ERR, 543 "scf_entry_add_value() failed: %s", 544 scf_strerror(scf_error())); 545 goto destruction; 546 } 547 548 if ((ret = scf_transaction_commit(tx)) == 1) 549 break; 550 551 if (ret == 0 && i < MAX_TRIES - 1) { 552 /* 553 * Property group set in scf_transaction_start() 554 * is not the most recent. Update pg, reset tx and 555 * retry tx. 556 */ 557 idmapdlog(LOG_WARNING, 558 "scf_transaction_commit(%s) failed - Retry: %s", 559 name, scf_strerror(scf_error())); 560 if (scf_pg_update(handles->config_pg) == -1) { 561 idmapdlog(LOG_ERR, 562 "scf_pg_update() failed: %s", 563 scf_strerror(scf_error())); 564 goto destruction; 565 } 566 scf_transaction_reset(tx); 567 } 568 } 569 570 571 if (ret == 1) 572 rc = 0; 573 else if (ret != -2) 574 idmapdlog(LOG_ERR, 575 "scf_transaction_commit(%s) failed: %s", 576 name, scf_strerror(scf_error())); 577 578 destruction: 579 scf_value_destroy(value); 580 scf_entry_destroy(ent); 581 scf_transaction_destroy(tx); 582 scf_property_destroy(scf_prop); 583 return (rc); 584 } 585 586 587 588 /* 589 * This function updates a boolean value. 590 * If nothing has changed it returns 0 else 1 591 */ 592 static int 593 update_bool(boolean_t *value, boolean_t *new, char *name) 594 { 595 if (*value == *new) 596 return (0); 597 598 idmapdlog(LOG_INFO, "change %s=%s", name, *new ? "true" : "false"); 599 *value = *new; 600 return (1); 601 } 602 603 604 /* 605 * This function updates a string value. 606 * If nothing has changed it returns 0 else 1 607 */ 608 static int 609 update_string(char **value, char **new, char *name) 610 { 611 if (*new == NULL) 612 return (0); 613 614 if (*value != NULL && strcmp(*new, *value) == 0) { 615 free(*new); 616 *new = NULL; 617 return (0); 618 } 619 620 idmapdlog(LOG_INFO, "change %s=%s", name, CHECK_NULL(*new)); 621 if (*value != NULL) 622 free(*value); 623 *value = *new; 624 *new = NULL; 625 return (1); 626 } 627 628 static int 629 update_enum(int *value, int *new, char *name, struct enum_lookup_map *map) 630 { 631 if (*value == *new) 632 return (0); 633 634 idmapdlog(LOG_INFO, "change %s=%s", name, enum_lookup(*new, map)); 635 636 *value = *new; 637 638 return (1); 639 } 640 641 /* 642 * This function updates a directory service structure. 643 * If nothing has changed it returns 0 else 1 644 */ 645 static int 646 update_dirs(idmap_ad_disc_ds_t **value, idmap_ad_disc_ds_t **new, char *name) 647 { 648 int i; 649 650 if (*value == *new) 651 /* Nothing to do */ 652 return (0); 653 654 if (*value != NULL && *new != NULL && 655 ad_disc_compare_ds(*value, *new) == 0) { 656 free(*new); 657 *new = NULL; 658 return (0); 659 } 660 661 if (*value != NULL) 662 free(*value); 663 664 *value = *new; 665 *new = NULL; 666 667 if (*value == NULL) { 668 /* We're unsetting this DS property */ 669 idmapdlog(LOG_INFO, "change %s=<none>", name); 670 return (1); 671 } 672 673 /* List all the new DSs */ 674 for (i = 0; (*value)[i].host[0] != '\0'; i++) 675 idmapdlog(LOG_INFO, "change %s=%s port=%d", name, 676 (*value)[i].host, (*value)[i].port); 677 return (1); 678 } 679 680 /* 681 * This function updates a trusted domains structure. 682 * If nothing has changed it returns 0 else 1 683 */ 684 static int 685 update_trusted_domains(ad_disc_trusteddomains_t **value, 686 ad_disc_trusteddomains_t **new, char *name) 687 { 688 int i; 689 690 if (*value == *new) 691 /* Nothing to do */ 692 return (0); 693 694 if (*value != NULL && *new != NULL && 695 ad_disc_compare_trusteddomains(*value, *new) == 0) { 696 free(*new); 697 *new = NULL; 698 return (0); 699 } 700 701 if (*value != NULL) 702 free(*value); 703 704 *value = *new; 705 *new = NULL; 706 707 if (*value == NULL) { 708 /* We're unsetting this DS property */ 709 idmapdlog(LOG_INFO, "change %s=<none>", name); 710 return (1); 711 } 712 713 /* List all the new domains */ 714 for (i = 0; (*value)[i].domain[0] != '\0'; i++) 715 idmapdlog(LOG_INFO, "change %s=%s direction=%s", name, 716 (*value)[i].domain, 717 (*value)[i].direction == 3 ? "bi-directional" : "inbound"); 718 return (1); 719 } 720 721 722 /* 723 * This function updates a domains in a forest structure. 724 * If nothing has changed it returns 0 else 1 725 */ 726 static int 727 update_domains_in_forest(ad_disc_domainsinforest_t **value, 728 ad_disc_domainsinforest_t **new, char *name) 729 { 730 int i; 731 732 if (*value == *new) 733 /* Nothing to do */ 734 return (0); 735 736 if (*value != NULL && *new != NULL && 737 ad_disc_compare_domainsinforest(*value, *new) == 0) { 738 free(*new); 739 *new = NULL; 740 return (0); 741 } 742 743 if (*value != NULL) 744 free(*value); 745 746 *value = *new; 747 *new = NULL; 748 749 if (*value == NULL) { 750 /* We're unsetting this DS property */ 751 idmapdlog(LOG_INFO, "change %s=<none>", name); 752 return (1); 753 } 754 755 /* List all the new domains */ 756 for (i = 0; (*value)[i].domain[0] != '\0'; i++) 757 idmapdlog(LOG_INFO, "change %s=%s", name, 758 (*value)[i].domain); 759 return (1); 760 } 761 762 763 static void 764 free_trusted_forests(idmap_trustedforest_t **value, int *num_values) 765 { 766 int i; 767 768 for (i = 0; i < *num_values; i++) { 769 free((*value)[i].forest_name); 770 free((*value)[i].global_catalog); 771 free((*value)[i].domains_in_forest); 772 } 773 free(*value); 774 *value = NULL; 775 *num_values = 0; 776 } 777 778 779 static int 780 compare_trusteddomainsinforest(ad_disc_domainsinforest_t *df1, 781 ad_disc_domainsinforest_t *df2) 782 { 783 int i, j; 784 int num_df1 = 0; 785 int num_df2 = 0; 786 boolean_t match; 787 788 for (i = 0; df1[i].domain[0] != '\0'; i++) 789 if (df1[i].trusted) 790 num_df1++; 791 792 for (j = 0; df2[j].domain[0] != '\0'; j++) 793 if (df2[j].trusted) 794 num_df2++; 795 796 if (num_df1 != num_df2) 797 return (1); 798 799 for (i = 0; df1[i].domain[0] != '\0'; i++) { 800 if (df1[i].trusted) { 801 match = B_FALSE; 802 for (j = 0; df2[j].domain[0] != '\0'; j++) { 803 if (df2[j].trusted && 804 domain_eq(df1[i].domain, df2[j].domain) && 805 strcmp(df1[i].sid, df2[j].sid) == 0) { 806 match = B_TRUE; 807 break; 808 } 809 } 810 if (!match) 811 return (1); 812 } 813 } 814 return (0); 815 } 816 817 818 819 /* 820 * This function updates trusted forest structure. 821 * If nothing has changed it returns 0 else 1 822 */ 823 static int 824 update_trusted_forest(idmap_trustedforest_t **value, int *num_value, 825 idmap_trustedforest_t **new, int *num_new, char *name) 826 { 827 int i, j; 828 boolean_t match; 829 830 if (*value == *new) 831 /* Nothing to do */ 832 return (0); 833 834 if (*value != NULL && *new != NULL) { 835 if (*num_value != *num_new) 836 goto not_equal; 837 for (i = 0; i < *num_value; i++) { 838 match = B_FALSE; 839 for (j = 0; j < *num_new; j++) { 840 if (strcmp((*value)[i].forest_name, 841 (*new)[j].forest_name) == 0 && 842 ad_disc_compare_ds( 843 (*value)[i].global_catalog, 844 (*new)[j].global_catalog) == 0 && 845 compare_trusteddomainsinforest( 846 (*value)[i].domains_in_forest, 847 (*new)[j].domains_in_forest) == 0) { 848 match = B_TRUE; 849 break; 850 } 851 } 852 if (!match) 853 goto not_equal; 854 } 855 free_trusted_forests(new, num_new); 856 return (0); 857 } 858 not_equal: 859 if (*value != NULL) 860 free_trusted_forests(value, num_value); 861 *value = *new; 862 *num_value = *num_new; 863 *new = NULL; 864 *num_new = 0; 865 866 if (*value == NULL) { 867 /* We're unsetting this DS property */ 868 idmapdlog(LOG_INFO, "change %s=<none>", name); 869 return (1); 870 } 871 872 /* List all the trusted forests */ 873 for (i = 0; i < *num_value; i++) { 874 for (j = 0; (*value)[i].domains_in_forest[j].domain[0] != '\0'; 875 j++) { 876 /* List trusted Domains in the forest. */ 877 if ((*value)[i].domains_in_forest[j].trusted) 878 idmapdlog(LOG_INFO, "change %s=%s domain=%s", 879 name, (*value)[i].forest_name, 880 (*value)[i].domains_in_forest[j].domain); 881 } 882 /* List the hosts */ 883 for (j = 0; (*value)[i].global_catalog[j].host[0] != '\0'; j++) 884 idmapdlog(LOG_INFO, "change %s=%s host=%s port=%d", 885 name, (*value)[i].forest_name, 886 (*value)[i].global_catalog[j].host, 887 (*value)[i].global_catalog[j].port); 888 } 889 return (1); 890 } 891 892 const char * 893 enum_lookup(int value, struct enum_lookup_map *map) 894 { 895 for (; map->string != NULL; map++) { 896 if (value == map->value) { 897 return (map->string); 898 } 899 } 900 return ("(invalid)"); 901 } 902 903 /* 904 * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the 905 * interfaces. 906 * 907 * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON. 908 */ 909 static 910 boolean_t 911 pfroute_event_is_interesting(int rt_sock) 912 { 913 int nbytes; 914 int64_t msg[2048 / 8]; 915 struct rt_msghdr *rtm; 916 boolean_t is_interesting = B_FALSE; 917 918 for (;;) { 919 if ((nbytes = read(rt_sock, msg, sizeof (msg))) <= 0) 920 break; 921 rtm = (struct rt_msghdr *)msg; 922 if (rtm->rtm_version != RTM_VERSION) 923 continue; 924 if (nbytes < rtm->rtm_msglen) 925 continue; 926 switch (rtm->rtm_type) { 927 case RTM_NEWADDR: 928 case RTM_DELADDR: 929 case RTM_IFINFO: 930 is_interesting = B_TRUE; 931 break; 932 default: 933 break; 934 } 935 } 936 return (is_interesting); 937 } 938 939 /* 940 * Wait for an event, and report what kind of event occurred. 941 * 942 * Note that there are cases where we are awoken but don't care about 943 * the lower-level event. We can't just loop here because we can't 944 * readily calculate how long to sleep the next time. We return 945 * EVENT_NOTHING and let the caller loop. 946 */ 947 static 948 enum event_type 949 wait_for_event(struct timespec *timeoutp) 950 { 951 port_event_t pe; 952 953 memset(&pe, 0, sizeof (pe)); 954 if (port_get(idmapd_ev_port, &pe, timeoutp) != 0) { 955 switch (errno) { 956 case EINTR: 957 return (EVENT_NOTHING); 958 case ETIME: 959 /* Timeout */ 960 return (EVENT_TIMEOUT); 961 default: 962 /* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */ 963 idmapdlog(LOG_ERR, "Event port failed: %s", 964 strerror(errno)); 965 exit(1); 966 /* NOTREACHED */ 967 } 968 } 969 970 971 switch (pe.portev_source) { 972 case 0: 973 /* 974 * This isn't documented, but seems to be what you get if 975 * the timeout is zero seconds and there are no events 976 * pending. 977 */ 978 return (EVENT_TIMEOUT); 979 980 case PORT_SOURCE_USER: 981 if (pe.portev_events == POKE_AUTO_DISCOVERY) 982 return (EVENT_DEGRADE); 983 if (pe.portev_events == RECONFIGURE) 984 return (EVENT_REFRESH); 985 break; 986 987 case PORT_SOURCE_FD: 988 if (pe.portev_object == rt_sock) { 989 /* 990 * PF_ROUTE socket read event: 991 * re-associate fd 992 * handle event 993 */ 994 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, 995 rt_sock, POLLIN, NULL) != 0) { 996 idmapdlog(LOG_ERR, "Failed to re-associate the " 997 "routing socket with the event port: %s", 998 strerror(errno)); 999 abort(); 1000 } 1001 /* 1002 * The network configuration may still be in flux. 1003 * No matter, the resolver will re-transmit and 1004 * timeout if need be. 1005 */ 1006 if (pfroute_event_is_interesting(rt_sock)) { 1007 idmapdlog(LOG_DEBUG, 1008 "Interesting routing event"); 1009 return (EVENT_ROUTING); 1010 } else { 1011 idmapdlog(LOG_DEBUG, 1012 "Boring routing event"); 1013 return (EVENT_NOTHING); 1014 } 1015 } 1016 /* Event on an FD other than the routing FD? Ignore it. */ 1017 break; 1018 } 1019 1020 return (EVENT_NOTHING); 1021 } 1022 1023 void * 1024 idmap_cfg_update_thread(void *arg) 1025 { 1026 1027 const ad_disc_t ad_ctx = _idmapdstate.cfg->handles.ad_ctx; 1028 1029 for (;;) { 1030 struct timespec timeout; 1031 struct timespec *timeoutp; 1032 int rc; 1033 int ttl; 1034 1035 (void) ad_disc_SubnetChanged(ad_ctx); 1036 1037 rc = idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER); 1038 if (rc < -1) { 1039 idmapdlog(LOG_ERR, "Fatal errors while reading " 1040 "SMF properties"); 1041 exit(1); 1042 } else if (rc == -1) { 1043 idmapdlog(LOG_WARNING, 1044 "Errors re-loading configuration may cause AD " 1045 "lookups to fail"); 1046 } 1047 1048 /* 1049 * Wait for an interesting event. Note that we might get 1050 * boring events between interesting events. If so, we loop. 1051 */ 1052 for (;;) { 1053 ttl = ad_disc_get_TTL(ad_ctx); 1054 1055 if (ttl < 0) { 1056 timeoutp = NULL; 1057 } else { 1058 timeoutp = &timeout; 1059 timeout.tv_sec = ttl; 1060 timeout.tv_nsec = 0; 1061 } 1062 1063 switch (wait_for_event(timeoutp)) { 1064 case EVENT_NOTHING: 1065 idmapdlog(LOG_DEBUG, "Boring event."); 1066 continue; 1067 case EVENT_REFRESH: 1068 idmapdlog(LOG_INFO, "SMF refresh"); 1069 /* 1070 * Blow away the ccache, we might have 1071 * re-joined the domain or joined a new one 1072 */ 1073 (void) unlink(IDMAP_CACHEDIR "/ccache"); 1074 break; 1075 case EVENT_DEGRADE: 1076 idmapdlog(LOG_DEBUG, 1077 "Service degraded"); 1078 break; 1079 case EVENT_TIMEOUT: 1080 idmapdlog(LOG_DEBUG, "TTL expired"); 1081 break; 1082 case EVENT_ROUTING: 1083 /* Already logged to DEBUG */ 1084 break; 1085 } 1086 /* An interesting event! */ 1087 break; 1088 } 1089 } 1090 /* 1091 * Lint isn't happy with the concept of a function declared to 1092 * return something, that doesn't return. Of course, merely adding 1093 * the return isn't enough, because it's never reached... 1094 */ 1095 /*NOTREACHED*/ 1096 return (NULL); 1097 } 1098 1099 int 1100 idmap_cfg_start_updates(void) 1101 { 1102 if ((idmapd_ev_port = port_create()) < 0) { 1103 idmapdlog(LOG_ERR, "Failed to create event port: %s", 1104 strerror(errno)); 1105 return (-1); 1106 } 1107 1108 if ((rt_sock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 1109 idmapdlog(LOG_ERR, "Failed to open routing socket: %s", 1110 strerror(errno)); 1111 (void) close(idmapd_ev_port); 1112 return (-1); 1113 } 1114 1115 if (fcntl(rt_sock, F_SETFL, O_NDELAY|O_NONBLOCK) < 0) { 1116 idmapdlog(LOG_ERR, "Failed to set routing socket flags: %s", 1117 strerror(errno)); 1118 (void) close(rt_sock); 1119 (void) close(idmapd_ev_port); 1120 return (-1); 1121 } 1122 1123 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, 1124 rt_sock, POLLIN, NULL) != 0) { 1125 idmapdlog(LOG_ERR, "Failed to associate the routing " 1126 "socket with the event port: %s", strerror(errno)); 1127 (void) close(rt_sock); 1128 (void) close(idmapd_ev_port); 1129 return (-1); 1130 } 1131 1132 if ((errno = pthread_create(&update_thread_handle, NULL, 1133 idmap_cfg_update_thread, NULL)) != 0) { 1134 idmapdlog(LOG_ERR, "Failed to start update thread: %s", 1135 strerror(errno)); 1136 (void) port_dissociate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock); 1137 (void) close(rt_sock); 1138 (void) close(idmapd_ev_port); 1139 return (-1); 1140 } 1141 1142 return (0); 1143 } 1144 1145 /* 1146 * Reject attribute names with invalid characters. 1147 */ 1148 static 1149 int 1150 valid_ldap_attr(const char *attr) { 1151 for (; *attr; attr++) { 1152 if (!isalnum(*attr) && *attr != '-' && 1153 *attr != '_' && *attr != '.' && *attr != ';') 1154 return (0); 1155 } 1156 return (1); 1157 } 1158 1159 static 1160 int 1161 check_smf_debug_mode(idmap_cfg_handles_t *handles) 1162 { 1163 boolean_t new_debug_mode; 1164 int rc; 1165 1166 rc = prop_exists(handles, "debug", &new_debug_mode); 1167 if (rc != 0) 1168 return (rc); 1169 1170 if (_idmapdstate.debug_mode != new_debug_mode) { 1171 if (!_idmapdstate.debug_mode) { 1172 _idmapdstate.debug_mode = new_debug_mode; 1173 idmap_log_stderr(LOG_DEBUG); 1174 idmapdlog(LOG_DEBUG, "debug mode enabled"); 1175 } else { 1176 idmapdlog(LOG_DEBUG, "debug mode disabled"); 1177 idmap_log_stderr(-1); 1178 _idmapdstate.debug_mode = new_debug_mode; 1179 } 1180 } 1181 1182 return (0); 1183 } 1184 1185 /* 1186 * This is the half of idmap_cfg_load() that loads property values from 1187 * SMF (using the config/ property group of the idmap FMRI). 1188 * 1189 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures 1190 * -3 -> hard smf config failures 1191 * reading from SMF. 1192 */ 1193 static 1194 int 1195 idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg, 1196 int * const errors) 1197 { 1198 int rc; 1199 char *s; 1200 1201 *errors = 0; 1202 1203 if (scf_pg_update(handles->config_pg) < 0) { 1204 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s", 1205 scf_strerror(scf_error())); 1206 return (-2); 1207 } 1208 1209 if (scf_pg_update(handles->general_pg) < 0) { 1210 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s", 1211 scf_strerror(scf_error())); 1212 return (-2); 1213 } 1214 1215 rc = check_smf_debug_mode(handles); 1216 if (rc != 0) 1217 (*errors)++; 1218 1219 rc = get_val_int(handles, "unresolvable_sid_mapping", 1220 &pgcfg->eph_map_unres_sids, SCF_TYPE_BOOLEAN); 1221 if (rc != 0) 1222 (*errors)++; 1223 1224 rc = get_val_astring(handles, "directory_based_mapping", &s); 1225 if (rc != 0) 1226 (*errors)++; 1227 else if (s == NULL || strcasecmp(s, "none") == 0) 1228 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE; 1229 else if (strcasecmp(s, "name") == 0) 1230 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NAME; 1231 else if (strcasecmp(s, "idmu") == 0) 1232 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_IDMU; 1233 else { 1234 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE; 1235 idmapdlog(LOG_ERR, 1236 "config/directory_based_mapping: invalid value \"%s\" ignored", 1237 s); 1238 (*errors)++; 1239 } 1240 free(s); 1241 1242 rc = get_val_int(handles, "list_size_limit", 1243 &pgcfg->list_size_limit, SCF_TYPE_COUNT); 1244 if (rc != 0) 1245 (*errors)++; 1246 1247 rc = get_val_astring(handles, "domain_name", 1248 &pgcfg->domain_name); 1249 if (rc != 0) 1250 (*errors)++; 1251 else { 1252 (void) ad_disc_set_DomainName(handles->ad_ctx, 1253 pgcfg->domain_name); 1254 pgcfg->domain_name_auto_disc = B_FALSE; 1255 } 1256 1257 rc = get_val_astring(handles, "default_domain", 1258 &pgcfg->default_domain); 1259 if (rc != 0) { 1260 /* 1261 * SCF failures fetching config/default_domain we treat 1262 * as fatal as they may leave ID mapping rules that 1263 * match unqualified winnames flapping in the wind. 1264 */ 1265 return (-2); 1266 } 1267 1268 if (pgcfg->default_domain == NULL && pgcfg->domain_name != NULL) { 1269 pgcfg->default_domain = strdup(pgcfg->domain_name); 1270 } 1271 1272 rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid); 1273 if (rc != 0) 1274 (*errors)++; 1275 if (pgcfg->machine_sid == NULL) { 1276 /* If machine_sid not configured, generate one */ 1277 if (generate_machine_sid(&pgcfg->machine_sid) < 0) 1278 return (-2); 1279 rc = set_val_astring(handles, "machine_sid", 1280 pgcfg->machine_sid); 1281 if (rc != 0) 1282 (*errors)++; 1283 } 1284 1285 rc = get_val_ds(handles, "domain_controller", 389, 1286 &pgcfg->domain_controller); 1287 if (rc != 0) 1288 (*errors)++; 1289 else { 1290 (void) ad_disc_set_DomainController(handles->ad_ctx, 1291 pgcfg->domain_controller); 1292 pgcfg->domain_controller_auto_disc = B_FALSE; 1293 } 1294 1295 rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name); 1296 if (rc != 0) 1297 (*errors)++; 1298 else { 1299 (void) ad_disc_set_ForestName(handles->ad_ctx, 1300 pgcfg->forest_name); 1301 pgcfg->forest_name_auto_disc = B_FALSE; 1302 } 1303 1304 rc = get_val_astring(handles, "site_name", &pgcfg->site_name); 1305 if (rc != 0) 1306 (*errors)++; 1307 else 1308 (void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name); 1309 1310 rc = get_val_ds(handles, "global_catalog", 3268, 1311 &pgcfg->global_catalog); 1312 if (rc != 0) 1313 (*errors)++; 1314 else { 1315 (void) ad_disc_set_GlobalCatalog(handles->ad_ctx, 1316 pgcfg->global_catalog); 1317 pgcfg->global_catalog_auto_disc = B_FALSE; 1318 } 1319 1320 /* Unless we're doing directory-based name mapping, we're done. */ 1321 if (pgcfg->directory_based_mapping != DIRECTORY_MAPPING_NAME) 1322 return (0); 1323 1324 rc = get_val_astring(handles, "ad_unixuser_attr", 1325 &pgcfg->ad_unixuser_attr); 1326 if (rc != 0) 1327 return (-2); 1328 if (pgcfg->ad_unixuser_attr != NULL && 1329 !valid_ldap_attr(pgcfg->ad_unixuser_attr)) { 1330 idmapdlog(LOG_ERR, "config/ad_unixuser_attr=%s is not a " 1331 "valid LDAP attribute name", pgcfg->ad_unixuser_attr); 1332 return (-3); 1333 } 1334 1335 rc = get_val_astring(handles, "ad_unixgroup_attr", 1336 &pgcfg->ad_unixgroup_attr); 1337 if (rc != 0) 1338 return (-2); 1339 if (pgcfg->ad_unixgroup_attr != NULL && 1340 !valid_ldap_attr(pgcfg->ad_unixgroup_attr)) { 1341 idmapdlog(LOG_ERR, "config/ad_unixgroup_attr=%s is not a " 1342 "valid LDAP attribute name", pgcfg->ad_unixgroup_attr); 1343 return (-3); 1344 } 1345 1346 rc = get_val_astring(handles, "nldap_winname_attr", 1347 &pgcfg->nldap_winname_attr); 1348 if (rc != 0) 1349 return (-2); 1350 if (pgcfg->nldap_winname_attr != NULL && 1351 !valid_ldap_attr(pgcfg->nldap_winname_attr)) { 1352 idmapdlog(LOG_ERR, "config/nldap_winname_attr=%s is not a " 1353 "valid LDAP attribute name", pgcfg->nldap_winname_attr); 1354 return (-3); 1355 } 1356 if (pgcfg->ad_unixuser_attr == NULL && 1357 pgcfg->ad_unixgroup_attr == NULL && 1358 pgcfg->nldap_winname_attr == NULL) { 1359 idmapdlog(LOG_ERR, 1360 "If config/directory_based_mapping property is set to " 1361 "\"name\" then at least one of the following name mapping " 1362 "attributes must be specified. (config/ad_unixuser_attr OR " 1363 "config/ad_unixgroup_attr OR config/nldap_winname_attr)"); 1364 return (-3); 1365 } 1366 1367 return (rc); 1368 1369 } 1370 1371 1372 /* 1373 * This is the half of idmap_cfg_load() that auto-discovers values of 1374 * discoverable properties that weren't already set via SMF properties. 1375 * 1376 * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it 1377 * needs to be careful not to overwrite any properties set in SMF. 1378 */ 1379 static 1380 void 1381 idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) 1382 { 1383 ad_disc_t ad_ctx = handles->ad_ctx; 1384 ad_disc_t trusted_ctx; 1385 int i, j, k, l; 1386 char *forestname; 1387 int num_trusteddomains; 1388 boolean_t new_forest; 1389 char *trusteddomain; 1390 idmap_ad_disc_ds_t *globalcatalog; 1391 idmap_trustedforest_t *trustedforests; 1392 ad_disc_domainsinforest_t *domainsinforest; 1393 1394 idmapdlog(LOG_DEBUG, "Running discovery."); 1395 1396 ad_disc_refresh(ad_ctx); 1397 1398 if (pgcfg->default_domain == NULL) 1399 pgcfg->default_domain = ad_disc_get_DomainName(ad_ctx, 1400 NULL); 1401 1402 if (pgcfg->domain_name == NULL) 1403 pgcfg->domain_name = ad_disc_get_DomainName(ad_ctx, 1404 &pgcfg->domain_name_auto_disc); 1405 1406 if (pgcfg->domain_controller == NULL) 1407 pgcfg->domain_controller = 1408 ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE, 1409 &pgcfg->domain_controller_auto_disc); 1410 1411 if (pgcfg->forest_name == NULL) 1412 pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx, 1413 &pgcfg->forest_name_auto_disc); 1414 1415 if (pgcfg->site_name == NULL) 1416 pgcfg->site_name = ad_disc_get_SiteName(ad_ctx, 1417 &pgcfg->site_name_auto_disc); 1418 1419 if (pgcfg->global_catalog == NULL) 1420 pgcfg->global_catalog = 1421 ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE, 1422 &pgcfg->global_catalog_auto_disc); 1423 1424 pgcfg->domains_in_forest = 1425 ad_disc_get_DomainsInForest(ad_ctx, NULL); 1426 1427 pgcfg->trusted_domains = 1428 ad_disc_get_TrustedDomains(ad_ctx, NULL); 1429 1430 if (pgcfg->forest_name != NULL && pgcfg->trusted_domains != NULL && 1431 pgcfg->trusted_domains[0].domain[0] != '\0') { 1432 /* 1433 * We have trusted domains. We need to go through every 1434 * one and find its forest. If it is a new forest we then need 1435 * to find its Global Catalog and the domains in the forest 1436 */ 1437 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++) 1438 continue; 1439 num_trusteddomains = i; 1440 1441 trustedforests = calloc(num_trusteddomains, 1442 sizeof (idmap_trustedforest_t)); 1443 j = 0; 1444 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++) { 1445 trusteddomain = pgcfg->trusted_domains[i].domain; 1446 trusted_ctx = ad_disc_init(); 1447 ad_disc_set_DomainName(trusted_ctx, 1448 trusteddomain); 1449 forestname = 1450 ad_disc_get_ForestName(trusted_ctx, NULL); 1451 if (forestname == NULL) { 1452 idmapdlog(LOG_DEBUG, "unable to discover " 1453 "Forest Name for the trusted domain %s", 1454 trusteddomain); 1455 ad_disc_fini(trusted_ctx); 1456 continue; 1457 } 1458 1459 if (strcasecmp(forestname, pgcfg->forest_name) == 0) { 1460 /* 1461 * Ignore the domain as it is part of 1462 * the primary forest 1463 */ 1464 free(forestname); 1465 ad_disc_fini(trusted_ctx); 1466 continue; 1467 } 1468 1469 /* Is this a new forest? */ 1470 new_forest = B_TRUE; 1471 for (k = 0; k < j; k++) { 1472 if (strcasecmp(forestname, 1473 trustedforests[k].forest_name) == 0) { 1474 new_forest = B_FALSE; 1475 domainsinforest = 1476 trustedforests[k].domains_in_forest; 1477 break; 1478 } 1479 } 1480 if (!new_forest) { 1481 /* Mark the domain as trusted */ 1482 for (l = 0; 1483 domainsinforest[l].domain[0] != '\0'; l++) { 1484 if (domain_eq(trusteddomain, 1485 domainsinforest[l].domain)) { 1486 domainsinforest[l].trusted = 1487 TRUE; 1488 break; 1489 } 1490 } 1491 free(forestname); 1492 ad_disc_fini(trusted_ctx); 1493 continue; 1494 } 1495 1496 /* 1497 * Get the Global Catalog and the domains in 1498 * this new forest. 1499 */ 1500 globalcatalog = 1501 ad_disc_get_GlobalCatalog(trusted_ctx, 1502 AD_DISC_PREFER_SITE, NULL); 1503 if (globalcatalog == NULL) { 1504 idmapdlog(LOG_DEBUG, 1505 "unable to discover Global " 1506 "Catalog for the trusted domain %s", 1507 trusteddomain); 1508 free(forestname); 1509 ad_disc_fini(trusted_ctx); 1510 continue; 1511 } 1512 domainsinforest = 1513 ad_disc_get_DomainsInForest(trusted_ctx, 1514 NULL); 1515 if (domainsinforest == NULL) { 1516 idmapdlog(LOG_DEBUG, 1517 "unable to discover Domains in the Forest " 1518 "for the trusted domain %s", 1519 trusteddomain); 1520 free(globalcatalog); 1521 free(forestname); 1522 ad_disc_fini(trusted_ctx); 1523 continue; 1524 } 1525 1526 trustedforests[j].forest_name = forestname; 1527 trustedforests[j].global_catalog = globalcatalog; 1528 trustedforests[j].domains_in_forest = domainsinforest; 1529 j++; 1530 /* Mark the domain as trusted */ 1531 for (l = 0; domainsinforest[l].domain[0] != '\0'; 1532 l++) { 1533 if (domain_eq(trusteddomain, 1534 domainsinforest[l].domain)) { 1535 domainsinforest[l].trusted = TRUE; 1536 break; 1537 } 1538 } 1539 ad_disc_fini(trusted_ctx); 1540 } 1541 if (j > 0) { 1542 pgcfg->num_trusted_forests = j; 1543 pgcfg->trusted_forests = trustedforests; 1544 } else { 1545 free(trustedforests); 1546 } 1547 } 1548 1549 if (pgcfg->domain_name == NULL) 1550 idmapdlog(LOG_DEBUG, "unable to discover Domain Name"); 1551 if (pgcfg->domain_controller == NULL) 1552 idmapdlog(LOG_DEBUG, "unable to discover Domain Controller"); 1553 if (pgcfg->forest_name == NULL) 1554 idmapdlog(LOG_DEBUG, "unable to discover Forest Name"); 1555 if (pgcfg->site_name == NULL) 1556 idmapdlog(LOG_DEBUG, "unable to discover Site Name"); 1557 if (pgcfg->global_catalog == NULL) 1558 idmapdlog(LOG_DEBUG, "unable to discover Global Catalog"); 1559 if (pgcfg->domains_in_forest == NULL) 1560 idmapdlog(LOG_DEBUG, 1561 "unable to discover Domains in the Forest"); 1562 if (pgcfg->trusted_domains == NULL) 1563 idmapdlog(LOG_DEBUG, "unable to discover Trusted Domains"); 1564 1565 ad_disc_done(ad_ctx); 1566 idmapdlog(LOG_DEBUG, "Discovery done."); 1567 } 1568 1569 1570 /* 1571 * idmap_cfg_load() is called at startup, and periodically via the 1572 * update thread when the auto-discovery TTLs expire, as well as part of 1573 * the refresh method, to update the current configuration. It always 1574 * reads from SMF, but you still have to refresh the service after 1575 * changing the config pg in order for the changes to take effect. 1576 * 1577 * There are two flags: 1578 * 1579 * - CFG_DISCOVER 1580 * - CFG_LOG 1581 * 1582 * If CFG_DISCOVER is set then idmap_cfg_load() calls 1583 * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property 1584 * values that weren't set in SMF. 1585 * 1586 * If CFG_LOG is set then idmap_cfg_load() will log (to LOG_NOTICE) 1587 * whether the configuration changed. This should be used only from the 1588 * refresh method. 1589 * 1590 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures 1591 * reading from SMF. 1592 */ 1593 int 1594 idmap_cfg_load(idmap_cfg_t *cfg, int flags) 1595 { 1596 int rc = 0; 1597 int errors; 1598 int changed = 0; 1599 int ad_reload_required = 0; 1600 idmap_pg_config_t new_pgcfg, *live_pgcfg; 1601 1602 live_pgcfg = &cfg->pgcfg; 1603 (void) memset(&new_pgcfg, 0, sizeof (new_pgcfg)); 1604 1605 pthread_mutex_lock(&cfg->handles.mutex); 1606 1607 if ((rc = idmap_cfg_load_smf(&cfg->handles, &new_pgcfg, &errors)) < -1) 1608 goto err; 1609 1610 if (flags & CFG_DISCOVER) 1611 idmap_cfg_discover(&cfg->handles, &new_pgcfg); 1612 1613 WRLOCK_CONFIG(); 1614 if (live_pgcfg->list_size_limit != new_pgcfg.list_size_limit) { 1615 idmapdlog(LOG_INFO, "change list_size=%d", 1616 new_pgcfg.list_size_limit); 1617 live_pgcfg->list_size_limit = new_pgcfg.list_size_limit; 1618 } 1619 1620 /* Non-discoverable props updated here */ 1621 changed += update_string(&live_pgcfg->machine_sid, 1622 &new_pgcfg.machine_sid, "machine_sid"); 1623 1624 changed += update_bool(&live_pgcfg->eph_map_unres_sids, 1625 &new_pgcfg.eph_map_unres_sids, "unresolvable_sid_mapping"); 1626 1627 changed += update_enum(&live_pgcfg->directory_based_mapping, 1628 &new_pgcfg.directory_based_mapping, "directory_based_mapping", 1629 directory_mapping_map); 1630 1631 changed += update_string(&live_pgcfg->ad_unixuser_attr, 1632 &new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr"); 1633 1634 changed += update_string(&live_pgcfg->ad_unixgroup_attr, 1635 &new_pgcfg.ad_unixgroup_attr, "ad_unixgroup_attr"); 1636 1637 changed += update_string(&live_pgcfg->nldap_winname_attr, 1638 &new_pgcfg.nldap_winname_attr, "nldap_winname_attr"); 1639 1640 /* Props that can be discovered and set in SMF updated here */ 1641 changed += update_string(&live_pgcfg->default_domain, 1642 &new_pgcfg.default_domain, "default_domain"); 1643 1644 changed += update_string(&live_pgcfg->domain_name, 1645 &new_pgcfg.domain_name, "domain_name"); 1646 live_pgcfg->domain_name_auto_disc = new_pgcfg.domain_name_auto_disc; 1647 1648 changed += update_dirs(&live_pgcfg->domain_controller, 1649 &new_pgcfg.domain_controller, "domain_controller"); 1650 live_pgcfg->domain_controller_auto_disc = 1651 new_pgcfg.domain_controller_auto_disc; 1652 1653 changed += update_string(&live_pgcfg->forest_name, 1654 &new_pgcfg.forest_name, "forest_name"); 1655 live_pgcfg->forest_name_auto_disc = new_pgcfg.forest_name_auto_disc; 1656 1657 changed += update_string(&live_pgcfg->site_name, 1658 &new_pgcfg.site_name, "site_name"); 1659 live_pgcfg->site_name_auto_disc = new_pgcfg.site_name_auto_disc; 1660 1661 if (update_dirs(&live_pgcfg->global_catalog, 1662 &new_pgcfg.global_catalog, "global_catalog")) { 1663 changed++; 1664 if (live_pgcfg->global_catalog != NULL && 1665 live_pgcfg->global_catalog[0].host[0] != '\0') 1666 ad_reload_required = TRUE; 1667 } 1668 live_pgcfg->global_catalog_auto_disc = 1669 new_pgcfg.global_catalog_auto_disc; 1670 1671 if (update_domains_in_forest(&live_pgcfg->domains_in_forest, 1672 &new_pgcfg.domains_in_forest, "domains_in_forest")) { 1673 changed++; 1674 ad_reload_required = TRUE; 1675 } 1676 1677 if (update_trusted_domains(&live_pgcfg->trusted_domains, 1678 &new_pgcfg.trusted_domains, "trusted_domains")) { 1679 changed++; 1680 if (live_pgcfg->trusted_domains != NULL && 1681 live_pgcfg->trusted_domains[0].domain[0] != '\0') 1682 ad_reload_required = TRUE; 1683 } 1684 1685 if (update_trusted_forest(&live_pgcfg->trusted_forests, 1686 &live_pgcfg->num_trusted_forests, &new_pgcfg.trusted_forests, 1687 &new_pgcfg.num_trusted_forests, "trusted_forest")) { 1688 changed++; 1689 if (live_pgcfg->trusted_forests != NULL) 1690 ad_reload_required = TRUE; 1691 } 1692 1693 if (ad_reload_required) 1694 reload_ad(); 1695 1696 idmap_cfg_unload(&new_pgcfg); 1697 1698 if (flags & CFG_LOG) { 1699 /* 1700 * If the config changes as a result of a refresh of the 1701 * service, then logging about it can provide useful 1702 * feedback to the sysadmin. 1703 */ 1704 idmapdlog(LOG_NOTICE, "Configuration %schanged", 1705 changed ? "" : "un"); 1706 } 1707 1708 UNLOCK_CONFIG(); 1709 1710 err: 1711 pthread_mutex_unlock(&cfg->handles.mutex); 1712 1713 if (rc < -1) 1714 return (rc); 1715 1716 return ((errors == 0) ? 0 : -1); 1717 } 1718 1719 /* 1720 * Initialize 'cfg'. 1721 */ 1722 idmap_cfg_t * 1723 idmap_cfg_init() 1724 { 1725 idmap_cfg_handles_t *handles; 1726 1727 /* First the smf repository handles: */ 1728 idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t)); 1729 if (!cfg) { 1730 idmapdlog(LOG_ERR, "Out of memory"); 1731 return (NULL); 1732 } 1733 handles = &cfg->handles; 1734 1735 (void) pthread_mutex_init(&handles->mutex, NULL); 1736 1737 if (!(handles->main = scf_handle_create(SCF_VERSION))) { 1738 idmapdlog(LOG_ERR, "scf_handle_create() failed: %s", 1739 scf_strerror(scf_error())); 1740 goto error; 1741 } 1742 1743 if (scf_handle_bind(handles->main) < 0) { 1744 idmapdlog(LOG_ERR, "scf_handle_bind() failed: %s", 1745 scf_strerror(scf_error())); 1746 goto error; 1747 } 1748 1749 if (!(handles->service = scf_service_create(handles->main)) || 1750 !(handles->instance = scf_instance_create(handles->main)) || 1751 !(handles->config_pg = scf_pg_create(handles->main)) || 1752 !(handles->general_pg = scf_pg_create(handles->main))) { 1753 idmapdlog(LOG_ERR, "scf handle creation failed: %s", 1754 scf_strerror(scf_error())); 1755 goto error; 1756 } 1757 1758 if (scf_handle_decode_fmri(handles->main, 1759 FMRI_BASE "/:properties/" CONFIG_PG, 1760 NULL, /* scope */ 1761 handles->service, /* service */ 1762 handles->instance, /* instance */ 1763 handles->config_pg, /* pg */ 1764 NULL, /* prop */ 1765 SCF_DECODE_FMRI_EXACT) < 0) { 1766 idmapdlog(LOG_ERR, "scf_handle_decode_fmri() failed: %s", 1767 scf_strerror(scf_error())); 1768 goto error; 1769 } 1770 1771 if (scf_service_get_pg(handles->service, 1772 GENERAL_PG, handles->general_pg) < 0) { 1773 idmapdlog(LOG_ERR, "scf_service_get_pg() failed: %s", 1774 scf_strerror(scf_error())); 1775 goto error; 1776 } 1777 1778 if (check_smf_debug_mode(handles) != 0) 1779 goto error; 1780 1781 /* Initialize AD Auto Discovery context */ 1782 handles->ad_ctx = ad_disc_init(); 1783 if (handles->ad_ctx == NULL) 1784 goto error; 1785 1786 return (cfg); 1787 1788 error: 1789 (void) idmap_cfg_fini(cfg); 1790 return (NULL); 1791 } 1792 1793 void 1794 idmap_cfg_unload(idmap_pg_config_t *pgcfg) 1795 { 1796 1797 if (pgcfg->default_domain) { 1798 free(pgcfg->default_domain); 1799 pgcfg->default_domain = NULL; 1800 } 1801 if (pgcfg->domain_name) { 1802 free(pgcfg->domain_name); 1803 pgcfg->domain_name = NULL; 1804 } 1805 if (pgcfg->machine_sid) { 1806 free(pgcfg->machine_sid); 1807 pgcfg->machine_sid = NULL; 1808 } 1809 if (pgcfg->domain_controller) { 1810 free(pgcfg->domain_controller); 1811 pgcfg->domain_controller = NULL; 1812 } 1813 if (pgcfg->forest_name) { 1814 free(pgcfg->forest_name); 1815 pgcfg->forest_name = NULL; 1816 } 1817 if (pgcfg->site_name) { 1818 free(pgcfg->site_name); 1819 pgcfg->site_name = NULL; 1820 } 1821 if (pgcfg->global_catalog) { 1822 free(pgcfg->global_catalog); 1823 pgcfg->global_catalog = NULL; 1824 } 1825 if (pgcfg->trusted_domains) { 1826 free(pgcfg->trusted_domains); 1827 pgcfg->trusted_domains = NULL; 1828 } 1829 if (pgcfg->trusted_forests) 1830 free_trusted_forests(&pgcfg->trusted_forests, 1831 &pgcfg->num_trusted_forests); 1832 1833 if (pgcfg->ad_unixuser_attr) { 1834 free(pgcfg->ad_unixuser_attr); 1835 pgcfg->ad_unixuser_attr = NULL; 1836 } 1837 if (pgcfg->ad_unixgroup_attr) { 1838 free(pgcfg->ad_unixgroup_attr); 1839 pgcfg->ad_unixgroup_attr = NULL; 1840 } 1841 if (pgcfg->nldap_winname_attr) { 1842 free(pgcfg->nldap_winname_attr); 1843 pgcfg->nldap_winname_attr = NULL; 1844 } 1845 } 1846 1847 int 1848 idmap_cfg_fini(idmap_cfg_t *cfg) 1849 { 1850 idmap_cfg_handles_t *handles = &cfg->handles; 1851 idmap_cfg_unload(&cfg->pgcfg); 1852 1853 (void) pthread_mutex_destroy(&handles->mutex); 1854 scf_pg_destroy(handles->config_pg); 1855 scf_pg_destroy(handles->general_pg); 1856 scf_instance_destroy(handles->instance); 1857 scf_service_destroy(handles->service); 1858 scf_handle_destroy(handles->main); 1859 if (handles->ad_ctx != NULL) 1860 ad_disc_fini(handles->ad_ctx); 1861 free(cfg); 1862 1863 return (0); 1864 } 1865 1866 void 1867 idmap_cfg_poke_updates(void) 1868 { 1869 if (idmapd_ev_port != -1) 1870 (void) port_send(idmapd_ev_port, POKE_AUTO_DISCOVERY, NULL); 1871 } 1872 1873 /*ARGSUSED*/ 1874 void 1875 idmap_cfg_hup_handler(int sig) 1876 { 1877 if (idmapd_ev_port >= 0) 1878 (void) port_send(idmapd_ev_port, RECONFIGURE, NULL); 1879 } 1880 1881 /* 1882 * Upgrade the DS mapping flags. 1883 * 1884 * If the old ds_name_mapping_enabled flag is present, then 1885 * if the new directory_based_mapping value is present, then 1886 * if the two are compatible, delete the old and note it 1887 * else delete the old and warn 1888 * else 1889 * set the new based on the old, and note it 1890 * delete the old 1891 */ 1892 static 1893 int 1894 upgrade_directory_mapping(idmap_cfg_handles_t *handles) 1895 { 1896 boolean_t legacy_ds_name_mapping_present; 1897 const char DS_NAME_MAPPING_ENABLED[] = "ds_name_mapping_enabled"; 1898 const char DIRECTORY_BASED_MAPPING[] = "directory_based_mapping"; 1899 int rc; 1900 1901 rc = prop_exists(handles, DS_NAME_MAPPING_ENABLED, 1902 &legacy_ds_name_mapping_present); 1903 1904 if (rc != 0) 1905 return (rc); 1906 1907 if (!legacy_ds_name_mapping_present) 1908 return (0); 1909 1910 boolean_t legacy_ds_name_mapping_enabled; 1911 rc = get_val_int(handles, DS_NAME_MAPPING_ENABLED, 1912 &legacy_ds_name_mapping_enabled, SCF_TYPE_BOOLEAN); 1913 if (rc != 0) 1914 return (rc); 1915 1916 char *legacy_mode; 1917 char *legacy_bool_string; 1918 if (legacy_ds_name_mapping_enabled) { 1919 legacy_mode = "name"; 1920 legacy_bool_string = "true"; 1921 } else { 1922 legacy_mode = "none"; 1923 legacy_bool_string = "false"; 1924 } 1925 1926 char *directory_based_mapping; 1927 rc = get_val_astring(handles, DIRECTORY_BASED_MAPPING, 1928 &directory_based_mapping); 1929 if (rc != 0) 1930 return (rc); 1931 1932 if (directory_based_mapping == NULL) { 1933 idmapdlog(LOG_INFO, 1934 "Upgrading old %s=%s setting\n" 1935 "to %s=%s.", 1936 DS_NAME_MAPPING_ENABLED, legacy_bool_string, 1937 DIRECTORY_BASED_MAPPING, legacy_mode); 1938 rc = set_val_astring(handles, DIRECTORY_BASED_MAPPING, 1939 legacy_mode); 1940 if (rc != 0) 1941 return (rc); 1942 } else { 1943 boolean_t new_name_mapping; 1944 if (strcasecmp(directory_based_mapping, "name") == 0) 1945 new_name_mapping = B_TRUE; 1946 else 1947 new_name_mapping = B_FALSE; 1948 1949 if (legacy_ds_name_mapping_enabled == new_name_mapping) { 1950 idmapdlog(LOG_INFO, 1951 "Automatically removing old %s=%s setting\n" 1952 "in favor of %s=%s.", 1953 DS_NAME_MAPPING_ENABLED, legacy_bool_string, 1954 DIRECTORY_BASED_MAPPING, directory_based_mapping); 1955 } else { 1956 idmapdlog(LOG_WARNING, 1957 "Removing conflicting %s=%s setting\n" 1958 "in favor of %s=%s.", 1959 DS_NAME_MAPPING_ENABLED, legacy_bool_string, 1960 DIRECTORY_BASED_MAPPING, directory_based_mapping); 1961 } 1962 free(directory_based_mapping); 1963 } 1964 1965 rc = del_val(handles, DS_NAME_MAPPING_ENABLED); 1966 if (rc != 0) 1967 return (rc); 1968 1969 return (0); 1970 } 1971 1972 /* 1973 * Do whatever is necessary to upgrade idmap's configuration before 1974 * we load it. 1975 */ 1976 int 1977 idmap_cfg_upgrade(idmap_cfg_t *cfg) 1978 { 1979 int rc; 1980 1981 rc = upgrade_directory_mapping(&cfg->handles); 1982 if (rc != 0) 1983 return (rc); 1984 1985 return (0); 1986 } 1987