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