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