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