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