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 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, boolean_t *exists) 111 { 112 113 scf_property_t *scf_prop; 114 scf_value_t *value; 115 116 *exists = B_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 = B_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(boolean_t *value, boolean_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 boolean_t match; 699 700 for (i = 0; df1[i].domain[0] != '\0'; i++) 701 if (df1[i].trusted) 702 num_df1++; 703 704 for (j = 0; df2[j].domain[0] != '\0'; j++) 705 if (df2[j].trusted) 706 num_df2++; 707 708 if (num_df1 != num_df2) 709 return (1); 710 711 for (i = 0; df1[i].domain[0] != '\0'; i++) { 712 if (df1[i].trusted) { 713 match = B_FALSE; 714 for (j = 0; df2[j].domain[0] != '\0'; j++) { 715 if (df2[j].trusted && 716 domain_eq(df1[i].domain, df2[j].domain) && 717 strcmp(df1[i].sid, df2[j].sid) == 0) { 718 match = B_TRUE; 719 break; 720 } 721 } 722 if (!match) 723 return (1); 724 } 725 } 726 return (0); 727 } 728 729 730 731 /* 732 * This function updates trusted forest structure. 733 * If nothing has changed it returns 0 else 1 734 */ 735 static int 736 update_trusted_forest(idmap_trustedforest_t **value, int *num_value, 737 idmap_trustedforest_t **new, int *num_new, char *name) 738 { 739 int i, j; 740 boolean_t match; 741 742 if (*value == *new) 743 /* Nothing to do */ 744 return (0); 745 746 if (*value != NULL && *new != NULL) { 747 if (*num_value != *num_new) 748 goto not_equal; 749 for (i = 0; i < *num_value; i++) { 750 match = B_FALSE; 751 for (j = 0; j < *num_new; j++) { 752 if (strcmp((*value)[i].forest_name, 753 (*new)[j].forest_name) == 0 && 754 ad_disc_compare_ds( 755 (*value)[i].global_catalog, 756 (*new)[j].global_catalog) == 0 && 757 compare_trusteddomainsinforest( 758 (*value)[i].domains_in_forest, 759 (*new)[j].domains_in_forest) == 0) { 760 match = B_TRUE; 761 break; 762 } 763 } 764 if (!match) 765 goto not_equal; 766 } 767 free_trusted_forests(new, num_new); 768 return (0); 769 } 770 not_equal: 771 if (*value != NULL) 772 free_trusted_forests(value, num_value); 773 *value = *new; 774 *num_value = *num_new; 775 *new = NULL; 776 *num_new = 0; 777 778 if (*value == NULL) { 779 /* We're unsetting this DS property */ 780 idmapdlog(LOG_INFO, "change %s=<none>", name); 781 return (1); 782 } 783 784 /* List all the trusted forests */ 785 for (i = 0; i < *num_value; i++) { 786 for (j = 0; (*value)[i].domains_in_forest[j].domain[0] != '\0'; 787 j++) { 788 /* List trusted Domains in the forest. */ 789 if ((*value)[i].domains_in_forest[j].trusted) 790 idmapdlog(LOG_INFO, "change %s=%s domain=%s", 791 name, (*value)[i].forest_name, 792 (*value)[i].domains_in_forest[j].domain); 793 } 794 /* List the hosts */ 795 for (j = 0; (*value)[i].global_catalog[j].host[0] != '\0'; j++) 796 idmapdlog(LOG_INFO, "change %s=%s host=%s port=%d", 797 name, (*value)[i].forest_name, 798 (*value)[i].global_catalog[j].host, 799 (*value)[i].global_catalog[j].port); 800 } 801 return (1); 802 } 803 804 805 #define MAX_CHECK_TIME (20 * 60) 806 807 /* 808 * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the 809 * interfaces. 810 * 811 * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON. 812 */ 813 static 814 int 815 pfroute_event_is_interesting(int rt_sock) 816 { 817 int nbytes; 818 int64_t msg[2048 / 8]; 819 struct rt_msghdr *rtm; 820 int is_interesting = FALSE; 821 822 for (;;) { 823 if ((nbytes = read(rt_sock, msg, sizeof (msg))) <= 0) 824 break; 825 rtm = (struct rt_msghdr *)msg; 826 if (rtm->rtm_version != RTM_VERSION) 827 continue; 828 if (nbytes < rtm->rtm_msglen) 829 continue; 830 switch (rtm->rtm_type) { 831 case RTM_NEWADDR: 832 case RTM_DELADDR: 833 case RTM_IFINFO: 834 is_interesting = TRUE; 835 break; 836 default: 837 break; 838 } 839 } 840 return (is_interesting); 841 } 842 843 /* 844 * Returns 1 if SIGHUP has been received (see hup_handler() elsewhere) or if an 845 * interface address was added or removed; otherwise it returns 0. 846 * 847 * Note that port_get() does not update its timeout argument when EINTR, unlike 848 * nanosleep(). We probably don't care very much here, but if we did care then 849 * we could always use a timer event and associate it with the same event port, 850 * then we could get accurate waiting regardless of EINTRs. 851 */ 852 static 853 int 854 wait_for_event(int poke_is_interesting, struct timespec *timeoutp) 855 { 856 port_event_t pe; 857 858 retry: 859 memset(&pe, 0, sizeof (pe)); 860 if (port_get(idmapd_ev_port, &pe, timeoutp) != 0) { 861 switch (errno) { 862 case EINTR: 863 goto retry; 864 case ETIME: 865 /* Timeout */ 866 return (FALSE); 867 default: 868 /* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */ 869 idmapdlog(LOG_ERR, "Event port failed: %s", 870 strerror(errno)); 871 exit(1); 872 /* NOTREACHED */ 873 break; 874 } 875 } 876 877 if (pe.portev_source == PORT_SOURCE_USER && 878 pe.portev_events == POKE_AUTO_DISCOVERY) 879 return (poke_is_interesting ? TRUE : FALSE); 880 881 if (pe.portev_source == PORT_SOURCE_FD && pe.portev_object == rt_sock) { 882 /* PF_ROUTE socket read event, re-associate fd, handle event */ 883 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock, 884 POLLIN, NULL) != 0) { 885 idmapdlog(LOG_ERR, "Failed to re-associate the " 886 "routing socket with the event port: %s", 887 strerror(errno)); 888 exit(1); 889 } 890 /* 891 * The network configuration may still be in flux. No matter, 892 * the resolver will re-transmit and timout if need be. 893 */ 894 return (pfroute_event_is_interesting(rt_sock)); 895 } 896 897 if (pe.portev_source == PORT_SOURCE_USER && 898 pe.portev_events == RECONFIGURE) { 899 int rc; 900 901 /* 902 * Blow away the ccache, we might have re-joined the 903 * domain or joined a new one 904 */ 905 (void) unlink(IDMAP_CACHEDIR "/ccache"); 906 /* HUP is the refresh method, so re-read SMF config */ 907 idmapdlog(LOG_INFO, "SMF refresh"); 908 rc = idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER|CFG_LOG); 909 if (rc < -1) { 910 idmapdlog(LOG_ERR, "Fatal errors while reading " 911 "SMF properties"); 912 exit(1); 913 } else if (rc == -1) { 914 idmapdlog(LOG_WARNING, "Various errors " 915 "re-loading configuration may cause AD lookups " 916 "to fail"); 917 } 918 return (FALSE); 919 } 920 921 return (FALSE); 922 } 923 924 void * 925 idmap_cfg_update_thread(void *arg) 926 { 927 928 int ttl, changed, poke_is_interesting; 929 idmap_cfg_handles_t *handles = &_idmapdstate.cfg->handles; 930 ad_disc_t ad_ctx = handles->ad_ctx; 931 struct timespec timeout, *timeoutp; 932 933 poke_is_interesting = 1; 934 for (ttl = 0, changed = TRUE; ; ttl = ad_disc_get_TTL(ad_ctx)) { 935 /* 936 * If ttl < 0 then we can wait for an event without timing out. 937 * If idmapd needs to notice that the system has been joined to 938 * a Windows domain then idmapd needs to be refreshed. 939 */ 940 timeoutp = (ttl < 0) ? NULL : &timeout; 941 if (ttl > MAX_CHECK_TIME) 942 ttl = MAX_CHECK_TIME; 943 timeout.tv_sec = ttl; 944 timeout.tv_nsec = 0; 945 changed = wait_for_event(poke_is_interesting, timeoutp); 946 947 /* 948 * If there are no interesting events, and this is not the first 949 * time through the loop, and we haven't waited the most that 950 * we're willing to wait, so do nothing but wait some more. 951 */ 952 if (changed == FALSE && ttl > 0 && ttl < MAX_CHECK_TIME) 953 continue; 954 955 (void) ad_disc_SubnetChanged(ad_ctx); 956 957 if (idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER) < -1) { 958 idmapdlog(LOG_ERR, "Fatal errors while reading " 959 "SMF properties"); 960 exit(1); 961 } 962 963 if (_idmapdstate.cfg->pgcfg.global_catalog == NULL || 964 _idmapdstate.cfg->pgcfg.global_catalog[0].host[0] == '\0') 965 poke_is_interesting = 1; 966 else 967 poke_is_interesting = 0; 968 } 969 /*NOTREACHED*/ 970 return (NULL); 971 } 972 973 int 974 idmap_cfg_start_updates(void) 975 { 976 if ((idmapd_ev_port = port_create()) < 0) { 977 idmapdlog(LOG_ERR, "Failed to create event port: %s", 978 strerror(errno)); 979 return (-1); 980 } 981 982 if ((rt_sock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 983 idmapdlog(LOG_ERR, "Failed to open routing socket: %s", 984 strerror(errno)); 985 (void) close(idmapd_ev_port); 986 return (-1); 987 } 988 989 if (fcntl(rt_sock, F_SETFL, O_NDELAY|O_NONBLOCK) < 0) { 990 idmapdlog(LOG_ERR, "Failed to set routing socket flags: %s", 991 strerror(errno)); 992 (void) close(rt_sock); 993 (void) close(idmapd_ev_port); 994 return (-1); 995 } 996 997 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, 998 rt_sock, POLLIN, NULL) != 0) { 999 idmapdlog(LOG_ERR, "Failed to associate the routing " 1000 "socket with the event port: %s", strerror(errno)); 1001 (void) close(rt_sock); 1002 (void) close(idmapd_ev_port); 1003 return (-1); 1004 } 1005 1006 if ((errno = pthread_create(&update_thread_handle, NULL, 1007 idmap_cfg_update_thread, NULL)) != 0) { 1008 idmapdlog(LOG_ERR, "Failed to start update thread: %s", 1009 strerror(errno)); 1010 (void) port_dissociate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock); 1011 (void) close(rt_sock); 1012 (void) close(idmapd_ev_port); 1013 return (-1); 1014 } 1015 1016 return (0); 1017 } 1018 1019 /* 1020 * Reject attribute names with invalid characters. 1021 */ 1022 static 1023 int 1024 valid_ldap_attr(const char *attr) { 1025 for (; *attr; attr++) { 1026 if (!isalnum(*attr) && *attr != '-' && 1027 *attr != '_' && *attr != '.' && *attr != ';') 1028 return (0); 1029 } 1030 return (1); 1031 } 1032 1033 /* 1034 * This is the half of idmap_cfg_load() that loads property values from 1035 * SMF (using the config/ property group of the idmap FMRI). 1036 * 1037 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures 1038 * -3 -> hard smf config failures 1039 * reading from SMF. 1040 */ 1041 static 1042 int 1043 idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg, 1044 int *errors) 1045 { 1046 int rc; 1047 uint8_t bool_val; 1048 char *str = NULL; 1049 boolean_t new_debug_mode; 1050 1051 if (scf_pg_update(handles->config_pg) < 0) { 1052 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s", 1053 scf_strerror(scf_error())); 1054 return (-2); 1055 } 1056 1057 if (scf_pg_update(handles->general_pg) < 0) { 1058 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s", 1059 scf_strerror(scf_error())); 1060 return (-2); 1061 } 1062 1063 1064 rc = prop_exists(handles, "debug", &new_debug_mode); 1065 if (rc != 0) 1066 errors++; 1067 1068 if (_idmapdstate.debug_mode != new_debug_mode) { 1069 if (!_idmapdstate.debug_mode) { 1070 _idmapdstate.debug_mode = new_debug_mode; 1071 idmap_log_stderr(LOG_DEBUG); 1072 idmapdlog(LOG_DEBUG, "debug mode enabled"); 1073 } else { 1074 idmapdlog(LOG_DEBUG, "debug mode disabled"); 1075 idmap_log_stderr(-1); 1076 _idmapdstate.debug_mode = new_debug_mode; 1077 } 1078 } 1079 1080 rc = get_val_int(handles, "unresolvable_sid_mapping", 1081 &pgcfg->eph_map_unres_sids, SCF_TYPE_BOOLEAN); 1082 if (rc != 0) 1083 errors++; 1084 1085 rc = get_val_int(handles, "list_size_limit", 1086 &pgcfg->list_size_limit, SCF_TYPE_COUNT); 1087 if (rc != 0) 1088 errors++; 1089 1090 rc = get_val_astring(handles, "domain_name", 1091 &pgcfg->domain_name); 1092 if (rc != 0) 1093 errors++; 1094 else { 1095 (void) ad_disc_set_DomainName(handles->ad_ctx, 1096 pgcfg->domain_name); 1097 pgcfg->domain_name_auto_disc = B_FALSE; 1098 } 1099 1100 rc = get_val_astring(handles, "default_domain", 1101 &pgcfg->default_domain); 1102 if (rc != 0) { 1103 /* 1104 * SCF failures fetching config/default_domain we treat 1105 * as fatal as they may leave ID mapping rules that 1106 * match unqualified winnames flapping in the wind. 1107 */ 1108 return (-2); 1109 } 1110 1111 rc = get_val_astring(handles, "mapping_domain", &str); 1112 if (rc != 0) 1113 errors++; 1114 1115 /* 1116 * We treat default_domain as having been specified in SMF IFF 1117 * either (the config/default_domain property was set) or (the 1118 * old, obsolete, never documented config/mapping_domain 1119 * property was set and the new config/domain_name property was 1120 * not set). 1121 */ 1122 pgcfg->dflt_dom_set_in_smf = B_TRUE; 1123 if (pgcfg->default_domain == NULL) { 1124 1125 pgcfg->dflt_dom_set_in_smf = B_FALSE; 1126 1127 if (pgcfg->domain_name != NULL) { 1128 pgcfg->default_domain = strdup(pgcfg->domain_name); 1129 if (str != NULL) { 1130 idmapdlog(LOG_WARNING, 1131 "Ignoring obsolete, undocumented " 1132 "config/mapping_domain property"); 1133 } 1134 } else if (str != NULL) { 1135 pgcfg->default_domain = strdup(str); 1136 pgcfg->dflt_dom_set_in_smf = B_TRUE; 1137 idmapdlog(LOG_WARNING, 1138 "The config/mapping_domain property is " 1139 "obsolete; support for it will be removed, " 1140 "please use config/default_domain instead"); 1141 } 1142 } 1143 1144 if (str != NULL) 1145 free(str); 1146 1147 rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid); 1148 if (rc != 0) 1149 errors++; 1150 if (pgcfg->machine_sid == NULL) { 1151 /* If machine_sid not configured, generate one */ 1152 if (generate_machine_sid(&pgcfg->machine_sid) < 0) 1153 return (-2); 1154 rc = set_val_astring(handles, "machine_sid", 1155 pgcfg->machine_sid); 1156 if (rc != 0) 1157 errors++; 1158 } 1159 1160 str = NULL; 1161 rc = get_val_ds(handles, "domain_controller", 389, 1162 &pgcfg->domain_controller); 1163 if (rc != 0) 1164 errors++; 1165 else { 1166 (void) ad_disc_set_DomainController(handles->ad_ctx, 1167 pgcfg->domain_controller); 1168 pgcfg->domain_controller_auto_disc = B_FALSE; 1169 } 1170 1171 rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name); 1172 if (rc != 0) 1173 errors++; 1174 else { 1175 (void) ad_disc_set_ForestName(handles->ad_ctx, 1176 pgcfg->forest_name); 1177 pgcfg->forest_name_auto_disc = B_FALSE; 1178 } 1179 1180 rc = get_val_astring(handles, "site_name", &pgcfg->site_name); 1181 if (rc != 0) 1182 errors++; 1183 else 1184 (void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name); 1185 1186 str = NULL; 1187 rc = get_val_ds(handles, "global_catalog", 3268, 1188 &pgcfg->global_catalog); 1189 if (rc != 0) 1190 errors++; 1191 else { 1192 (void) ad_disc_set_GlobalCatalog(handles->ad_ctx, 1193 pgcfg->global_catalog); 1194 pgcfg->global_catalog_auto_disc = B_FALSE; 1195 } 1196 1197 /* 1198 * Read directory-based name mappings related SMF properties 1199 */ 1200 rc = get_val_int(handles, "ds_name_mapping_enabled", 1201 &bool_val, SCF_TYPE_BOOLEAN); 1202 if (rc != 0) 1203 return (-2); 1204 1205 if (!bool_val) 1206 return (rc); 1207 1208 pgcfg->ds_name_mapping_enabled = B_TRUE; 1209 rc = get_val_astring(handles, "ad_unixuser_attr", 1210 &pgcfg->ad_unixuser_attr); 1211 if (rc != 0) 1212 return (-2); 1213 if (pgcfg->ad_unixuser_attr != NULL && 1214 !valid_ldap_attr(pgcfg->ad_unixuser_attr)) { 1215 idmapdlog(LOG_ERR, "config/ad_unixuser_attr=%s is not a " 1216 "valid LDAP attribute name", pgcfg->ad_unixuser_attr); 1217 return (-3); 1218 } 1219 1220 rc = get_val_astring(handles, "ad_unixgroup_attr", 1221 &pgcfg->ad_unixgroup_attr); 1222 if (rc != 0) 1223 return (-2); 1224 if (pgcfg->ad_unixgroup_attr != NULL && 1225 !valid_ldap_attr(pgcfg->ad_unixgroup_attr)) { 1226 idmapdlog(LOG_ERR, "config/ad_unixgroup_attr=%s is not a " 1227 "valid LDAP attribute name", pgcfg->ad_unixgroup_attr); 1228 return (-3); 1229 } 1230 1231 rc = get_val_astring(handles, "nldap_winname_attr", 1232 &pgcfg->nldap_winname_attr); 1233 if (rc != 0) 1234 return (-2); 1235 if (pgcfg->nldap_winname_attr != NULL && 1236 !valid_ldap_attr(pgcfg->nldap_winname_attr)) { 1237 idmapdlog(LOG_ERR, "config/nldap_winname_attr=%s is not a " 1238 "valid LDAP attribute name", pgcfg->nldap_winname_attr); 1239 return (-3); 1240 } 1241 if (pgcfg->ad_unixuser_attr == NULL && 1242 pgcfg->ad_unixgroup_attr == NULL && 1243 pgcfg->nldap_winname_attr == NULL) { 1244 idmapdlog(LOG_ERR, 1245 "If config/ds_name_mapping_enabled property is set to " 1246 "true then atleast one of the following name mapping " 1247 "attributes must be specified. (config/ad_unixuser_attr OR " 1248 "config/ad_unixgroup_attr OR config/nldap_winname_attr)"); 1249 return (-3); 1250 } 1251 1252 return (rc); 1253 1254 } 1255 1256 1257 /* 1258 * This is the half of idmap_cfg_load() that auto-discovers values of 1259 * discoverable properties that weren't already set via SMF properties. 1260 * 1261 * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it 1262 * needs to be careful not to overwrite any properties set in SMF. 1263 */ 1264 static 1265 void 1266 idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) 1267 { 1268 ad_disc_t ad_ctx = handles->ad_ctx; 1269 ad_disc_t trusted_ctx; 1270 int i, j, k, l; 1271 char *forestname; 1272 int num_trusteddomains; 1273 boolean_t new_forest; 1274 char *trusteddomain; 1275 idmap_ad_disc_ds_t *globalcatalog; 1276 idmap_trustedforest_t *trustedforests; 1277 ad_disc_domainsinforest_t *domainsinforest; 1278 1279 ad_disc_refresh(ad_ctx); 1280 1281 if (pgcfg->default_domain == NULL) 1282 pgcfg->default_domain = ad_disc_get_DomainName(ad_ctx, 1283 NULL); 1284 1285 if (pgcfg->domain_name == NULL) 1286 pgcfg->domain_name = ad_disc_get_DomainName(ad_ctx, 1287 &pgcfg->domain_name_auto_disc); 1288 1289 if (pgcfg->domain_controller == NULL) 1290 pgcfg->domain_controller = 1291 ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE, 1292 &pgcfg->domain_controller_auto_disc); 1293 1294 if (pgcfg->forest_name == NULL) 1295 pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx, 1296 &pgcfg->forest_name_auto_disc); 1297 1298 if (pgcfg->site_name == NULL) 1299 pgcfg->site_name = ad_disc_get_SiteName(ad_ctx, 1300 &pgcfg->site_name_auto_disc); 1301 1302 if (pgcfg->global_catalog == NULL) 1303 pgcfg->global_catalog = 1304 ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE, 1305 &pgcfg->global_catalog_auto_disc); 1306 1307 pgcfg->domains_in_forest = 1308 ad_disc_get_DomainsInForest(ad_ctx, NULL); 1309 1310 pgcfg->trusted_domains = 1311 ad_disc_get_TrustedDomains(ad_ctx, NULL); 1312 1313 if (pgcfg->forest_name != NULL && pgcfg->trusted_domains != NULL && 1314 pgcfg->trusted_domains[0].domain[0] != '\0') { 1315 /* 1316 * We have trusted domains. We need to go through every 1317 * one and find its forest. If it is a new forest we then need 1318 * to find its Global Catalog and the domains in the forest 1319 */ 1320 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++) 1321 continue; 1322 num_trusteddomains = i; 1323 1324 trustedforests = calloc(num_trusteddomains, 1325 sizeof (idmap_trustedforest_t)); 1326 j = 0; 1327 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++) { 1328 trusteddomain = pgcfg->trusted_domains[i].domain; 1329 trusted_ctx = ad_disc_init(); 1330 ad_disc_set_DomainName(trusted_ctx, 1331 trusteddomain); 1332 forestname = 1333 ad_disc_get_ForestName(trusted_ctx, NULL); 1334 if (forestname == NULL) { 1335 idmapdlog(LOG_DEBUG, "unable to discover " 1336 "Forest Name for the trusted domain %s", 1337 trusteddomain); 1338 ad_disc_fini(trusted_ctx); 1339 continue; 1340 } 1341 1342 if (strcasecmp(forestname, pgcfg->forest_name) == 0) { 1343 /* 1344 * Ignore the domain as it is part of 1345 * the primary forest 1346 */ 1347 free(forestname); 1348 ad_disc_fini(trusted_ctx); 1349 continue; 1350 } 1351 1352 /* Is this a new forest? */ 1353 new_forest = B_TRUE; 1354 for (k = 0; k < j; k++) { 1355 if (strcasecmp(forestname, 1356 trustedforests[k].forest_name) == 0) { 1357 new_forest = B_FALSE; 1358 domainsinforest = 1359 trustedforests[k].domains_in_forest; 1360 break; 1361 } 1362 } 1363 if (!new_forest) { 1364 /* Mark the domain as trusted */ 1365 for (l = 0; 1366 domainsinforest[l].domain[0] != '\0'; l++) { 1367 if (domain_eq(trusteddomain, 1368 domainsinforest[l].domain)) { 1369 domainsinforest[l].trusted = 1370 TRUE; 1371 break; 1372 } 1373 } 1374 free(forestname); 1375 ad_disc_fini(trusted_ctx); 1376 continue; 1377 } 1378 1379 /* 1380 * Get the Global Catalog and the domains in 1381 * this new forest. 1382 */ 1383 globalcatalog = 1384 ad_disc_get_GlobalCatalog(trusted_ctx, 1385 AD_DISC_PREFER_SITE, NULL); 1386 if (globalcatalog == NULL) { 1387 idmapdlog(LOG_DEBUG, 1388 "unable to discover Global " 1389 "Catalog for the trusted domain %s", 1390 trusteddomain); 1391 free(forestname); 1392 ad_disc_fini(trusted_ctx); 1393 continue; 1394 } 1395 domainsinforest = 1396 ad_disc_get_DomainsInForest(trusted_ctx, 1397 NULL); 1398 if (domainsinforest == NULL) { 1399 idmapdlog(LOG_DEBUG, 1400 "unable to discover Domains in the Forest " 1401 "for the trusted domain %s", 1402 trusteddomain); 1403 free(globalcatalog); 1404 free(forestname); 1405 ad_disc_fini(trusted_ctx); 1406 continue; 1407 } 1408 1409 trustedforests[j].forest_name = forestname; 1410 trustedforests[j].global_catalog = globalcatalog; 1411 trustedforests[j].domains_in_forest = domainsinforest; 1412 j++; 1413 /* Mark the domain as trusted */ 1414 for (l = 0; domainsinforest[l].domain[0] != '\0'; 1415 l++) { 1416 if (domain_eq(trusteddomain, 1417 domainsinforest[l].domain)) { 1418 domainsinforest[l].trusted = TRUE; 1419 break; 1420 } 1421 } 1422 ad_disc_fini(trusted_ctx); 1423 } 1424 if (j > 0) { 1425 pgcfg->num_trusted_forests = j; 1426 pgcfg->trusted_forests = trustedforests; 1427 } else { 1428 free(trustedforests); 1429 } 1430 } 1431 1432 if (pgcfg->domain_name == NULL) 1433 idmapdlog(LOG_DEBUG, "unable to discover Domain Name"); 1434 if (pgcfg->domain_controller == NULL) 1435 idmapdlog(LOG_DEBUG, "unable to discover Domain Controller"); 1436 if (pgcfg->forest_name == NULL) 1437 idmapdlog(LOG_DEBUG, "unable to discover Forest Name"); 1438 if (pgcfg->site_name == NULL) 1439 idmapdlog(LOG_DEBUG, "unable to discover Site Name"); 1440 if (pgcfg->global_catalog == NULL) 1441 idmapdlog(LOG_DEBUG, "unable to discover Global Catalog"); 1442 if (pgcfg->domains_in_forest == NULL) 1443 idmapdlog(LOG_DEBUG, 1444 "unable to discover Domains in the Forest"); 1445 if (pgcfg->trusted_domains == NULL) 1446 idmapdlog(LOG_DEBUG, "unable to discover Trusted Domains"); 1447 } 1448 1449 1450 /* 1451 * idmap_cfg_load() is called at startup, and periodically via the 1452 * update thread when the auto-discovery TTLs expire, as well as part of 1453 * the refresh method, to update the current configuration. It always 1454 * reads from SMF, but you still have to refresh the service after 1455 * changing the config pg in order for the changes to take effect. 1456 * 1457 * There are two flags: 1458 * 1459 * - CFG_DISCOVER 1460 * - CFG_LOG 1461 * 1462 * If CFG_DISCOVER is set then idmap_cfg_load() calls 1463 * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property 1464 * values that weren't set in SMF. 1465 * 1466 * If CFG_LOG is set then idmap_cfg_load() will log (to LOG_NOTICE) 1467 * whether the configuration changed. This should be used only from the 1468 * refresh method. 1469 * 1470 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures 1471 * reading from SMF. 1472 */ 1473 int 1474 idmap_cfg_load(idmap_cfg_t *cfg, int flags) 1475 { 1476 int rc = 0; 1477 int errors = 0; 1478 int changed = 0; 1479 int ad_reload_required = 0; 1480 idmap_pg_config_t new_pgcfg, *live_pgcfg; 1481 1482 live_pgcfg = &cfg->pgcfg; 1483 (void) memset(&new_pgcfg, 0, sizeof (new_pgcfg)); 1484 1485 pthread_mutex_lock(&cfg->handles.mutex); 1486 1487 if ((rc = idmap_cfg_load_smf(&cfg->handles, &new_pgcfg, &errors)) < -1) 1488 goto err; 1489 1490 if (flags & CFG_DISCOVER) 1491 idmap_cfg_discover(&cfg->handles, &new_pgcfg); 1492 1493 WRLOCK_CONFIG(); 1494 if (live_pgcfg->list_size_limit != new_pgcfg.list_size_limit) { 1495 idmapdlog(LOG_INFO, "change list_size=%d", 1496 new_pgcfg.list_size_limit); 1497 live_pgcfg->list_size_limit = new_pgcfg.list_size_limit; 1498 } 1499 1500 /* Non-discoverable props updated here */ 1501 changed += update_string(&live_pgcfg->machine_sid, 1502 &new_pgcfg.machine_sid, "machine_sid"); 1503 1504 changed += update_bool(&live_pgcfg->eph_map_unres_sids, 1505 &new_pgcfg.eph_map_unres_sids, "unresolvable_sid_mapping"); 1506 1507 changed += live_pgcfg->ds_name_mapping_enabled != 1508 new_pgcfg.ds_name_mapping_enabled; 1509 live_pgcfg->ds_name_mapping_enabled = 1510 new_pgcfg.ds_name_mapping_enabled; 1511 1512 changed += update_string(&live_pgcfg->ad_unixuser_attr, 1513 &new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr"); 1514 1515 changed += update_string(&live_pgcfg->ad_unixgroup_attr, 1516 &new_pgcfg.ad_unixgroup_attr, "ad_unixgroup_attr"); 1517 1518 changed += update_string(&live_pgcfg->nldap_winname_attr, 1519 &new_pgcfg.nldap_winname_attr, "nldap_winname_attr"); 1520 1521 /* Props that can be discovered and set in SMF updated here */ 1522 if (!live_pgcfg->dflt_dom_set_in_smf) 1523 changed += update_string(&live_pgcfg->default_domain, 1524 &new_pgcfg.default_domain, "default_domain"); 1525 1526 changed += update_string(&live_pgcfg->domain_name, 1527 &new_pgcfg.domain_name, "domain_name"); 1528 live_pgcfg->domain_name_auto_disc = new_pgcfg.domain_name_auto_disc; 1529 1530 changed += update_dirs(&live_pgcfg->domain_controller, 1531 &new_pgcfg.domain_controller, "domain_controller"); 1532 live_pgcfg->domain_controller_auto_disc = 1533 new_pgcfg.domain_controller_auto_disc; 1534 1535 changed += update_string(&live_pgcfg->forest_name, 1536 &new_pgcfg.forest_name, "forest_name"); 1537 live_pgcfg->forest_name_auto_disc = new_pgcfg.forest_name_auto_disc; 1538 1539 changed += update_string(&live_pgcfg->site_name, 1540 &new_pgcfg.site_name, "site_name"); 1541 live_pgcfg->site_name_auto_disc = new_pgcfg.site_name_auto_disc; 1542 1543 if (update_dirs(&live_pgcfg->global_catalog, 1544 &new_pgcfg.global_catalog, "global_catalog")) { 1545 changed++; 1546 if (live_pgcfg->global_catalog != NULL && 1547 live_pgcfg->global_catalog[0].host[0] != '\0') 1548 ad_reload_required = TRUE; 1549 } 1550 live_pgcfg->global_catalog_auto_disc = 1551 new_pgcfg.global_catalog_auto_disc; 1552 1553 if (update_domains_in_forest(&live_pgcfg->domains_in_forest, 1554 &new_pgcfg.domains_in_forest, "domains_in_forest")) { 1555 changed++; 1556 ad_reload_required = TRUE; 1557 } 1558 1559 if (update_trusted_domains(&live_pgcfg->trusted_domains, 1560 &new_pgcfg.trusted_domains, "trusted_domains")) { 1561 changed++; 1562 if (live_pgcfg->trusted_domains != NULL && 1563 live_pgcfg->trusted_domains[0].domain[0] != '\0') 1564 ad_reload_required = TRUE; 1565 } 1566 1567 if (update_trusted_forest(&live_pgcfg->trusted_forests, 1568 &live_pgcfg->num_trusted_forests, &new_pgcfg.trusted_forests, 1569 &new_pgcfg.num_trusted_forests, "trusted_forest")) { 1570 changed++; 1571 if (live_pgcfg->trusted_forests != NULL) 1572 ad_reload_required = TRUE; 1573 } 1574 1575 if (ad_reload_required) 1576 reload_ad(); 1577 1578 idmap_cfg_unload(&new_pgcfg); 1579 1580 if (flags & CFG_LOG) { 1581 /* 1582 * If the config changes as a result of a refresh of the 1583 * service, then logging about it can provide useful 1584 * feedback to the sysadmin. 1585 */ 1586 idmapdlog(LOG_NOTICE, "Configuration %schanged", 1587 changed ? "" : "un"); 1588 } 1589 1590 UNLOCK_CONFIG(); 1591 1592 err: 1593 pthread_mutex_unlock(&cfg->handles.mutex); 1594 1595 if (rc < -1) 1596 return (rc); 1597 1598 return ((errors == 0) ? 0 : -1); 1599 } 1600 1601 /* 1602 * Initialize 'cfg'. 1603 */ 1604 idmap_cfg_t * 1605 idmap_cfg_init() 1606 { 1607 idmap_cfg_handles_t *handles; 1608 1609 /* First the smf repository handles: */ 1610 idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t)); 1611 if (!cfg) { 1612 idmapdlog(LOG_ERR, "Out of memory"); 1613 return (NULL); 1614 } 1615 handles = &cfg->handles; 1616 1617 (void) pthread_mutex_init(&handles->mutex, NULL); 1618 1619 if (!(handles->main = scf_handle_create(SCF_VERSION))) { 1620 idmapdlog(LOG_ERR, "scf_handle_create() failed: %s", 1621 scf_strerror(scf_error())); 1622 goto error; 1623 } 1624 1625 if (scf_handle_bind(handles->main) < 0) { 1626 idmapdlog(LOG_ERR, "scf_handle_bind() failed: %s", 1627 scf_strerror(scf_error())); 1628 goto error; 1629 } 1630 1631 if (!(handles->service = scf_service_create(handles->main)) || 1632 !(handles->instance = scf_instance_create(handles->main)) || 1633 !(handles->config_pg = scf_pg_create(handles->main)) || 1634 !(handles->general_pg = scf_pg_create(handles->main))) { 1635 idmapdlog(LOG_ERR, "scf handle creation failed: %s", 1636 scf_strerror(scf_error())); 1637 goto error; 1638 } 1639 1640 if (scf_handle_decode_fmri(handles->main, 1641 FMRI_BASE "/:properties/" CONFIG_PG, 1642 NULL, /* scope */ 1643 handles->service, /* service */ 1644 handles->instance, /* instance */ 1645 handles->config_pg, /* pg */ 1646 NULL, /* prop */ 1647 SCF_DECODE_FMRI_EXACT) < 0) { 1648 idmapdlog(LOG_ERR, "scf_handle_decode_fmri() failed: %s", 1649 scf_strerror(scf_error())); 1650 goto error; 1651 } 1652 1653 if (scf_service_get_pg(handles->service, 1654 GENERAL_PG, handles->general_pg) < 0) { 1655 idmapdlog(LOG_ERR, "scf_service_get_pg() failed: %s", 1656 scf_strerror(scf_error())); 1657 goto error; 1658 } 1659 1660 /* Initialize AD Auto Discovery context */ 1661 handles->ad_ctx = ad_disc_init(); 1662 if (handles->ad_ctx == NULL) 1663 goto error; 1664 1665 return (cfg); 1666 1667 error: 1668 (void) idmap_cfg_fini(cfg); 1669 return (NULL); 1670 } 1671 1672 void 1673 idmap_cfg_unload(idmap_pg_config_t *pgcfg) 1674 { 1675 1676 if (pgcfg->default_domain) { 1677 free(pgcfg->default_domain); 1678 pgcfg->default_domain = NULL; 1679 } 1680 if (pgcfg->domain_name) { 1681 free(pgcfg->domain_name); 1682 pgcfg->domain_name = NULL; 1683 } 1684 if (pgcfg->machine_sid) { 1685 free(pgcfg->machine_sid); 1686 pgcfg->machine_sid = NULL; 1687 } 1688 if (pgcfg->domain_controller) { 1689 free(pgcfg->domain_controller); 1690 pgcfg->domain_controller = NULL; 1691 } 1692 if (pgcfg->forest_name) { 1693 free(pgcfg->forest_name); 1694 pgcfg->forest_name = NULL; 1695 } 1696 if (pgcfg->site_name) { 1697 free(pgcfg->site_name); 1698 pgcfg->site_name = NULL; 1699 } 1700 if (pgcfg->global_catalog) { 1701 free(pgcfg->global_catalog); 1702 pgcfg->global_catalog = NULL; 1703 } 1704 if (pgcfg->trusted_domains) { 1705 free(pgcfg->trusted_domains); 1706 pgcfg->trusted_domains = NULL; 1707 } 1708 if (pgcfg->trusted_forests) 1709 free_trusted_forests(&pgcfg->trusted_forests, 1710 &pgcfg->num_trusted_forests); 1711 1712 if (pgcfg->ad_unixuser_attr) { 1713 free(pgcfg->ad_unixuser_attr); 1714 pgcfg->ad_unixuser_attr = NULL; 1715 } 1716 if (pgcfg->ad_unixgroup_attr) { 1717 free(pgcfg->ad_unixgroup_attr); 1718 pgcfg->ad_unixgroup_attr = NULL; 1719 } 1720 if (pgcfg->nldap_winname_attr) { 1721 free(pgcfg->nldap_winname_attr); 1722 pgcfg->nldap_winname_attr = NULL; 1723 } 1724 } 1725 1726 int 1727 idmap_cfg_fini(idmap_cfg_t *cfg) 1728 { 1729 idmap_cfg_handles_t *handles = &cfg->handles; 1730 idmap_cfg_unload(&cfg->pgcfg); 1731 1732 (void) pthread_mutex_destroy(&handles->mutex); 1733 scf_pg_destroy(handles->config_pg); 1734 scf_pg_destroy(handles->general_pg); 1735 scf_instance_destroy(handles->instance); 1736 scf_service_destroy(handles->service); 1737 scf_handle_destroy(handles->main); 1738 if (handles->ad_ctx != NULL) 1739 ad_disc_fini(handles->ad_ctx); 1740 free(cfg); 1741 1742 return (0); 1743 } 1744 1745 void 1746 idmap_cfg_poke_updates(void) 1747 { 1748 if (idmapd_ev_port != -1) 1749 (void) port_send(idmapd_ev_port, POKE_AUTO_DISCOVERY, NULL); 1750 } 1751 1752 /*ARGSUSED*/ 1753 void 1754 idmap_cfg_hup_handler(int sig) 1755 { 1756 if (idmapd_ev_port >= 0) 1757 (void) port_send(idmapd_ev_port, RECONFIGURE, NULL); 1758 } 1759