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; 194 int count = 0; 195 int rc = 0; 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 goto destruction; 207 208 if (scf_iter_property_values(iter, scf_prop) < 0) { 209 idmapdlog(LOG_ERR, 210 "%s: scf_iter_property_values(%s) failed: %s", 211 me, name, scf_strerror(scf_error())); 212 rc = -1; 213 goto destruction; 214 } 215 216 /* Workaround scf bugs -- can't reset an iteration */ 217 if (count == 0) { 218 while (scf_iter_next_value(iter, value) > 0) 219 count++; 220 221 if (count == 0) 222 /* no values */ 223 goto destruction; 224 225 scf_value_destroy(value); 226 scf_iter_destroy(iter); 227 scf_property_destroy(scf_prop); 228 goto restart; 229 } 230 231 if ((servers = calloc(count + 1, sizeof (*servers))) == NULL) { 232 idmapdlog(LOG_ERR, "%s: Out of memory", me); 233 goto destruction; 234 } 235 236 count = 0; 237 while (scf_iter_next_value(iter, value) > 0) { 238 servers[count].priority = 0; 239 servers[count].weight = 100; 240 servers[count].port = defport; 241 if ((host = scf_value2string(value)) == NULL) { 242 rc = -1; 243 goto destruction; 244 } 245 if ((portstr = strchr(host, ':')) != NULL) { 246 *portstr++ = '\0'; 247 servers[count].port = strtol(portstr, 248 (char **)NULL, 10); 249 if (servers[count].port == 0) 250 servers[count].port = defport; 251 } 252 len = strlcpy(servers[count].host, host, 253 sizeof (servers->host)); 254 255 free(host); 256 257 /* Ignore this server if the hostname is too long */ 258 if (len < sizeof (servers->host)) 259 count++; 260 } 261 262 *val = servers; 263 264 destruction: 265 scf_value_destroy(value); 266 scf_iter_destroy(iter); 267 scf_property_destroy(scf_prop); 268 269 if (rc < 0) { 270 if (servers) 271 free(servers); 272 *val = NULL; 273 } 274 275 return (rc); 276 } 277 278 279 static int 280 get_val_astring(idmap_cfg_handles_t *handles, char *name, char **val) 281 { 282 int rc = 0; 283 284 scf_property_t *scf_prop = scf_property_create(handles->main); 285 scf_value_t *value = scf_value_create(handles->main); 286 287 *val = NULL; 288 289 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) 290 /* this is OK: the property is just undefined */ 291 goto destruction; 292 293 if (scf_property_get_value(scf_prop, value) < 0) { 294 idmapdlog(LOG_ERR, 295 "%s: scf_property_get_value(%s) failed: %s", 296 me, name, scf_strerror(scf_error())); 297 rc = -1; 298 goto destruction; 299 } 300 301 if (!(*val = scf_value2string(value))) 302 rc = -1; 303 304 destruction: 305 scf_value_destroy(value); 306 scf_property_destroy(scf_prop); 307 308 if (rc < 0) { 309 if (*val) 310 free(*val); 311 *val = NULL; 312 } 313 314 return (rc); 315 } 316 317 318 static int 319 set_val_astring(idmap_cfg_handles_t *handles, char *name, const char *val) 320 { 321 int rc = 0, i; 322 scf_property_t *scf_prop = NULL; 323 scf_value_t *value = NULL; 324 scf_transaction_t *tx = NULL; 325 scf_transaction_entry_t *ent = NULL; 326 327 if ((scf_prop = scf_property_create(handles->main)) == NULL || 328 (value = scf_value_create(handles->main)) == NULL || 329 (tx = scf_transaction_create(handles->main)) == NULL || 330 (ent = scf_entry_create(handles->main)) == NULL) { 331 idmapdlog(LOG_ERR, "%s: Unable to set property %s: %s", 332 me, name, scf_strerror(scf_error())); 333 rc = -1; 334 goto destruction; 335 } 336 337 for (i = 0; i < MAX_TRIES && rc == 0; i++) { 338 if (scf_transaction_start(tx, handles->config_pg) == -1) { 339 idmapdlog(LOG_ERR, 340 "%s: scf_transaction_start(%s) failed: %s", 341 me, name, scf_strerror(scf_error())); 342 rc = -1; 343 goto destruction; 344 } 345 346 rc = scf_transaction_property_new(tx, ent, name, 347 SCF_TYPE_ASTRING); 348 if (rc == -1) { 349 idmapdlog(LOG_ERR, 350 "%s: scf_transaction_property_new() failed: %s", 351 me, scf_strerror(scf_error())); 352 goto destruction; 353 } 354 355 if (scf_value_set_astring(value, val) == -1) { 356 idmapdlog(LOG_ERR, 357 "%s: scf_value_set_astring() failed: %s", 358 me, scf_strerror(scf_error())); 359 rc = -1; 360 goto destruction; 361 } 362 363 if (scf_entry_add_value(ent, value) == -1) { 364 idmapdlog(LOG_ERR, 365 "%s: scf_entry_add_value() failed: %s", 366 me, scf_strerror(scf_error())); 367 rc = -1; 368 goto destruction; 369 } 370 371 rc = scf_transaction_commit(tx); 372 if (rc == 0 && i < MAX_TRIES - 1) { 373 /* 374 * Property group set in scf_transaction_start() 375 * is not the most recent. Update pg, reset tx and 376 * retry tx. 377 */ 378 idmapdlog(LOG_WARNING, 379 "%s: scf_transaction_commit(%s) failed - Retry: %s", 380 me, name, scf_strerror(scf_error())); 381 if (scf_pg_update(handles->config_pg) == -1) { 382 idmapdlog(LOG_ERR, 383 "%s: scf_pg_update() failed: %s", 384 me, scf_strerror(scf_error())); 385 rc = -1; 386 goto destruction; 387 } 388 scf_transaction_reset(tx); 389 } 390 } 391 392 /* Log failure message if all retries failed */ 393 if (rc == 0) { 394 idmapdlog(LOG_ERR, 395 "%s: scf_transaction_commit(%s) failed: %s", 396 me, name, scf_strerror(scf_error())); 397 rc = -1; 398 } 399 400 destruction: 401 scf_value_destroy(value); 402 scf_entry_destroy(ent); 403 scf_transaction_destroy(tx); 404 scf_property_destroy(scf_prop); 405 return (rc); 406 } 407 408 static int 409 update_value(char **value, char **new, char *name) 410 { 411 if (*new == NULL) 412 return (FALSE); 413 414 if (*value != NULL && strcmp(*new, *value) == 0) { 415 free(*new); 416 *new = NULL; 417 return (FALSE); 418 } 419 420 idmapdlog(LOG_INFO, "%s: change %s=%s", me, name, CHECK_NULL(*new)); 421 if (*value != NULL) 422 free(*value); 423 *value = *new; 424 *new = NULL; 425 return (TRUE); 426 } 427 428 static int 429 update_dirs(ad_disc_ds_t **value, ad_disc_ds_t **new, char *name) 430 { 431 int i; 432 433 if (*new == NULL) 434 return (FALSE); 435 436 if (*value != NULL && ad_disc_compare_ds(*value, *new) == 0) { 437 free(*new); 438 *new = NULL; 439 return (FALSE); 440 } 441 442 if (*value) 443 free(*value); 444 445 for (i = 0; (*new)[i].host[0] != '\0'; i++) 446 idmapdlog(LOG_INFO, "%s: change %s=%s port=%d", me, name, 447 (*new)[i].host, (*new)[i].port); 448 *value = *new; 449 *new = NULL; 450 return (TRUE); 451 } 452 453 454 #define SUBNET_CHECK_TIME (2 * 60) 455 #define MAX_CHECK_TIME (10 * 60) 456 457 /* 458 * Returns 1 if SIGHUP has been received (see hup_handler elsewhere), 0 459 * otherwise. Uses an event port and a user-defined event. 460 * 461 * Note that port_get() does not update its timeout argument when EINTR, 462 * unlike nanosleep(). We probably don't care very much here because 463 * the only signals we expect are ones that will lead to idmapd dying or 464 * SIGHUP, and we intend for the latter to cause this function to 465 * return. But if we did care then we could always use a timer event 466 * (see timer_create(3RT)) and associate it with the same event port, 467 * then we could get accurate waiting regardless of EINTRs. 468 */ 469 static 470 int 471 wait_for_ttl(struct timespec *timeout) 472 { 473 port_event_t pe; 474 int retries = 1; 475 476 /* 477 * If event port creation failed earlier and fails now then we 478 * simply don't learn about SIGHUPs in a timely fashion. No big 479 * deal 480 */ 481 if (hup_ev_port == -1 && (hup_ev_port = port_create()) < 0) { 482 (void) nanosleep(timeout, NULL); 483 return (0); 484 } 485 486 retry: 487 if (port_get(hup_ev_port, &pe, timeout) != 0) { 488 switch (errno) { 489 case EBADF: 490 case EBADFD: 491 hup_ev_port = -1; 492 (void) nanosleep(timeout, NULL); 493 break; 494 case EINVAL: 495 /* 496 * Shouldn't happen, except, perhaps, near the 497 * end of time 498 */ 499 timeout->tv_nsec = 0; 500 timeout->tv_sec = MAX_CHECK_TIME; 501 if (retries-- > 0) 502 goto retry; 503 /* NOTREACHED */ 504 break; 505 case EINTR: 506 if (!hupped) 507 goto retry; 508 break; 509 case ETIME: 510 /* Timeout */ 511 break; 512 default: 513 /* EFAULT */ 514 (void) nanosleep(timeout, NULL); 515 break; 516 } 517 } 518 519 /* 520 * We only have one event that we care about, a user event, so 521 * there's nothing to check or clean up about pe. 522 * 523 * If we get here it's either because we had a SIGHUP and a user 524 * event was sent to our port, or because the port_get() timed 525 * out (or even both!). 526 */ 527 528 if (hupped) { 529 hupped = 0; 530 /* Got SIGHUP, re-read SMF config */ 531 (void) idmapdlog(LOG_INFO, "idmapd: SMF refresh"); 532 WRLOCK_CONFIG(); 533 (void) idmap_cfg_unload(&_idmapdstate.cfg->pgcfg); 534 if (idmap_cfg_load(&_idmapdstate.cfg->handles, 535 &_idmapdstate.cfg->pgcfg) < 0) 536 (void) idmapdlog(LOG_NOTICE, 537 "idmapd: Failed to reload config"); 538 UNLOCK_CONFIG(); 539 return (1); 540 } 541 542 return (0); 543 } 544 545 void * 546 idmap_cfg_update_thread(void *arg) 547 { 548 549 idmap_pg_config_t new_cfg; 550 int ttl; 551 idmap_cfg_handles_t *handles = &_idmapdstate.cfg->handles; 552 idmap_pg_config_t *live_cfg = &_idmapdstate.cfg->pgcfg; 553 ad_disc_t ad_ctx = handles->ad_ctx; 554 struct timespec delay; 555 int changed; 556 557 (void) memset(&new_cfg, 0, sizeof (new_cfg)); 558 559 for (;;) { 560 changed = FALSE; 561 ttl = ad_disc_get_TTL(ad_ctx); 562 if (ttl > MAX_CHECK_TIME) 563 ttl = MAX_CHECK_TIME; 564 while (ttl > 0 || ttl == -1) { 565 if (ttl == -1) { 566 wait_for_ttl(NULL); 567 } else if (ttl > SUBNET_CHECK_TIME) { 568 /* 569 * We really ought to just monitor 570 * network interfaces with a PF_ROUTE 571 * socket... This crude method of 572 * discovering subnet changes will do 573 * for now. Though might even not want 574 * to bother: subnet changes leading to 575 * sitename changes ought never happen, 576 * and requiring a refresh when they do 577 * should be no problem (SMF/NWAM ought 578 * to be able to refresh us). 579 */ 580 delay.tv_sec = SUBNET_CHECK_TIME; 581 delay.tv_nsec = 0; 582 if (wait_for_ttl(&delay)) { 583 /* Got SIGHUP, re-discover */ 584 ttl = 0; 585 changed = TRUE; 586 break; 587 } 588 ttl -= SUBNET_CHECK_TIME; 589 if (ad_disc_SubnetChanged(ad_ctx)) 590 break; 591 } else { 592 delay.tv_sec = ttl; 593 delay.tv_nsec = 0; 594 if (wait_for_ttl(&delay)) 595 changed = TRUE; 596 ttl = 0; 597 } 598 } 599 600 /* 601 * Load configuration data into a private copy. 602 * 603 * The fixed values (i.e., from SMF) have already been 604 * set in AD auto discovery, so if all values have been 605 * set in SMF and they haven't been changed or the 606 * service been refreshed then the rest of this loop's 607 * body is one big no-op. 608 */ 609 pthread_mutex_lock(&handles->mutex); 610 611 new_cfg.default_domain = ad_disc_get_DomainName(ad_ctx); 612 if (new_cfg.default_domain == NULL) { 613 idmapdlog(LOG_INFO, 614 "%s: unable to discover Default Domain", me); 615 } 616 617 new_cfg.domain_name = ad_disc_get_DomainName(ad_ctx); 618 if (new_cfg.domain_name == NULL) { 619 idmapdlog(LOG_INFO, 620 "%s: unable to discover Domain Name", me); 621 } 622 623 new_cfg.domain_controller = 624 ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE); 625 if (new_cfg.domain_controller == NULL) { 626 idmapdlog(LOG_INFO, 627 "%s: unable to discover Domain Controller", me); 628 } 629 630 new_cfg.forest_name = ad_disc_get_ForestName(ad_ctx); 631 if (new_cfg.forest_name == NULL) { 632 idmapdlog(LOG_INFO, 633 "%s: unable to discover Forest Name", me); 634 } 635 636 new_cfg.site_name = ad_disc_get_SiteName(ad_ctx); 637 if (new_cfg.site_name == NULL) { 638 idmapdlog(LOG_INFO, 639 "%s: unable to discover Site Name", me); 640 } 641 642 new_cfg.global_catalog = 643 ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE); 644 if (new_cfg.global_catalog == NULL) { 645 idmapdlog(LOG_INFO, 646 "%s: unable to discover Global Catalog", me); 647 } 648 649 pthread_mutex_unlock(&handles->mutex); 650 651 if (new_cfg.default_domain == NULL && 652 new_cfg.domain_name == NULL && 653 new_cfg.domain_controller == NULL && 654 new_cfg.forest_name == NULL && 655 new_cfg.global_catalog == NULL) { 656 idmapdlog(LOG_NOTICE, "%s: Could not auto-discover AD " 657 "domain and forest names nor domain controllers " 658 "and global catalog servers", me); 659 idmap_cfg_unload(&new_cfg); 660 continue; 661 } 662 663 /* 664 * Update the live configuration 665 */ 666 WRLOCK_CONFIG(); 667 668 if (live_cfg->list_size_limit != new_cfg.list_size_limit) { 669 idmapdlog(LOG_INFO, "%s: change list_size=%d", me, 670 new_cfg.list_size_limit); 671 live_cfg->list_size_limit = new_cfg.list_size_limit; 672 } 673 674 /* 675 * If default_domain came from SMF then we must not 676 * auto-discover it. 677 */ 678 if (live_cfg->dflt_dom_set_in_smf == FALSE && 679 update_value(&live_cfg->default_domain, 680 &new_cfg.default_domain, "default_domain") == TRUE) 681 changed = TRUE; 682 683 (void) update_value(&live_cfg->domain_name, 684 &new_cfg.domain_name, "domain_name"); 685 686 (void) update_dirs(&live_cfg->domain_controller, 687 &new_cfg.domain_controller, "domain_controller"); 688 689 (void) update_value(&live_cfg->forest_name, 690 &new_cfg.forest_name, "forest_name"); 691 692 (void) update_value(&live_cfg->site_name, 693 &new_cfg.site_name, "site_name"); 694 695 if (update_dirs(&live_cfg->global_catalog, 696 &new_cfg.global_catalog, "global_catalog") == TRUE) 697 changed = TRUE; 698 UNLOCK_CONFIG(); 699 700 idmap_cfg_unload(&new_cfg); 701 702 703 /* 704 * Re-create the ad_t/ad_host_t objects if 705 * either the default domain or the global 706 * catalog server list changed. 707 */ 708 709 if (changed) { 710 RDLOCK_CONFIG(); 711 (void) reload_ad(); 712 UNLOCK_CONFIG(); 713 print_idmapdstate(); 714 } 715 } 716 /*NOTREACHED*/ 717 return (NULL); 718 } 719 720 721 int 722 idmap_cfg_start_updates(idmap_cfg_t *cfg) 723 { 724 /* Don't check for failure -- see wait_for_ttl() */ 725 hup_ev_port = port_create(); 726 727 errno = pthread_create(&update_thread_handle, NULL, 728 idmap_cfg_update_thread, NULL); 729 if (errno == 0) 730 return (0); 731 else 732 return (-1); 733 } 734 735 736 int 737 idmap_cfg_load(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) 738 { 739 int rc = 0; 740 char *str = NULL; 741 ad_disc_t ad_ctx = handles->ad_ctx; 742 743 pgcfg->list_size_limit = 0; 744 pgcfg->default_domain = NULL; 745 pgcfg->domain_name = NULL; 746 pgcfg->machine_sid = NULL; 747 pgcfg->domain_controller = NULL; 748 pgcfg->forest_name = NULL; 749 pgcfg->site_name = NULL; 750 pgcfg->global_catalog = NULL; 751 752 pthread_mutex_lock(&handles->mutex); 753 754 ad_disc_refresh(handles->ad_ctx); 755 756 if (scf_pg_update(handles->config_pg) < 0) { 757 idmapdlog(LOG_ERR, "%s: scf_pg_update() failed: %s", 758 me, scf_strerror(scf_error())); 759 rc = -1; 760 goto exit; 761 } 762 763 if (scf_pg_update(handles->general_pg) < 0) { 764 idmapdlog(LOG_ERR, "%s: scf_pg_update() failed: %s", 765 me, scf_strerror(scf_error())); 766 rc = -1; 767 goto exit; 768 } 769 770 rc = get_val_int(handles, "list_size_limit", 771 &pgcfg->list_size_limit, SCF_TYPE_COUNT); 772 if (rc != 0) { 773 rc = -1; 774 goto exit; 775 } 776 777 rc = get_val_astring(handles, "domain_name", 778 &pgcfg->domain_name); 779 if (rc != 0) { 780 rc = -1; 781 goto exit; 782 } 783 (void) ad_disc_set_DomainName(ad_ctx, pgcfg->domain_name); 784 785 rc = get_val_astring(handles, "default_domain", 786 &pgcfg->default_domain); 787 if (rc != 0) { 788 rc = -1; 789 goto exit; 790 } 791 792 rc = get_val_astring(handles, "mapping_domain", &str); 793 if (rc != 0) { 794 rc = -1; 795 goto exit; 796 } 797 798 /* 799 * We treat default_domain as having been specified in SMF IFF 800 * either (the config/default_domain property was set) or (the 801 * old, obsolete, never documented config/mapping_domain 802 * property was set and the new config/domain_name property was 803 * not set). 804 */ 805 pgcfg->dflt_dom_set_in_smf = TRUE; 806 if (pgcfg->default_domain == NULL) { 807 808 pgcfg->dflt_dom_set_in_smf = FALSE; 809 810 if (pgcfg->domain_name != NULL) { 811 pgcfg->default_domain = strdup(pgcfg->domain_name); 812 if (str != NULL) { 813 idmapdlog(LOG_WARNING, 814 "%s: Ignoring obsolete, undocumented " 815 "config/mapping_domain property", me); 816 } 817 } else if (str != NULL) { 818 pgcfg->default_domain = strdup(str); 819 pgcfg->dflt_dom_set_in_smf = TRUE; 820 idmapdlog(LOG_WARNING, 821 "%s: The config/mapping_domain property is " 822 "obsolete; support for it will be removed, " 823 "please use config/default_domain instead", 824 me); 825 } 826 } 827 828 if (str != NULL) 829 free(str); 830 831 rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid); 832 if (rc != 0) { 833 rc = -1; 834 goto exit; 835 } 836 if (pgcfg->machine_sid == NULL) { 837 /* If machine_sid not configured, generate one */ 838 if (generate_machine_sid(&pgcfg->machine_sid) < 0) { 839 rc = -1; 840 goto exit; 841 } 842 rc = set_val_astring(handles, "machine_sid", 843 pgcfg->machine_sid); 844 if (rc < 0) { 845 free(pgcfg->machine_sid); 846 pgcfg->machine_sid = NULL; 847 rc = -1; 848 goto exit; 849 } 850 } 851 852 str = NULL; 853 rc = get_val_ds(handles, "domain_controller", 389, 854 &pgcfg->domain_controller); 855 if (rc != 0) { 856 rc = -1; 857 goto exit; 858 } 859 (void) ad_disc_set_DomainController(ad_ctx, pgcfg->domain_controller); 860 861 rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name); 862 if (rc != 0) { 863 rc = -1; 864 goto exit; 865 } 866 (void) ad_disc_set_ForestName(ad_ctx, pgcfg->forest_name); 867 868 rc = get_val_astring(handles, "site_name", &pgcfg->site_name); 869 if (rc != 0) { 870 rc = -1; 871 goto exit; 872 } 873 (void) ad_disc_set_SiteName(ad_ctx, pgcfg->site_name); 874 875 str = NULL; 876 rc = get_val_ds(handles, "global_catalog", 3268, 877 &pgcfg->global_catalog); 878 if (rc != 0) { 879 rc = -1; 880 goto exit; 881 } 882 (void) ad_disc_set_GlobalCatalog(ad_ctx, pgcfg->global_catalog); 883 884 885 /* 886 * Auto Discover the rest 887 */ 888 if (pgcfg->default_domain == NULL) { 889 pgcfg->default_domain = ad_disc_get_DomainName(ad_ctx); 890 if (pgcfg->default_domain == NULL) { 891 idmapdlog(LOG_INFO, 892 "%s: unable to discover Default Domain", me); 893 } 894 } 895 896 if (pgcfg->domain_name == NULL) { 897 pgcfg->domain_name = ad_disc_get_DomainName(ad_ctx); 898 if (pgcfg->domain_name == NULL) { 899 idmapdlog(LOG_INFO, 900 "%s: unable to discover Domain Name", me); 901 } 902 } 903 904 if (pgcfg->domain_controller == NULL) { 905 pgcfg->domain_controller = 906 ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE); 907 if (pgcfg->domain_controller == NULL) { 908 idmapdlog(LOG_INFO, 909 "%s: unable to discover Domain Controller", me); 910 } 911 } 912 913 if (pgcfg->forest_name == NULL) { 914 pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx); 915 if (pgcfg->forest_name == NULL) { 916 idmapdlog(LOG_INFO, 917 "%s: unable to discover Forest Name", me); 918 } 919 } 920 921 if (pgcfg->site_name == NULL) { 922 pgcfg->site_name = ad_disc_get_SiteName(ad_ctx); 923 if (pgcfg->site_name == NULL) { 924 idmapdlog(LOG_INFO, 925 "%s: unable to discover Site Name", me); 926 } 927 } 928 929 if (pgcfg->global_catalog == NULL) { 930 pgcfg->global_catalog = 931 ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE); 932 if (pgcfg->global_catalog == NULL) { 933 idmapdlog(LOG_INFO, 934 "%s: unable to discover Global Catalog", me); 935 } 936 } 937 exit: 938 pthread_mutex_unlock(&handles->mutex); 939 940 return (rc); 941 } 942 943 /* 944 * Initialize 'cfg'. 945 */ 946 idmap_cfg_t * 947 idmap_cfg_init() { 948 idmap_cfg_handles_t *handles; 949 950 /* First the smf repository handles: */ 951 idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t)); 952 if (!cfg) { 953 idmapdlog(LOG_ERR, "%s: Out of memory", me); 954 return (NULL); 955 } 956 handles = &cfg->handles; 957 958 (void) pthread_mutex_init(&handles->mutex, NULL); 959 960 if (!(handles->main = scf_handle_create(SCF_VERSION))) { 961 idmapdlog(LOG_ERR, "%s: scf_handle_create() failed: %s", 962 me, scf_strerror(scf_error())); 963 goto error; 964 } 965 966 if (scf_handle_bind(handles->main) < 0) { 967 idmapdlog(LOG_ERR, "%s: scf_handle_bind() failed: %s", 968 me, scf_strerror(scf_error())); 969 goto error; 970 } 971 972 if (!(handles->service = scf_service_create(handles->main)) || 973 !(handles->instance = scf_instance_create(handles->main)) || 974 !(handles->config_pg = scf_pg_create(handles->main)) || 975 !(handles->general_pg = scf_pg_create(handles->main))) { 976 idmapdlog(LOG_ERR, "%s: scf handle creation failed: %s", 977 me, scf_strerror(scf_error())); 978 goto error; 979 } 980 981 if (scf_handle_decode_fmri(handles->main, 982 FMRI_BASE "/:properties/" CONFIG_PG, 983 NULL, /* scope */ 984 handles->service, /* service */ 985 handles->instance, /* instance */ 986 handles->config_pg, /* pg */ 987 NULL, /* prop */ 988 SCF_DECODE_FMRI_EXACT) < 0) { 989 idmapdlog(LOG_ERR, "%s: scf_handle_decode_fmri() failed: %s", 990 me, scf_strerror(scf_error())); 991 goto error; 992 993 } 994 995 if (scf_service_get_pg(handles->service, 996 GENERAL_PG, handles->general_pg) < 0) { 997 idmapdlog(LOG_ERR, "%s: scf_service_get_pg() failed: %s", 998 me, scf_strerror(scf_error())); 999 goto error; 1000 } 1001 1002 /* Initialize AD Auto Discovery context */ 1003 handles->ad_ctx = ad_disc_init(); 1004 if (handles->ad_ctx == NULL) 1005 goto error; 1006 1007 return (cfg); 1008 1009 error: 1010 (void) idmap_cfg_fini(cfg); 1011 return (NULL); 1012 } 1013 1014 void 1015 idmap_cfg_unload(idmap_pg_config_t *pgcfg) { 1016 1017 if (pgcfg->default_domain) { 1018 free(pgcfg->default_domain); 1019 pgcfg->default_domain = NULL; 1020 } 1021 if (pgcfg->domain_name) { 1022 free(pgcfg->domain_name); 1023 pgcfg->domain_name = NULL; 1024 } 1025 if (pgcfg->machine_sid) { 1026 free(pgcfg->machine_sid); 1027 pgcfg->machine_sid = NULL; 1028 } 1029 if (pgcfg->domain_controller) { 1030 free(pgcfg->domain_controller); 1031 pgcfg->domain_controller = NULL; 1032 } 1033 if (pgcfg->forest_name) { 1034 free(pgcfg->forest_name); 1035 pgcfg->forest_name = NULL; 1036 } 1037 if (pgcfg->site_name) { 1038 free(pgcfg->site_name); 1039 pgcfg->site_name = NULL; 1040 } 1041 if (pgcfg->global_catalog) { 1042 free(pgcfg->global_catalog); 1043 pgcfg->global_catalog = NULL; 1044 } 1045 } 1046 1047 int 1048 idmap_cfg_fini(idmap_cfg_t *cfg) 1049 { 1050 idmap_cfg_handles_t *handles = &cfg->handles; 1051 idmap_cfg_unload(&cfg->pgcfg); 1052 1053 (void) pthread_mutex_destroy(&handles->mutex); 1054 scf_pg_destroy(handles->config_pg); 1055 scf_pg_destroy(handles->general_pg); 1056 scf_instance_destroy(handles->instance); 1057 scf_service_destroy(handles->service); 1058 scf_handle_destroy(handles->main); 1059 ad_disc_fini(handles->ad_ctx); 1060 free(cfg); 1061 1062 return (0); 1063 } 1064