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