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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Config routines common to idmap(1M) and idmapd(1M) 30 */ 31 32 #include <stdlib.h> 33 #include <strings.h> 34 #include <libintl.h> 35 #include <ctype.h> 36 #include <errno.h> 37 #include "idmapd.h" 38 #include <stdio.h> 39 #include <stdarg.h> 40 #include <uuid/uuid.h> 41 #include <pthread.h> 42 #include <port.h> 43 #include "addisc.h" 44 45 #define MACHINE_SID_LEN (9 + UUID_LEN/4 * 11) 46 #define FMRI_BASE "svc:/system/idmap" 47 #define CONFIG_PG "config" 48 #define GENERAL_PG "general" 49 /* initial length of the array for policy options/attributes: */ 50 #define DEF_ARRAY_LENGTH 16 51 52 /*LINTLIBRARY*/ 53 54 55 static const char *me = "idmapd"; 56 57 58 static pthread_t update_thread_handle = 0; 59 60 int hup_ev_port = -1; 61 extern int hupped; 62 63 static int 64 generate_machine_sid(char **machine_sid) { 65 char *p; 66 uuid_t uu; 67 int i, j, len, rlen; 68 uint32_t rid; 69 70 /* 71 * Generate and split 128-bit UUID into four 32-bit RIDs 72 * The machine_sid will be of the form S-1-5-N1-N2-N3-N4 73 * We depart from Windows here, which instead of 128 74 * bits worth of random numbers uses 96 bits. 75 */ 76 77 *machine_sid = calloc(1, MACHINE_SID_LEN); 78 if (*machine_sid == NULL) { 79 idmapdlog(LOG_ERR, "%s: Out of memory", me); 80 return (-1); 81 } 82 (void) strcpy(*machine_sid, "S-1-5-21"); 83 p = *machine_sid + strlen("S-1-5-21"); 84 len = MACHINE_SID_LEN - strlen("S-1-5-21"); 85 86 uuid_clear(uu); 87 uuid_generate_random(uu); 88 89 for (i = 0; i < UUID_LEN/4; i++) { 90 j = i * 4; 91 rid = (uu[j] << 24) | (uu[j + 1] << 16) | 92 (uu[j + 2] << 8) | (uu[j + 3]); 93 rlen = snprintf(p, len, "-%u", rid); 94 p += rlen; 95 len -= rlen; 96 } 97 98 return (0); 99 } 100 101 /* Check if in the case of failure the original value of *val is preserved */ 102 static int 103 get_val_int(idmap_cfg_handles_t *handles, char *name, 104 void *val, scf_type_t type) 105 { 106 int rc = 0; 107 108 scf_property_t *scf_prop = scf_property_create(handles->main); 109 scf_value_t *value = scf_value_create(handles->main); 110 111 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) 112 /* this is OK: the property is just undefined */ 113 goto destruction; 114 115 116 if (scf_property_get_value(scf_prop, value) < 0) 117 /* It is still OK when a property doesn't have any value */ 118 goto destruction; 119 120 switch (type) { 121 case SCF_TYPE_BOOLEAN: 122 rc = scf_value_get_boolean(value, val); 123 break; 124 case SCF_TYPE_COUNT: 125 rc = scf_value_get_count(value, val); 126 break; 127 case SCF_TYPE_INTEGER: 128 rc = scf_value_get_integer(value, val); 129 break; 130 default: 131 idmapdlog(LOG_ERR, "%s: Invalid scf integer type (%d)", 132 me, type); 133 rc = -1; 134 break; 135 } 136 137 138 destruction: 139 scf_value_destroy(value); 140 scf_property_destroy(scf_prop); 141 142 return (rc); 143 } 144 145 static char * 146 scf_value2string(scf_value_t *value) { 147 int rc = -1; 148 char buf_size = 127; 149 int length; 150 char *buf = NULL; 151 buf = (char *) malloc(sizeof (char) * buf_size); 152 153 for (;;) { 154 length = scf_value_get_astring(value, buf, buf_size); 155 if (length < 0) { 156 rc = -1; 157 goto destruction; 158 } 159 160 if (length == buf_size - 1) { 161 buf_size *= 2; 162 buf = (char *)realloc(buf, buf_size * sizeof (char)); 163 if (!buf) { 164 idmapdlog(LOG_ERR, "%s: Out of memory", me); 165 rc = -1; 166 goto destruction; 167 } 168 } else { 169 rc = 0; 170 break; 171 } 172 } 173 174 destruction: 175 if (rc < 0) { 176 if (buf) 177 free(buf); 178 buf = NULL; 179 } 180 181 return (buf); 182 } 183 184 static int 185 get_val_ds(idmap_cfg_handles_t *handles, const char *name, int defport, 186 ad_disc_ds_t **val) 187 { 188 ad_disc_ds_t *servers = NULL; 189 scf_property_t *scf_prop; 190 scf_value_t *value; 191 scf_iter_t *iter; 192 char *host, *portstr; 193 int len, i; 194 int count = 0; 195 int rc = -1; 196 197 *val = NULL; 198 199 restart: 200 scf_prop = scf_property_create(handles->main); 201 value = scf_value_create(handles->main); 202 iter = scf_iter_create(handles->main); 203 204 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) { 205 /* this is OK: the property is just undefined */ 206 rc = 0; 207 goto destruction; 208 } 209 210 if (scf_iter_property_values(iter, scf_prop) < 0) { 211 idmapdlog(LOG_ERR, 212 "%s: scf_iter_property_values(%s) failed: %s", 213 me, name, scf_strerror(scf_error())); 214 goto destruction; 215 } 216 217 /* Workaround scf bugs -- can't reset an iteration */ 218 if (count == 0) { 219 while (scf_iter_next_value(iter, value) > 0) 220 count++; 221 222 if (count == 0) { 223 /* no values */ 224 rc = 0; 225 goto destruction; 226 } 227 228 scf_value_destroy(value); 229 scf_iter_destroy(iter); 230 scf_property_destroy(scf_prop); 231 goto restart; 232 } 233 234 if ((servers = calloc(count + 1, sizeof (*servers))) == NULL) { 235 idmapdlog(LOG_ERR, "%s: Out of memory", me); 236 goto destruction; 237 } 238 239 i = 0; 240 while (i < count && scf_iter_next_value(iter, value) > 0) { 241 servers[i].priority = 0; 242 servers[i].weight = 100; 243 servers[i].port = defport; 244 if ((host = scf_value2string(value)) == NULL) { 245 goto destruction; 246 } 247 if ((portstr = strchr(host, ':')) != NULL) { 248 *portstr++ = '\0'; 249 servers[i].port = strtol(portstr, 250 (char **)NULL, 10); 251 if (servers[i].port == 0) 252 servers[i].port = defport; 253 } 254 len = strlcpy(servers[i].host, host, 255 sizeof (servers->host)); 256 257 free(host); 258 259 /* Ignore this server if the hostname is too long */ 260 if (len < sizeof (servers->host)) 261 i++; 262 } 263 264 *val = servers; 265 266 rc = 0; 267 268 destruction: 269 scf_value_destroy(value); 270 scf_iter_destroy(iter); 271 scf_property_destroy(scf_prop); 272 273 if (rc < 0) { 274 if (servers) 275 free(servers); 276 *val = NULL; 277 } 278 279 return (rc); 280 } 281 282 283 static int 284 get_val_astring(idmap_cfg_handles_t *handles, char *name, char **val) 285 { 286 int rc = 0; 287 288 scf_property_t *scf_prop = scf_property_create(handles->main); 289 scf_value_t *value = scf_value_create(handles->main); 290 291 *val = NULL; 292 293 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) 294 /* this is OK: the property is just undefined */ 295 goto destruction; 296 297 if (scf_property_get_value(scf_prop, value) < 0) { 298 idmapdlog(LOG_ERR, 299 "%s: scf_property_get_value(%s) failed: %s", 300 me, name, scf_strerror(scf_error())); 301 rc = -1; 302 goto destruction; 303 } 304 305 if (!(*val = scf_value2string(value))) 306 rc = -1; 307 308 destruction: 309 scf_value_destroy(value); 310 scf_property_destroy(scf_prop); 311 312 if (rc < 0) { 313 if (*val) 314 free(*val); 315 *val = NULL; 316 } 317 318 return (rc); 319 } 320 321 322 static int 323 set_val_astring(idmap_cfg_handles_t *handles, char *name, const char *val) 324 { 325 int rc = -1; 326 int ret = -2; 327 int i; 328 scf_property_t *scf_prop = NULL; 329 scf_value_t *value = NULL; 330 scf_transaction_t *tx = NULL; 331 scf_transaction_entry_t *ent = NULL; 332 333 if ((scf_prop = scf_property_create(handles->main)) == NULL || 334 (value = scf_value_create(handles->main)) == NULL || 335 (tx = scf_transaction_create(handles->main)) == NULL || 336 (ent = scf_entry_create(handles->main)) == NULL) { 337 idmapdlog(LOG_ERR, "%s: Unable to set property %s: %s", 338 me, name, scf_strerror(scf_error())); 339 goto destruction; 340 } 341 342 for (i = 0; i < MAX_TRIES && (ret == -2 || ret == 0); i++) { 343 if (scf_transaction_start(tx, handles->config_pg) == -1) { 344 idmapdlog(LOG_ERR, 345 "%s: scf_transaction_start(%s) failed: %s", 346 me, name, scf_strerror(scf_error())); 347 goto destruction; 348 } 349 350 if (scf_transaction_property_new(tx, ent, name, 351 SCF_TYPE_ASTRING) < 0) { 352 idmapdlog(LOG_ERR, 353 "%s: scf_transaction_property_new() failed: %s", 354 me, scf_strerror(scf_error())); 355 goto destruction; 356 } 357 358 if (scf_value_set_astring(value, val) == -1) { 359 idmapdlog(LOG_ERR, 360 "%s: scf_value_set_astring() failed: %s", 361 me, scf_strerror(scf_error())); 362 goto destruction; 363 } 364 365 if (scf_entry_add_value(ent, value) == -1) { 366 idmapdlog(LOG_ERR, 367 "%s: scf_entry_add_value() failed: %s", 368 me, scf_strerror(scf_error())); 369 goto destruction; 370 } 371 372 if ((ret = scf_transaction_commit(tx)) == 1) 373 break; 374 375 if (ret == 0 && i < MAX_TRIES - 1) { 376 /* 377 * Property group set in scf_transaction_start() 378 * is not the most recent. Update pg, reset tx and 379 * retry tx. 380 */ 381 idmapdlog(LOG_WARNING, 382 "%s: scf_transaction_commit(%s) failed - Retry: %s", 383 me, name, scf_strerror(scf_error())); 384 if (scf_pg_update(handles->config_pg) == -1) { 385 idmapdlog(LOG_ERR, 386 "%s: scf_pg_update() failed: %s", 387 me, scf_strerror(scf_error())); 388 goto destruction; 389 } 390 scf_transaction_reset(tx); 391 } 392 } 393 394 395 if (ret == 1) 396 rc = 0; 397 else if (ret != -2) 398 idmapdlog(LOG_ERR, 399 "%s: scf_transaction_commit(%s) failed: %s", 400 me, name, scf_strerror(scf_error())); 401 402 destruction: 403 scf_value_destroy(value); 404 scf_entry_destroy(ent); 405 scf_transaction_destroy(tx); 406 scf_property_destroy(scf_prop); 407 return (rc); 408 } 409 410 static int 411 update_value(char **value, char **new, char *name) 412 { 413 if (*new == NULL) 414 return (FALSE); 415 416 if (*value != NULL && strcmp(*new, *value) == 0) { 417 free(*new); 418 *new = NULL; 419 return (FALSE); 420 } 421 422 idmapdlog(LOG_INFO, "%s: change %s=%s", me, name, CHECK_NULL(*new)); 423 if (*value != NULL) 424 free(*value); 425 *value = *new; 426 *new = NULL; 427 return (TRUE); 428 } 429 430 static int 431 update_dirs(ad_disc_ds_t **value, ad_disc_ds_t **new, char *name) 432 { 433 int i; 434 435 if (*new == NULL) 436 return (FALSE); 437 438 if (*value != NULL && ad_disc_compare_ds(*value, *new) == 0) { 439 free(*new); 440 *new = NULL; 441 return (FALSE); 442 } 443 444 if (*value) 445 free(*value); 446 447 for (i = 0; (*new)[i].host[0] != '\0'; i++) 448 idmapdlog(LOG_INFO, "%s: change %s=%s port=%d", me, name, 449 (*new)[i].host, (*new)[i].port); 450 *value = *new; 451 *new = NULL; 452 return (TRUE); 453 } 454 455 456 #define SUBNET_CHECK_TIME (2 * 60) 457 #define MAX_CHECK_TIME (10 * 60) 458 459 /* 460 * Returns 1 if SIGHUP has been received (see hup_handler elsewhere), 0 461 * otherwise. Uses an event port and a user-defined event. 462 * 463 * Note that port_get() does not update its timeout argument when EINTR, 464 * unlike nanosleep(). We probably don't care very much here because 465 * the only signals we expect are ones that will lead to idmapd dying or 466 * SIGHUP, and we intend for the latter to cause this function to 467 * return. But if we did care then we could always use a timer event 468 * (see timer_create(3RT)) and associate it with the same event port, 469 * then we could get accurate waiting regardless of EINTRs. 470 */ 471 static 472 int 473 wait_for_ttl(struct timespec *timeout) 474 { 475 port_event_t pe; 476 int retries = 1; 477 478 /* 479 * If event port creation failed earlier and fails now then we 480 * simply don't learn about SIGHUPs in a timely fashion. No big 481 * deal 482 */ 483 if (hup_ev_port == -1 && (hup_ev_port = port_create()) < 0) { 484 (void) nanosleep(timeout, NULL); 485 return (0); 486 } 487 488 retry: 489 if (port_get(hup_ev_port, &pe, timeout) != 0) { 490 switch (errno) { 491 case EBADF: 492 case EBADFD: 493 hup_ev_port = -1; 494 (void) nanosleep(timeout, NULL); 495 break; 496 case EINVAL: 497 /* 498 * Shouldn't happen, except, perhaps, near the 499 * end of time 500 */ 501 timeout->tv_nsec = 0; 502 timeout->tv_sec = MAX_CHECK_TIME; 503 if (retries-- > 0) 504 goto retry; 505 /* NOTREACHED */ 506 break; 507 case EINTR: 508 if (!hupped) 509 goto retry; 510 break; 511 case ETIME: 512 /* Timeout */ 513 break; 514 default: 515 /* EFAULT */ 516 (void) nanosleep(timeout, NULL); 517 break; 518 } 519 } 520 521 /* 522 * We only have one event that we care about, a user event, so 523 * there's nothing to check or clean up about pe. 524 * 525 * If we get here it's either because we had a SIGHUP and a user 526 * event was sent to our port, or because the port_get() timed 527 * out (or even both!). 528 */ 529 530 if (hupped) { 531 int rc; 532 533 hupped = 0; 534 /* 535 * Blow away the ccache, we might have re-joined the 536 * domain or joined a new one 537 */ 538 (void) unlink(IDMAP_CACHEDIR "/ccache"); 539 /* HUP is the refresh method, so re-read SMF config */ 540 (void) idmapdlog(LOG_INFO, "idmapd: SMF refresh"); 541 WRLOCK_CONFIG(); 542 (void) idmap_cfg_unload(&_idmapdstate.cfg->pgcfg); 543 rc = idmap_cfg_load(&_idmapdstate.cfg->handles, 544 &_idmapdstate.cfg->pgcfg, 1); 545 if (rc == -2) 546 (void) idmapdlog(LOG_ERR, 547 "idmapd: Various errors re-loading configuration " 548 "will cause AD lookups to fail"); 549 if (rc == -1) 550 (void) idmapdlog(LOG_WARNING, 551 "idmapd: Various errors re-loading configuration " 552 "may cause AD lookups to fail"); 553 UNLOCK_CONFIG(); 554 return (1); 555 } 556 557 return (0); 558 } 559 560 void * 561 idmap_cfg_update_thread(void *arg) 562 { 563 564 idmap_pg_config_t new_cfg; 565 int ttl, changed; 566 idmap_cfg_handles_t *handles = &_idmapdstate.cfg->handles; 567 idmap_pg_config_t *live_cfg = &_idmapdstate.cfg->pgcfg; 568 ad_disc_t ad_ctx = handles->ad_ctx; 569 struct timespec delay; 570 int first = 1; 571 572 (void) memset(&new_cfg, 0, sizeof (new_cfg)); 573 574 for (;;) { 575 changed = FALSE; 576 577 if (first) { 578 ttl = 1; 579 first = 0; 580 } else { 581 ttl = ad_disc_get_TTL(ad_ctx); 582 } 583 584 if (ttl > MAX_CHECK_TIME) 585 ttl = MAX_CHECK_TIME; 586 while (ttl > 0 || ttl == -1) { 587 if (ttl == -1) { 588 wait_for_ttl(NULL); 589 } else if (ttl > SUBNET_CHECK_TIME) { 590 /* 591 * We really ought to just monitor 592 * network interfaces with a PF_ROUTE 593 * socket... This crude method of 594 * discovering subnet changes will do 595 * for now. Though might even not want 596 * to bother: subnet changes leading to 597 * sitename changes ought never happen, 598 * and requiring a refresh when they do 599 * should be no problem (SMF/NWAM ought 600 * to be able to refresh us). 601 */ 602 delay.tv_sec = SUBNET_CHECK_TIME; 603 delay.tv_nsec = 0; 604 if (wait_for_ttl(&delay)) { 605 /* Got SIGHUP, re-discover */ 606 ttl = 0; 607 changed = TRUE; 608 break; 609 } 610 ttl -= SUBNET_CHECK_TIME; 611 if (ad_disc_SubnetChanged(ad_ctx)) 612 break; 613 } else { 614 delay.tv_sec = ttl; 615 delay.tv_nsec = 0; 616 if (wait_for_ttl(&delay)) 617 changed = TRUE; 618 ttl = 0; 619 } 620 } 621 622 /* 623 * Load configuration data into a private copy. 624 * 625 * The fixed values (i.e., from SMF) have already been 626 * set in AD auto discovery, so if all values have been 627 * set in SMF and they haven't been changed or the 628 * service been refreshed then the rest of this loop's 629 * body is one big no-op. 630 */ 631 pthread_mutex_lock(&handles->mutex); 632 633 new_cfg.default_domain = ad_disc_get_DomainName(ad_ctx); 634 if (new_cfg.default_domain == NULL) { 635 idmapdlog(LOG_INFO, 636 "%s: unable to discover Default Domain", me); 637 } 638 639 new_cfg.domain_name = ad_disc_get_DomainName(ad_ctx); 640 if (new_cfg.domain_name == NULL) { 641 idmapdlog(LOG_INFO, 642 "%s: unable to discover Domain Name", me); 643 } 644 645 new_cfg.domain_controller = 646 ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE); 647 if (new_cfg.domain_controller == NULL) { 648 idmapdlog(LOG_INFO, 649 "%s: unable to discover Domain Controller", me); 650 } 651 652 new_cfg.forest_name = ad_disc_get_ForestName(ad_ctx); 653 if (new_cfg.forest_name == NULL) { 654 idmapdlog(LOG_INFO, 655 "%s: unable to discover Forest Name", me); 656 } 657 658 new_cfg.site_name = ad_disc_get_SiteName(ad_ctx); 659 if (new_cfg.site_name == NULL) { 660 idmapdlog(LOG_INFO, 661 "%s: unable to discover Site Name", me); 662 } 663 664 new_cfg.global_catalog = 665 ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE); 666 if (new_cfg.global_catalog == NULL) { 667 idmapdlog(LOG_INFO, 668 "%s: unable to discover Global Catalog", me); 669 } 670 671 pthread_mutex_unlock(&handles->mutex); 672 673 if (new_cfg.default_domain == NULL && 674 new_cfg.domain_name == NULL && 675 new_cfg.domain_controller == NULL && 676 new_cfg.forest_name == NULL && 677 new_cfg.global_catalog == NULL) { 678 idmapdlog(LOG_NOTICE, "%s: Could not auto-discover AD " 679 "domain and forest names nor domain controllers " 680 "and global catalog servers", me); 681 idmap_cfg_unload(&new_cfg); 682 continue; 683 } 684 685 /* 686 * Update the live configuration 687 */ 688 WRLOCK_CONFIG(); 689 690 if (live_cfg->list_size_limit != new_cfg.list_size_limit) { 691 idmapdlog(LOG_INFO, "%s: change list_size=%d", me, 692 new_cfg.list_size_limit); 693 live_cfg->list_size_limit = new_cfg.list_size_limit; 694 } 695 696 /* 697 * If default_domain came from SMF then we must not 698 * auto-discover it. 699 */ 700 if (live_cfg->dflt_dom_set_in_smf == FALSE && 701 update_value(&live_cfg->default_domain, 702 &new_cfg.default_domain, "default_domain") == TRUE) 703 changed = TRUE; 704 705 (void) update_value(&live_cfg->domain_name, 706 &new_cfg.domain_name, "domain_name"); 707 708 (void) update_dirs(&live_cfg->domain_controller, 709 &new_cfg.domain_controller, "domain_controller"); 710 711 (void) update_value(&live_cfg->forest_name, 712 &new_cfg.forest_name, "forest_name"); 713 714 (void) update_value(&live_cfg->site_name, 715 &new_cfg.site_name, "site_name"); 716 717 if (update_dirs(&live_cfg->global_catalog, 718 &new_cfg.global_catalog, "global_catalog") == TRUE) 719 changed = TRUE; 720 UNLOCK_CONFIG(); 721 722 idmap_cfg_unload(&new_cfg); 723 724 725 /* 726 * Re-create the ad_t/ad_host_t objects if 727 * either the default domain or the global 728 * catalog server list changed. 729 */ 730 731 if (changed) { 732 RDLOCK_CONFIG(); 733 (void) reload_ad(); 734 UNLOCK_CONFIG(); 735 print_idmapdstate(); 736 } 737 } 738 /*NOTREACHED*/ 739 return (NULL); 740 } 741 742 743 int 744 idmap_cfg_start_updates(idmap_cfg_t *cfg) 745 { 746 /* Don't check for failure -- see wait_for_ttl() */ 747 hup_ev_port = port_create(); 748 749 errno = pthread_create(&update_thread_handle, NULL, 750 idmap_cfg_update_thread, NULL); 751 if (errno == 0) 752 return (0); 753 else 754 return (-1); 755 } 756 757 758 int 759 idmap_cfg_load(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg, 760 int discover) 761 { 762 int rc; 763 int errors = 0; 764 char *str = NULL; 765 ad_disc_t ad_ctx = handles->ad_ctx; 766 767 pgcfg->list_size_limit = 0; 768 pgcfg->default_domain = NULL; 769 pgcfg->domain_name = NULL; 770 pgcfg->machine_sid = NULL; 771 pgcfg->domain_controller = NULL; 772 pgcfg->forest_name = NULL; 773 pgcfg->site_name = NULL; 774 pgcfg->global_catalog = NULL; 775 776 pthread_mutex_lock(&handles->mutex); 777 778 ad_disc_refresh(handles->ad_ctx); 779 780 if (scf_pg_update(handles->config_pg) < 0) { 781 idmapdlog(LOG_ERR, "%s: scf_pg_update() failed: %s", 782 me, scf_strerror(scf_error())); 783 rc = -2; 784 goto exit; 785 } 786 787 if (scf_pg_update(handles->general_pg) < 0) { 788 idmapdlog(LOG_ERR, "%s: scf_pg_update() failed: %s", 789 me, scf_strerror(scf_error())); 790 rc = -2; 791 goto exit; 792 } 793 794 rc = get_val_int(handles, "list_size_limit", 795 &pgcfg->list_size_limit, SCF_TYPE_COUNT); 796 if (rc != 0) { 797 pgcfg->list_size_limit = 0; 798 errors++; 799 } 800 801 rc = get_val_astring(handles, "domain_name", 802 &pgcfg->domain_name); 803 if (rc != 0) 804 errors++; 805 else 806 (void) ad_disc_set_DomainName(ad_ctx, pgcfg->domain_name); 807 808 rc = get_val_astring(handles, "default_domain", 809 &pgcfg->default_domain); 810 if (rc != 0) { 811 /* 812 * SCF failures fetching config/default_domain we treat 813 * as fatal as they may leave ID mapping rules that 814 * match unqualified winnames flapping in the wind. 815 */ 816 rc = -2; 817 goto exit; 818 } 819 820 rc = get_val_astring(handles, "mapping_domain", &str); 821 if (rc != 0) 822 errors++; 823 824 /* 825 * We treat default_domain as having been specified in SMF IFF 826 * either (the config/default_domain property was set) or (the 827 * old, obsolete, never documented config/mapping_domain 828 * property was set and the new config/domain_name property was 829 * not set). 830 */ 831 pgcfg->dflt_dom_set_in_smf = TRUE; 832 if (pgcfg->default_domain == NULL) { 833 834 pgcfg->dflt_dom_set_in_smf = FALSE; 835 836 if (pgcfg->domain_name != NULL) { 837 pgcfg->default_domain = strdup(pgcfg->domain_name); 838 if (str != NULL) { 839 idmapdlog(LOG_WARNING, 840 "%s: Ignoring obsolete, undocumented " 841 "config/mapping_domain property", me); 842 } 843 } else if (str != NULL) { 844 pgcfg->default_domain = strdup(str); 845 pgcfg->dflt_dom_set_in_smf = TRUE; 846 idmapdlog(LOG_WARNING, 847 "%s: The config/mapping_domain property is " 848 "obsolete; support for it will be removed, " 849 "please use config/default_domain instead", 850 me); 851 } 852 } 853 854 if (str != NULL) 855 free(str); 856 857 rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid); 858 if (rc != 0) 859 errors++; 860 if (pgcfg->machine_sid == NULL) { 861 /* If machine_sid not configured, generate one */ 862 if (generate_machine_sid(&pgcfg->machine_sid) < 0) { 863 rc = -2; 864 goto exit; 865 } 866 rc = set_val_astring(handles, "machine_sid", 867 pgcfg->machine_sid); 868 if (rc != 0) 869 errors++; 870 } 871 872 str = NULL; 873 rc = get_val_ds(handles, "domain_controller", 389, 874 &pgcfg->domain_controller); 875 if (rc != 0) 876 errors++; 877 else 878 (void) ad_disc_set_DomainController(ad_ctx, 879 pgcfg->domain_controller); 880 881 rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name); 882 if (rc != 0) 883 errors++; 884 else 885 (void) ad_disc_set_ForestName(ad_ctx, pgcfg->forest_name); 886 887 rc = get_val_astring(handles, "site_name", &pgcfg->site_name); 888 if (rc != 0) 889 errors++; 890 else 891 (void) ad_disc_set_SiteName(ad_ctx, pgcfg->site_name); 892 893 str = NULL; 894 rc = get_val_ds(handles, "global_catalog", 3268, 895 &pgcfg->global_catalog); 896 if (rc != 0) 897 errors++; 898 else 899 (void) ad_disc_set_GlobalCatalog(ad_ctx, pgcfg->global_catalog); 900 901 902 if (!discover) 903 goto exit; 904 905 /* 906 * Auto Discover the rest 907 */ 908 if (pgcfg->default_domain == NULL) { 909 pgcfg->default_domain = ad_disc_get_DomainName(ad_ctx); 910 if (pgcfg->default_domain == NULL) { 911 idmapdlog(LOG_INFO, 912 "%s: unable to discover Default Domain", me); 913 } 914 } 915 916 if (pgcfg->domain_name == NULL) { 917 pgcfg->domain_name = ad_disc_get_DomainName(ad_ctx); 918 if (pgcfg->domain_name == NULL) { 919 idmapdlog(LOG_INFO, 920 "%s: unable to discover Domain Name", me); 921 } 922 } 923 924 if (pgcfg->domain_controller == NULL) { 925 pgcfg->domain_controller = 926 ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE); 927 if (pgcfg->domain_controller == NULL) { 928 idmapdlog(LOG_INFO, 929 "%s: unable to discover Domain Controller", me); 930 } 931 } 932 933 if (pgcfg->forest_name == NULL) { 934 pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx); 935 if (pgcfg->forest_name == NULL) { 936 idmapdlog(LOG_INFO, 937 "%s: unable to discover Forest Name", me); 938 } 939 } 940 941 if (pgcfg->site_name == NULL) { 942 pgcfg->site_name = ad_disc_get_SiteName(ad_ctx); 943 if (pgcfg->site_name == NULL) { 944 idmapdlog(LOG_INFO, 945 "%s: unable to discover Site Name", me); 946 } 947 } 948 949 if (pgcfg->global_catalog == NULL) { 950 pgcfg->global_catalog = 951 ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE); 952 if (pgcfg->global_catalog == NULL) { 953 idmapdlog(LOG_INFO, 954 "%s: unable to discover Global Catalog", me); 955 } 956 } 957 958 exit: 959 pthread_mutex_unlock(&handles->mutex); 960 961 if (rc == -2) 962 return (rc); 963 964 return ((errors == 0) ? 0 : -1); 965 } 966 967 /* 968 * Initialize 'cfg'. 969 */ 970 idmap_cfg_t * 971 idmap_cfg_init() { 972 idmap_cfg_handles_t *handles; 973 974 /* First the smf repository handles: */ 975 idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t)); 976 if (!cfg) { 977 idmapdlog(LOG_ERR, "%s: Out of memory", me); 978 return (NULL); 979 } 980 handles = &cfg->handles; 981 982 (void) pthread_mutex_init(&handles->mutex, NULL); 983 984 if (!(handles->main = scf_handle_create(SCF_VERSION))) { 985 idmapdlog(LOG_ERR, "%s: scf_handle_create() failed: %s", 986 me, scf_strerror(scf_error())); 987 goto error; 988 } 989 990 if (scf_handle_bind(handles->main) < 0) { 991 idmapdlog(LOG_ERR, "%s: scf_handle_bind() failed: %s", 992 me, scf_strerror(scf_error())); 993 goto error; 994 } 995 996 if (!(handles->service = scf_service_create(handles->main)) || 997 !(handles->instance = scf_instance_create(handles->main)) || 998 !(handles->config_pg = scf_pg_create(handles->main)) || 999 !(handles->general_pg = scf_pg_create(handles->main))) { 1000 idmapdlog(LOG_ERR, "%s: scf handle creation failed: %s", 1001 me, scf_strerror(scf_error())); 1002 goto error; 1003 } 1004 1005 if (scf_handle_decode_fmri(handles->main, 1006 FMRI_BASE "/:properties/" CONFIG_PG, 1007 NULL, /* scope */ 1008 handles->service, /* service */ 1009 handles->instance, /* instance */ 1010 handles->config_pg, /* pg */ 1011 NULL, /* prop */ 1012 SCF_DECODE_FMRI_EXACT) < 0) { 1013 idmapdlog(LOG_ERR, "%s: scf_handle_decode_fmri() failed: %s", 1014 me, scf_strerror(scf_error())); 1015 goto error; 1016 1017 } 1018 1019 if (scf_service_get_pg(handles->service, 1020 GENERAL_PG, handles->general_pg) < 0) { 1021 idmapdlog(LOG_ERR, "%s: scf_service_get_pg() failed: %s", 1022 me, scf_strerror(scf_error())); 1023 goto error; 1024 } 1025 1026 /* Initialize AD Auto Discovery context */ 1027 handles->ad_ctx = ad_disc_init(); 1028 if (handles->ad_ctx == NULL) 1029 goto error; 1030 1031 return (cfg); 1032 1033 error: 1034 (void) idmap_cfg_fini(cfg); 1035 return (NULL); 1036 } 1037 1038 void 1039 idmap_cfg_unload(idmap_pg_config_t *pgcfg) { 1040 1041 if (pgcfg->default_domain) { 1042 free(pgcfg->default_domain); 1043 pgcfg->default_domain = NULL; 1044 } 1045 if (pgcfg->domain_name) { 1046 free(pgcfg->domain_name); 1047 pgcfg->domain_name = NULL; 1048 } 1049 if (pgcfg->machine_sid) { 1050 free(pgcfg->machine_sid); 1051 pgcfg->machine_sid = NULL; 1052 } 1053 if (pgcfg->domain_controller) { 1054 free(pgcfg->domain_controller); 1055 pgcfg->domain_controller = NULL; 1056 } 1057 if (pgcfg->forest_name) { 1058 free(pgcfg->forest_name); 1059 pgcfg->forest_name = NULL; 1060 } 1061 if (pgcfg->site_name) { 1062 free(pgcfg->site_name); 1063 pgcfg->site_name = NULL; 1064 } 1065 if (pgcfg->global_catalog) { 1066 free(pgcfg->global_catalog); 1067 pgcfg->global_catalog = NULL; 1068 } 1069 } 1070 1071 int 1072 idmap_cfg_fini(idmap_cfg_t *cfg) 1073 { 1074 idmap_cfg_handles_t *handles = &cfg->handles; 1075 idmap_cfg_unload(&cfg->pgcfg); 1076 1077 (void) pthread_mutex_destroy(&handles->mutex); 1078 scf_pg_destroy(handles->config_pg); 1079 scf_pg_destroy(handles->general_pg); 1080 scf_instance_destroy(handles->instance); 1081 scf_service_destroy(handles->service); 1082 scf_handle_destroy(handles->main); 1083 ad_disc_fini(handles->ad_ctx); 1084 free(cfg); 1085 1086 return (0); 1087 } 1088