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