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