8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / idmap / idmapd / idmap_config.c
blobad3c70b93264db65579f22c7f991eab174c9c88f
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
28 * Config routines common to idmap(1M) and idmapd(1M)
31 #include <stdlib.h>
32 #include <strings.h>
33 #include <libintl.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <stdio.h>
37 #include <stdarg.h>
38 #include <uuid/uuid.h>
39 #include <pthread.h>
40 #include <port.h>
41 #include <sys/socket.h>
42 #include <net/route.h>
43 #include <sys/u8_textprep.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 #include <netdb.h>
47 #include <note.h>
48 #include "idmapd.h"
49 #include "addisc.h"
51 #define MACHINE_SID_LEN (9 + 3 * 11)
52 #define FMRI_BASE "svc:/system/idmap"
53 #define CONFIG_PG "config"
54 #define DEBUG_PG "debug"
55 #define RECONFIGURE 1
56 #define POKE_AUTO_DISCOVERY 2
57 #define KICK_AUTO_DISCOVERY 3
60 * Default cache timeouts. Can override via svccfg
61 * config/id_cache_timeout = count: seconds
62 * config/name_cache_timeout = count: seconds
64 #define ID_CACHE_TMO_DEFAULT 86400
65 #define NAME_CACHE_TMO_DEFAULT 604800
68 * Default maximum time between rediscovery runs.
69 * config/rediscovery_interval = count: seconds
71 #define REDISCOVERY_INTERVAL_DEFAULT 3600
74 * Mininum time between rediscovery runs, in case adutils gives us a
75 * really short TTL (which it never should, but be defensive)
76 * (not configurable) seconds.
78 #define MIN_REDISCOVERY_INTERVAL 60
80 enum event_type {
81 EVENT_NOTHING, /* Woke up for no good reason */
82 EVENT_TIMEOUT, /* Timeout expired */
83 EVENT_ROUTING, /* An interesting routing event happened */
84 EVENT_POKED, /* Requested from degrade_svc() */
85 EVENT_KICKED, /* Force rediscovery, i.e. DC failed. */
86 EVENT_REFRESH, /* SMF refresh */
90 static void idmapd_set_krb5_realm(char *);
92 static pthread_t update_thread_handle = 0;
94 static int idmapd_ev_port = -1;
95 static int rt_sock = -1;
97 struct enum_lookup_map directory_mapping_map[] = {
98 { DIRECTORY_MAPPING_NONE, "none" },
99 { DIRECTORY_MAPPING_NAME, "name" },
100 { DIRECTORY_MAPPING_IDMU, "idmu" },
101 { 0, NULL },
104 struct enum_lookup_map trust_dir_map[] = {
105 { 1, "they trust us" },
106 { 2, "we trust them" },
107 { 3, "we trust each other" },
108 { 0, NULL },
111 static int
112 generate_machine_uuid(char **machine_uuid)
114 uuid_t uu;
116 *machine_uuid = calloc(1, UUID_PRINTABLE_STRING_LENGTH + 1);
117 if (*machine_uuid == NULL) {
118 idmapdlog(LOG_ERR, "Out of memory");
119 return (-1);
122 uuid_clear(uu);
123 uuid_generate_time(uu);
124 uuid_unparse(uu, *machine_uuid);
126 return (0);
129 static int
130 generate_machine_sid(char **machine_sid, char *machine_uuid)
132 union {
133 uuid_t uu;
134 uint32_t v[4];
135 } uv;
136 int len;
139 * Split the 128-bit machine UUID into three 32-bit values
140 * we'll use as the "sub-authorities" of the machine SID.
141 * The machine_sid will have the form S-1-5-21-J-K-L
142 * (that's four sub-authorities altogether) where:
143 * J = last 4 bytes of node_addr,
144 * K = time_mid, time_hi_and_version
145 * L = time_low
146 * (see struct uuid)
149 (void) memset(&uv, 0, sizeof (uv));
150 (void) uuid_parse(machine_uuid, uv.uu);
152 len = asprintf(machine_sid, "S-1-5-21-%u-%u-%u",
153 uv.v[3], uv.v[0], uv.v[1]);
155 if (len == -1 || *machine_sid == NULL) {
156 idmapdlog(LOG_ERR, "Out of memory");
157 return (-1);
160 return (0);
164 /* In the case of error, exists is set to FALSE anyway */
165 static int
166 prop_exists(idmap_cfg_handles_t *handles, const char *name, boolean_t *exists)
169 scf_property_t *scf_prop;
171 *exists = B_FALSE;
173 scf_prop = scf_property_create(handles->main);
174 if (scf_prop == NULL) {
175 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
176 scf_strerror(scf_error()));
177 return (-1);
180 if (scf_pg_get_property(handles->config_pg, name, scf_prop) == 0)
181 *exists = B_TRUE;
183 scf_property_destroy(scf_prop);
185 return (0);
188 static int
189 get_debug(idmap_cfg_handles_t *handles, const char *name)
191 int64_t i64 = 0;
193 scf_property_t *scf_prop;
194 scf_value_t *value;
196 scf_prop = scf_property_create(handles->main);
197 if (scf_prop == NULL) {
198 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
199 scf_strerror(scf_error()));
200 abort();
202 value = scf_value_create(handles->main);
203 if (value == NULL) {
204 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
205 scf_strerror(scf_error()));
206 abort();
209 if (scf_pg_get_property(handles->debug_pg, name, scf_prop) < 0) {
210 /* this is OK: the property is just undefined */
211 goto destruction;
215 if (scf_property_get_value(scf_prop, value) < 0) {
216 /* It is still OK when a property doesn't have any value */
217 goto destruction;
220 if (scf_value_get_integer(value, &i64) != 0) {
221 idmapdlog(LOG_ERR, "Can not retrieve %s/%s: %s",
222 DEBUG_PG, name, scf_strerror(scf_error()));
223 abort();
226 destruction:
227 scf_value_destroy(value);
228 scf_property_destroy(scf_prop);
230 return ((int)i64);
233 static int
234 get_val_bool(idmap_cfg_handles_t *handles, const char *name,
235 boolean_t *val, boolean_t default_val)
237 int rc = 0;
239 scf_property_t *scf_prop;
240 scf_value_t *value;
242 *val = default_val;
244 scf_prop = scf_property_create(handles->main);
245 if (scf_prop == NULL) {
246 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
247 scf_strerror(scf_error()));
248 return (-1);
250 value = scf_value_create(handles->main);
251 if (value == NULL) {
252 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
253 scf_strerror(scf_error()));
254 scf_property_destroy(scf_prop);
255 return (-1);
258 /* It is OK if the property is undefined */
259 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
260 goto destruction;
263 /* It is still OK when a property doesn't have any value */
264 if (scf_property_get_value(scf_prop, value) < 0)
265 goto destruction;
267 uint8_t b;
268 rc = scf_value_get_boolean(value, &b);
270 if (rc == 0)
271 *val = (boolean_t)b;
273 destruction:
274 scf_value_destroy(value);
275 scf_property_destroy(scf_prop);
277 return (rc);
280 static int
281 get_val_int(idmap_cfg_handles_t *handles, const char *name,
282 void *val, scf_type_t type)
284 int rc = 0;
286 scf_property_t *scf_prop;
287 scf_value_t *value;
289 switch (type) {
290 case SCF_TYPE_COUNT:
291 *(uint64_t *)val = 0;
292 break;
293 case SCF_TYPE_INTEGER:
294 *(int64_t *)val = 0;
295 break;
296 default:
297 idmapdlog(LOG_ERR, "Invalid scf integer type (%d)",
298 type);
299 abort();
302 scf_prop = scf_property_create(handles->main);
303 if (scf_prop == NULL) {
304 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
305 scf_strerror(scf_error()));
306 return (-1);
308 value = scf_value_create(handles->main);
309 if (value == NULL) {
310 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
311 scf_strerror(scf_error()));
312 scf_property_destroy(scf_prop);
313 return (-1);
316 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
317 /* this is OK: the property is just undefined */
318 goto destruction;
321 if (scf_property_get_value(scf_prop, value) < 0)
322 /* It is still OK when a property doesn't have any value */
323 goto destruction;
325 switch (type) {
326 case SCF_TYPE_COUNT:
327 rc = scf_value_get_count(value, val);
328 break;
329 case SCF_TYPE_INTEGER:
330 rc = scf_value_get_integer(value, val);
331 break;
332 default:
333 abort(); /* tested above */
334 /* NOTREACHED */
337 if (rc != 0) {
338 idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s",
339 name, scf_strerror(scf_error()));
342 destruction:
343 scf_value_destroy(value);
344 scf_property_destroy(scf_prop);
346 return (rc);
349 static char *
350 scf_value2string(const char *name, scf_value_t *value)
352 static size_t max_val = 0;
354 if (max_val == 0)
355 max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
357 char buf[max_val + 1];
358 if (scf_value_get_astring(value, buf, max_val + 1) < 0) {
359 idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s",
360 name, scf_strerror(scf_error()));
361 return (NULL);
364 char *s = strdup(buf);
365 if (s == NULL)
366 idmapdlog(LOG_ERR, "Out of memory");
368 return (s);
371 static int
372 get_val_ds(idmap_cfg_handles_t *handles, const char *name, int defport,
373 ad_disc_ds_t **val)
375 char port_str[8];
376 struct addrinfo hints;
377 struct addrinfo *ai;
378 ad_disc_ds_t *servers = NULL;
379 scf_property_t *scf_prop;
380 scf_value_t *value;
381 scf_iter_t *iter;
382 char *host, *portstr;
383 int err, len, i;
384 int count = 0;
385 int rc = -1;
387 *val = NULL;
389 restart:
390 scf_prop = scf_property_create(handles->main);
391 if (scf_prop == NULL) {
392 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
393 scf_strerror(scf_error()));
394 return (-1);
397 value = scf_value_create(handles->main);
398 if (value == NULL) {
399 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
400 scf_strerror(scf_error()));
401 scf_property_destroy(scf_prop);
402 return (-1);
405 iter = scf_iter_create(handles->main);
406 if (iter == NULL) {
407 idmapdlog(LOG_ERR, "scf_iter_create() failed: %s",
408 scf_strerror(scf_error()));
409 scf_value_destroy(value);
410 scf_property_destroy(scf_prop);
411 return (-1);
414 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) {
415 /* this is OK: the property is just undefined */
416 rc = 0;
417 goto destruction;
420 if (scf_iter_property_values(iter, scf_prop) < 0) {
421 idmapdlog(LOG_ERR,
422 "scf_iter_property_values(%s) failed: %s",
423 name, scf_strerror(scf_error()));
424 goto destruction;
427 /* Workaround scf bugs -- can't reset an iteration */
428 if (count == 0) {
429 while (scf_iter_next_value(iter, value) > 0)
430 count++;
432 if (count == 0) {
433 /* no values */
434 rc = 0;
435 goto destruction;
438 scf_value_destroy(value);
439 scf_iter_destroy(iter);
440 scf_property_destroy(scf_prop);
441 goto restart;
444 if ((servers = calloc(count + 1, sizeof (*servers))) == NULL) {
445 idmapdlog(LOG_ERR, "Out of memory");
446 goto destruction;
449 (void) memset(&hints, 0, sizeof (hints));
450 hints.ai_protocol = IPPROTO_TCP;
451 hints.ai_socktype = SOCK_STREAM;
452 host = NULL;
454 i = 0;
455 while (i < count && scf_iter_next_value(iter, value) > 0) {
456 if (host) {
457 free(host);
458 host = NULL;
460 servers[i].priority = 0;
461 servers[i].weight = 100;
462 servers[i].port = defport;
463 if ((host = scf_value2string(name, value)) == NULL)
464 continue;
465 if ((portstr = strchr(host, ':')) != NULL) {
466 *portstr++ = '\0';
467 servers[i].port = strtol(portstr,
468 (char **)NULL, 10);
469 if (servers[i].port == 0)
470 servers[i].port = defport;
474 * Ignore this server if the hostname is too long
475 * or empty (continue without i++)
477 len = strlen(host);
478 if (len == 0) {
479 if (DBG(CONFIG, 1)) {
480 idmapdlog(LOG_INFO, "%s host=\"\"", name);
482 continue;
484 if (len >= sizeof (servers->host)) {
485 idmapdlog(LOG_ERR, "Host name too long: %s", host);
486 idmapdlog(LOG_ERR, "ignoring %s value", name);
487 continue;
491 * Get the host address too. If we can't, then
492 * log an error and skip this host.
494 (void) snprintf(port_str, sizeof (port_str),
495 "%d", servers[i].port);
496 ai = NULL;
497 err = getaddrinfo(host, port_str, &hints, &ai);
498 if (err != 0) {
499 idmapdlog(LOG_ERR, "No address for host: %s (%s)",
500 host, gai_strerror(err));
501 idmapdlog(LOG_ERR, "ignoring %s value", name);
502 continue;
505 (void) strlcpy(servers[i].host, host,
506 sizeof (servers->host));
507 (void) memcpy(&servers[i].addr, ai->ai_addr, ai->ai_addrlen);
508 freeaddrinfo(ai);
510 /* Added a DS to the array. */
511 i++;
513 free(host);
515 if (i == 0) {
516 if (DBG(CONFIG, 1)) {
517 idmapdlog(LOG_INFO, "%s is empty", name);
519 free(servers);
520 servers = NULL;
522 *val = servers;
524 rc = 0;
526 destruction:
527 scf_value_destroy(value);
528 scf_iter_destroy(iter);
529 scf_property_destroy(scf_prop);
531 if (rc < 0) {
532 if (servers)
533 free(servers);
534 *val = NULL;
537 return (rc);
540 static int
541 get_val_astring(idmap_cfg_handles_t *handles, const char *name, char **val)
543 int rc = 0;
545 scf_property_t *scf_prop;
546 scf_value_t *value;
548 scf_prop = scf_property_create(handles->main);
549 if (scf_prop == NULL) {
550 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
551 scf_strerror(scf_error()));
552 return (-1);
554 value = scf_value_create(handles->main);
555 if (value == NULL) {
556 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
557 scf_strerror(scf_error()));
558 scf_property_destroy(scf_prop);
559 return (-1);
562 *val = NULL;
564 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
565 /* this is OK: the property is just undefined */
566 goto destruction;
568 if (scf_property_get_value(scf_prop, value) < 0) {
569 idmapdlog(LOG_ERR,
570 "scf_property_get_value(%s) failed: %s",
571 name, scf_strerror(scf_error()));
572 rc = -1;
573 goto destruction;
576 *val = scf_value2string(name, value);
577 if (*val == NULL)
578 rc = -1;
580 destruction:
581 scf_value_destroy(value);
582 scf_property_destroy(scf_prop);
584 if (rc < 0) {
585 if (*val)
586 free(*val);
587 *val = NULL;
590 return (rc);
594 static int
595 del_val(
596 idmap_cfg_handles_t *handles,
597 scf_propertygroup_t *pg,
598 const char *name)
600 int rc = -1;
601 int ret;
602 scf_transaction_t *tx = NULL;
603 scf_transaction_entry_t *ent = NULL;
605 if ((tx = scf_transaction_create(handles->main)) == NULL) {
606 idmapdlog(LOG_ERR,
607 "scf_transaction_create() failed: %s",
608 scf_strerror(scf_error()));
609 goto destruction;
611 if ((ent = scf_entry_create(handles->main)) == NULL) {
612 idmapdlog(LOG_ERR,
613 "scf_entry_create() failed: %s",
614 scf_strerror(scf_error()));
615 goto destruction;
618 do {
619 if (scf_pg_update(pg) == -1) {
620 idmapdlog(LOG_ERR,
621 "scf_pg_update(%s) failed: %s",
622 name, scf_strerror(scf_error()));
623 goto destruction;
625 if (scf_transaction_start(tx, pg) != 0) {
626 idmapdlog(LOG_ERR,
627 "scf_transaction_start(%s) failed: %s",
628 name, scf_strerror(scf_error()));
629 goto destruction;
632 if (scf_transaction_property_delete(tx, ent, name) != 0) {
633 /* Don't complain if it already doesn't exist. */
634 if (scf_error() != SCF_ERROR_NOT_FOUND) {
635 idmapdlog(LOG_ERR,
636 "scf_transaction_property_delete() failed:"
637 " %s",
638 scf_strerror(scf_error()));
640 goto destruction;
643 ret = scf_transaction_commit(tx);
645 if (ret == 0)
646 scf_transaction_reset(tx);
647 } while (ret == 0);
649 if (ret == -1) {
650 idmapdlog(LOG_ERR,
651 "scf_transaction_commit(%s) failed: %s",
652 name, scf_strerror(scf_error()));
653 goto destruction;
656 rc = 0;
658 destruction:
659 if (ent != NULL)
660 scf_entry_destroy(ent);
661 if (tx != NULL)
662 scf_transaction_destroy(tx);
663 return (rc);
667 static int
668 set_val(
669 idmap_cfg_handles_t *handles,
670 scf_propertygroup_t *pg,
671 const char *name,
672 scf_value_t *value)
674 int rc = -1;
675 int i;
676 scf_property_t *prop = NULL;
677 scf_transaction_t *tx = NULL;
678 scf_transaction_entry_t *ent = NULL;
680 if ((prop = scf_property_create(handles->main)) == NULL ||
681 (tx = scf_transaction_create(handles->main)) == NULL ||
682 (ent = scf_entry_create(handles->main)) == NULL) {
683 idmapdlog(LOG_ERR, "Unable to set property %s",
684 name, scf_strerror(scf_error()));
685 goto destruction;
688 for (i = 0; i < MAX_TRIES; i++) {
689 int ret;
691 if (scf_pg_update(pg) == -1) {
692 idmapdlog(LOG_ERR,
693 "scf_pg_update() failed: %s",
694 scf_strerror(scf_error()));
695 goto destruction;
698 if (scf_transaction_start(tx, pg) == -1) {
699 idmapdlog(LOG_ERR,
700 "scf_transaction_start(%s) failed: %s",
701 name, scf_strerror(scf_error()));
702 goto destruction;
705 ret = scf_pg_get_property(pg, name, prop);
706 if (ret == SCF_SUCCESS) {
707 if (scf_transaction_property_change_type(tx, ent, name,
708 scf_value_type(value)) < 0) {
709 idmapdlog(LOG_ERR,
710 "scf_transaction_property_change_type(%s)"
711 " failed: %s",
712 name, scf_strerror(scf_error()));
713 goto destruction;
715 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
716 if (scf_transaction_property_new(tx, ent, name,
717 scf_value_type(value)) < 0) {
718 idmapdlog(LOG_ERR,
719 "scf_transaction_property_new() failed: %s",
720 scf_strerror(scf_error()));
721 goto destruction;
723 } else {
724 idmapdlog(LOG_ERR,
725 "scf_pg_get_property(%s) failed: %s",
726 name, scf_strerror(scf_error()));
727 goto destruction;
730 if (scf_entry_add_value(ent, value) == -1) {
731 idmapdlog(LOG_ERR,
732 "scf_entry_add_value() failed: %s",
733 scf_strerror(scf_error()));
734 goto destruction;
737 ret = scf_transaction_commit(tx);
738 if (ret == 0) {
740 * Property group set in scf_transaction_start()
741 * is not the most recent. Update pg, reset tx and
742 * retry tx.
744 idmapdlog(LOG_WARNING,
745 "scf_transaction_commit(%s) failed: %s",
746 name, scf_strerror(scf_error()));
747 scf_transaction_reset(tx);
748 continue;
750 if (ret != 1) {
751 idmapdlog(LOG_ERR,
752 "scf_transaction_commit(%s) failed: %s",
753 name, scf_strerror(scf_error()));
754 goto destruction;
756 /* Success! */
757 rc = 0;
758 break;
761 destruction:
762 scf_entry_destroy(ent);
763 scf_transaction_destroy(tx);
764 scf_property_destroy(prop);
765 return (rc);
768 static int
769 set_val_integer(
770 idmap_cfg_handles_t *handles,
771 scf_propertygroup_t *pg,
772 const char *name,
773 int64_t val)
775 scf_value_t *value = NULL;
776 int rc;
778 if ((value = scf_value_create(handles->main)) == NULL) {
779 idmapdlog(LOG_ERR, "Unable to set property %s",
780 name, scf_strerror(scf_error()));
781 return (-1);
784 scf_value_set_integer(value, val);
786 rc = set_val(handles, pg, name, value);
788 scf_value_destroy(value);
790 return (rc);
794 static int
795 set_val_astring(
796 idmap_cfg_handles_t *handles,
797 scf_propertygroup_t *pg,
798 const char *name,
799 const char *val)
801 scf_value_t *value = NULL;
802 int rc = -1;
804 if ((value = scf_value_create(handles->main)) == NULL) {
805 idmapdlog(LOG_ERR, "Unable to set property %s",
806 name, scf_strerror(scf_error()));
807 goto out;
810 if (scf_value_set_astring(value, val) == -1) {
811 idmapdlog(LOG_ERR,
812 "scf_value_set_astring() failed: %s",
813 scf_strerror(scf_error()));
814 goto out;
817 rc = set_val(handles, pg, name, value);
819 out:
820 scf_value_destroy(value);
821 return (rc);
827 * This function updates a boolean value.
828 * If nothing has changed it returns 0 else 1
830 static int
831 update_bool(boolean_t *value, boolean_t *new, char *name)
833 if (*value == *new)
834 return (0);
836 if (DBG(CONFIG, 1)) {
837 idmapdlog(LOG_INFO, "change %s=%s", name,
838 *new ? "true" : "false");
841 *value = *new;
842 return (1);
846 * This function updates a uint64_t value.
847 * If nothing has changed it returns 0 else 1
849 static int
850 update_uint64(uint64_t *value, uint64_t *new, char *name)
852 if (*value == *new)
853 return (0);
855 if (DBG(CONFIG, 1))
856 idmapdlog(LOG_INFO, "change %s=%llu", name, *new);
858 *value = *new;
859 return (1);
863 * This function updates a string value.
864 * If nothing has changed it returns 0 else 1
866 static int
867 update_string(char **value, char **new, char *name)
869 int changed;
871 if (*new == NULL && *value != NULL)
872 changed = 1;
873 else if (*new != NULL && *value == NULL)
874 changed = 1;
875 else if (*new != NULL && *value != NULL && strcmp(*new, *value) != 0)
876 changed = 1;
877 else
878 changed = 0;
881 * Note that even if unchanged we can't just return; we must free one
882 * of the values.
885 if (DBG(CONFIG, 1) && changed)
886 idmapdlog(LOG_INFO, "change %s=%s", name, CHECK_NULL(*new));
888 free(*value);
889 *value = *new;
890 *new = NULL;
891 return (changed);
894 static int
895 update_enum(int *value, int *new, char *name, struct enum_lookup_map *map)
897 if (*value == *new)
898 return (0);
900 if (DBG(CONFIG, 1)) {
901 idmapdlog(LOG_INFO, "change %s=%s", name,
902 enum_lookup(*new, map));
905 *value = *new;
907 return (1);
911 * This function updates a directory service structure.
912 * If nothing has changed it returns 0 else 1
914 static int
915 update_dirs(ad_disc_ds_t **value, ad_disc_ds_t **new, char *name)
918 if (*value == *new)
919 /* Nothing to do */
920 return (0);
922 if (*value != NULL && *new != NULL &&
923 ad_disc_compare_ds(*value, *new) == 0) {
924 free(*new);
925 *new = NULL;
926 return (0);
929 if (*value != NULL)
930 free(*value);
932 *value = *new;
933 *new = NULL;
935 if (*value == NULL) {
936 /* We're unsetting this DS property */
937 if (DBG(CONFIG, 1))
938 idmapdlog(LOG_INFO, "change %s=<none>", name);
939 return (1);
942 if (DBG(CONFIG, 1)) {
943 /* List all the new DSs */
944 char buf[64];
945 ad_disc_ds_t *ds;
946 for (ds = *value; ds->host[0] != '\0'; ds++) {
947 if (ad_disc_getnameinfo(buf, sizeof (buf), &ds->addr))
948 (void) strlcpy(buf, "?", sizeof (buf));
949 idmapdlog(LOG_INFO, "change %s=%s addr=%s port=%d",
950 name, ds->host, buf, ds->port);
953 return (1);
957 * This function updates a trusted domains structure.
958 * If nothing has changed it returns 0 else 1
960 static int
961 update_trusted_domains(ad_disc_trusteddomains_t **value,
962 ad_disc_trusteddomains_t **new, char *name)
964 int i;
966 if (*value == *new)
967 /* Nothing to do */
968 return (0);
970 if (*value != NULL && *new != NULL &&
971 ad_disc_compare_trusteddomains(*value, *new) == 0) {
972 free(*new);
973 *new = NULL;
974 return (0);
977 if (*value != NULL)
978 free(*value);
980 *value = *new;
981 *new = NULL;
983 if (*value == NULL) {
984 /* We're unsetting this DS property */
985 if (DBG(CONFIG, 1))
986 idmapdlog(LOG_INFO, "change %s=<none>", name);
987 return (1);
990 if (DBG(CONFIG, 1)) {
991 /* List all the new domains */
992 for (i = 0; (*value)[i].domain[0] != '\0'; i++) {
993 idmapdlog(LOG_INFO, "change %s=%s direction=%s", name,
994 (*value)[i].domain,
995 enum_lookup((*value)[i].direction, trust_dir_map));
998 return (1);
1003 * This function updates a domains in a forest structure.
1004 * If nothing has changed it returns 0 else 1
1006 static int
1007 update_domains_in_forest(ad_disc_domainsinforest_t **value,
1008 ad_disc_domainsinforest_t **new, char *name)
1010 int i;
1012 if (*value == *new)
1013 /* Nothing to do */
1014 return (0);
1016 if (*value != NULL && *new != NULL &&
1017 ad_disc_compare_domainsinforest(*value, *new) == 0) {
1018 free(*new);
1019 *new = NULL;
1020 return (0);
1023 if (*value != NULL)
1024 free(*value);
1026 *value = *new;
1027 *new = NULL;
1029 if (*value == NULL) {
1030 /* We're unsetting this DS property */
1031 if (DBG(CONFIG, 1))
1032 idmapdlog(LOG_INFO, "change %s=<none>", name);
1033 return (1);
1036 if (DBG(CONFIG, 1)) {
1037 /* List all the new domains */
1038 for (i = 0; (*value)[i].domain[0] != '\0'; i++) {
1039 idmapdlog(LOG_INFO, "change %s=%s", name,
1040 (*value)[i].domain);
1043 return (1);
1047 static void
1048 free_trusted_forests(idmap_trustedforest_t **value, int *num_values)
1050 int i;
1052 for (i = 0; i < *num_values; i++) {
1053 free((*value)[i].forest_name);
1054 free((*value)[i].global_catalog);
1055 free((*value)[i].domains_in_forest);
1057 free(*value);
1058 *value = NULL;
1059 *num_values = 0;
1063 static int
1064 compare_trusteddomainsinforest(ad_disc_domainsinforest_t *df1,
1065 ad_disc_domainsinforest_t *df2)
1067 int i, j;
1068 int num_df1 = 0;
1069 int num_df2 = 0;
1070 boolean_t match;
1072 for (i = 0; df1[i].domain[0] != '\0'; i++)
1073 if (df1[i].trusted)
1074 num_df1++;
1076 for (j = 0; df2[j].domain[0] != '\0'; j++)
1077 if (df2[j].trusted)
1078 num_df2++;
1080 if (num_df1 != num_df2)
1081 return (1);
1083 for (i = 0; df1[i].domain[0] != '\0'; i++) {
1084 if (df1[i].trusted) {
1085 match = B_FALSE;
1086 for (j = 0; df2[j].domain[0] != '\0'; j++) {
1087 if (df2[j].trusted &&
1088 domain_eq(df1[i].domain, df2[j].domain) &&
1089 strcmp(df1[i].sid, df2[j].sid) == 0) {
1090 match = B_TRUE;
1091 break;
1094 if (!match)
1095 return (1);
1098 return (0);
1104 * This function updates trusted forest structure.
1105 * If nothing has changed it returns 0 else 1
1107 static int
1108 update_trusted_forest(idmap_trustedforest_t **value, int *num_value,
1109 idmap_trustedforest_t **new, int *num_new, char *name)
1111 int i, j;
1112 boolean_t match;
1114 if (*value == *new)
1115 /* Nothing to do */
1116 return (0);
1118 if (*value != NULL && *new != NULL) {
1119 if (*num_value != *num_new)
1120 goto not_equal;
1121 for (i = 0; i < *num_value; i++) {
1122 match = B_FALSE;
1123 for (j = 0; j < *num_new; j++) {
1124 if (strcmp((*value)[i].forest_name,
1125 (*new)[j].forest_name) == 0 &&
1126 ad_disc_compare_ds(
1127 (*value)[i].global_catalog,
1128 (*new)[j].global_catalog) == 0 &&
1129 compare_trusteddomainsinforest(
1130 (*value)[i].domains_in_forest,
1131 (*new)[j].domains_in_forest) == 0) {
1132 match = B_TRUE;
1133 break;
1136 if (!match)
1137 goto not_equal;
1139 free_trusted_forests(new, num_new);
1140 return (0);
1142 not_equal:
1143 if (*value != NULL)
1144 free_trusted_forests(value, num_value);
1145 *value = *new;
1146 *num_value = *num_new;
1147 *new = NULL;
1148 *num_new = 0;
1150 if (*value == NULL) {
1151 /* We're unsetting this DS property */
1152 if (DBG(CONFIG, 1))
1153 idmapdlog(LOG_INFO, "change %s=<none>", name);
1154 return (1);
1157 if (DBG(CONFIG, 1)) {
1158 /* List all the trusted forests */
1159 for (i = 0; i < *num_value; i++) {
1160 idmap_trustedforest_t *f = &(*value)[i];
1161 for (j = 0;
1162 f->domains_in_forest[j].domain[0] != '\0';
1163 j++) {
1164 /* List trusted Domains in the forest. */
1165 if (f->domains_in_forest[j].trusted)
1166 idmapdlog(LOG_INFO,
1167 "change %s=%s domain=%s",
1168 name, f->forest_name,
1169 f->domains_in_forest[j].domain);
1171 /* List the hosts */
1172 for (j = 0;
1173 f->global_catalog[j].host[0] != '\0';
1174 j++) {
1175 idmapdlog(LOG_INFO,
1176 "change %s=%s host=%s port=%d",
1177 name, f->forest_name,
1178 f->global_catalog[j].host,
1179 f->global_catalog[j].port);
1183 return (1);
1186 const char *
1187 enum_lookup(int value, struct enum_lookup_map *map)
1189 for (; map->string != NULL; map++) {
1190 if (value == map->value) {
1191 return (map->string);
1194 return ("(invalid)");
1198 * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the
1199 * interfaces.
1201 * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON.
1203 static
1204 boolean_t
1205 pfroute_event_is_interesting(int rt_sock)
1207 int nbytes;
1208 int64_t msg[2048 / 8];
1209 struct rt_msghdr *rtm;
1210 boolean_t is_interesting = B_FALSE;
1212 for (;;) {
1213 if ((nbytes = read(rt_sock, msg, sizeof (msg))) <= 0)
1214 break;
1215 rtm = (struct rt_msghdr *)msg;
1216 if (rtm->rtm_version != RTM_VERSION)
1217 continue;
1218 if (nbytes < rtm->rtm_msglen)
1219 continue;
1220 switch (rtm->rtm_type) {
1221 case RTM_NEWADDR:
1222 case RTM_DELADDR:
1223 case RTM_IFINFO:
1224 is_interesting = B_TRUE;
1225 break;
1226 default:
1227 break;
1230 return (is_interesting);
1234 * Wait for an event, and report what kind of event occurred.
1236 * Note that there are cases where we are awoken but don't care about
1237 * the lower-level event. We can't just loop here because we can't
1238 * readily calculate how long to sleep the next time. We return
1239 * EVENT_NOTHING and let the caller loop.
1241 static
1242 enum event_type
1243 wait_for_event(struct timespec *timeoutp)
1245 port_event_t pe;
1247 (void) memset(&pe, 0, sizeof (pe));
1248 if (port_get(idmapd_ev_port, &pe, timeoutp) != 0) {
1249 switch (errno) {
1250 case EINTR:
1251 return (EVENT_NOTHING);
1252 case ETIME:
1253 /* Timeout */
1254 return (EVENT_TIMEOUT);
1255 default:
1256 /* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */
1257 idmapdlog(LOG_ERR, "Event port failed: %s",
1258 strerror(errno));
1259 exit(1);
1260 /* NOTREACHED */
1265 switch (pe.portev_source) {
1266 case 0:
1268 * This isn't documented, but seems to be what you get if
1269 * the timeout is zero seconds and there are no events
1270 * pending.
1272 return (EVENT_TIMEOUT);
1274 case PORT_SOURCE_USER:
1275 switch (pe.portev_events) {
1276 case RECONFIGURE:
1277 return (EVENT_REFRESH);
1278 case POKE_AUTO_DISCOVERY:
1279 return (EVENT_POKED);
1280 case KICK_AUTO_DISCOVERY:
1281 return (EVENT_KICKED);
1283 return (EVENT_NOTHING);
1285 case PORT_SOURCE_FD:
1286 if (pe.portev_object == rt_sock) {
1288 * PF_ROUTE socket read event:
1289 * re-associate fd
1290 * handle event
1292 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD,
1293 rt_sock, POLLIN, NULL) != 0) {
1294 idmapdlog(LOG_ERR, "Failed to re-associate the "
1295 "routing socket with the event port: %s",
1296 strerror(errno));
1297 abort();
1300 * The network configuration may still be in flux.
1301 * No matter, the resolver will re-transmit and
1302 * timeout if need be.
1304 if (pfroute_event_is_interesting(rt_sock)) {
1305 if (DBG(CONFIG, 1)) {
1306 idmapdlog(LOG_DEBUG,
1307 "Interesting routing event");
1309 return (EVENT_ROUTING);
1310 } else {
1311 if (DBG(CONFIG, 2)) {
1312 idmapdlog(LOG_DEBUG,
1313 "Boring routing event");
1315 return (EVENT_NOTHING);
1318 /* Event on an FD other than the routing FD? Ignore it. */
1319 break;
1322 return (EVENT_NOTHING);
1325 void *
1326 idmap_cfg_update_thread(void *arg)
1328 NOTE(ARGUNUSED(arg))
1329 idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg;
1330 const ad_disc_t ad_ctx = _idmapdstate.cfg->handles.ad_ctx;
1331 int flags = CFG_DISCOVER;
1333 for (;;) {
1334 struct timespec timeout;
1335 struct timespec *timeoutp;
1336 int rc;
1337 int ttl, max_ttl;
1339 (void) ad_disc_SubnetChanged(ad_ctx);
1341 rc = idmap_cfg_load(_idmapdstate.cfg, flags);
1342 if (rc < -1) {
1343 idmapdlog(LOG_ERR, "Fatal errors while reading "
1344 "SMF properties");
1345 exit(1);
1346 } else if (rc == -1) {
1347 idmapdlog(LOG_WARNING,
1348 "Errors re-loading configuration may cause AD "
1349 "lookups to fail");
1353 * Wait for an interesting event. Note that we might get
1354 * boring events between interesting events. If so, we loop.
1356 flags = CFG_DISCOVER;
1357 for (;;) {
1359 * If we don't know our domain name, don't bother
1360 * with rediscovery until the next config change.
1361 * Avoids hourly noise in workgroup mode.
1363 if (pgcfg->domain_name == NULL)
1364 ttl = -1;
1365 else
1366 ttl = ad_disc_get_TTL(ad_ctx);
1367 if (ttl < 0) {
1368 timeoutp = NULL;
1369 } else {
1370 max_ttl = (int)pgcfg->rediscovery_interval;
1371 if (ttl > max_ttl)
1372 ttl = max_ttl;
1373 if (ttl < MIN_REDISCOVERY_INTERVAL)
1374 ttl = MIN_REDISCOVERY_INTERVAL;
1375 timeout.tv_sec = ttl;
1376 timeout.tv_nsec = 0;
1377 timeoutp = &timeout;
1380 if (DBG(CONFIG, 1))
1381 idmapdlog(LOG_DEBUG,
1382 "_cfg_update_thread waiting");
1384 switch (wait_for_event(timeoutp)) {
1385 case EVENT_NOTHING:
1386 if (DBG(CONFIG, 2))
1387 idmapdlog(LOG_DEBUG, "Boring event.");
1388 continue;
1389 case EVENT_REFRESH:
1390 if (DBG(CONFIG, 1))
1391 idmapdlog(LOG_INFO, "SMF refresh");
1393 * Forget any DC we had previously.
1395 flags |= CFG_FORGET_DC;
1398 * Blow away the ccache, we might have
1399 * re-joined the domain or joined a new one
1401 (void) unlink(IDMAP_CACHEDIR "/ccache");
1402 break;
1403 case EVENT_POKED:
1404 if (DBG(CONFIG, 1))
1405 idmapdlog(LOG_DEBUG, "poked");
1406 break;
1407 case EVENT_KICKED:
1408 if (DBG(CONFIG, 1))
1409 idmapdlog(LOG_DEBUG, "kicked");
1410 flags |= CFG_FORGET_DC;
1411 break;
1412 case EVENT_TIMEOUT:
1413 if (DBG(CONFIG, 1))
1414 idmapdlog(LOG_DEBUG, "TTL expired");
1415 break;
1416 case EVENT_ROUTING:
1417 /* Already logged to DEBUG */
1418 break;
1420 /* An interesting event! */
1421 break;
1425 * Lint isn't happy with the concept of a function declared to
1426 * return something, that doesn't return. Of course, merely adding
1427 * the return isn't enough, because it's never reached...
1429 /*NOTREACHED*/
1430 return (NULL);
1434 idmap_cfg_start_updates(void)
1436 if ((idmapd_ev_port = port_create()) < 0) {
1437 idmapdlog(LOG_ERR, "Failed to create event port: %s",
1438 strerror(errno));
1439 return (-1);
1442 if ((rt_sock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
1443 idmapdlog(LOG_ERR, "Failed to open routing socket: %s",
1444 strerror(errno));
1445 (void) close(idmapd_ev_port);
1446 return (-1);
1449 if (fcntl(rt_sock, F_SETFL, O_NDELAY|O_NONBLOCK) < 0) {
1450 idmapdlog(LOG_ERR, "Failed to set routing socket flags: %s",
1451 strerror(errno));
1452 (void) close(rt_sock);
1453 (void) close(idmapd_ev_port);
1454 return (-1);
1457 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD,
1458 rt_sock, POLLIN, NULL) != 0) {
1459 idmapdlog(LOG_ERR, "Failed to associate the routing "
1460 "socket with the event port: %s", strerror(errno));
1461 (void) close(rt_sock);
1462 (void) close(idmapd_ev_port);
1463 return (-1);
1466 if ((errno = pthread_create(&update_thread_handle, NULL,
1467 idmap_cfg_update_thread, NULL)) != 0) {
1468 idmapdlog(LOG_ERR, "Failed to start update thread: %s",
1469 strerror(errno));
1470 (void) port_dissociate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock);
1471 (void) close(rt_sock);
1472 (void) close(idmapd_ev_port);
1473 return (-1);
1476 return (0);
1480 * Reject attribute names with invalid characters.
1482 static
1484 valid_ldap_attr(const char *attr) {
1485 for (; *attr; attr++) {
1486 if (!isalnum(*attr) && *attr != '-' &&
1487 *attr != '_' && *attr != '.' && *attr != ';')
1488 return (0);
1490 return (1);
1493 static
1494 void
1495 idmapd_set_debug(
1496 idmap_cfg_handles_t *handles,
1497 enum idmapd_debug item,
1498 const char *name)
1500 int val;
1502 if (item < 0 || item > IDMAPD_DEBUG_MAX)
1503 return;
1505 val = get_debug(handles, name);
1507 if (val != _idmapdstate.debug[item])
1508 idmapdlog(LOG_DEBUG, "%s/%s = %d", DEBUG_PG, name, val);
1510 _idmapdstate.debug[item] = val;
1513 static
1514 void
1515 check_smf_debug_mode(idmap_cfg_handles_t *handles)
1517 idmapd_set_debug(handles, IDMAPD_DEBUG_ALL, "all");
1518 idmapd_set_debug(handles, IDMAPD_DEBUG_CONFIG, "config");
1519 idmapd_set_debug(handles, IDMAPD_DEBUG_MAPPING, "mapping");
1520 idmapd_set_debug(handles, IDMAPD_DEBUG_DISC, "discovery");
1521 idmapd_set_debug(handles, IDMAPD_DEBUG_DNS, "dns");
1522 idmapd_set_debug(handles, IDMAPD_DEBUG_LDAP, "ldap");
1524 adutils_set_debug(AD_DEBUG_ALL, _idmapdstate.debug[IDMAPD_DEBUG_ALL]);
1525 adutils_set_debug(AD_DEBUG_DISC, _idmapdstate.debug[IDMAPD_DEBUG_DISC]);
1526 adutils_set_debug(AD_DEBUG_DNS, _idmapdstate.debug[IDMAPD_DEBUG_DNS]);
1527 adutils_set_debug(AD_DEBUG_LDAP, _idmapdstate.debug[IDMAPD_DEBUG_LDAP]);
1531 * This is the half of idmap_cfg_load() that loads property values from
1532 * SMF (using the config/ property group of the idmap FMRI).
1534 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
1535 * -3 -> hard smf config failures
1536 * reading from SMF.
1538 static int
1539 idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
1540 int * const errors)
1542 int rc;
1543 char *s;
1545 *errors = 0;
1547 if (scf_pg_update(handles->config_pg) < 0) {
1548 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
1549 scf_strerror(scf_error()));
1550 return (-2);
1553 if (scf_pg_update(handles->debug_pg) < 0) {
1554 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
1555 scf_strerror(scf_error()));
1556 return (-2);
1559 check_smf_debug_mode(handles);
1561 rc = get_val_bool(handles, "unresolvable_sid_mapping",
1562 &pgcfg->eph_map_unres_sids, B_TRUE);
1563 if (rc != 0)
1564 (*errors)++;
1566 rc = get_val_bool(handles, "use_ads",
1567 &pgcfg->use_ads, B_TRUE);
1568 if (rc != 0)
1569 (*errors)++;
1571 rc = get_val_bool(handles, "use_lsa",
1572 &pgcfg->use_lsa, B_TRUE);
1573 if (rc != 0)
1574 (*errors)++;
1576 rc = get_val_bool(handles, "disable_cross_forest_trusts",
1577 &pgcfg->disable_cross_forest_trusts, B_TRUE);
1578 if (rc != 0)
1579 (*errors)++;
1581 rc = get_val_astring(handles, "directory_based_mapping", &s);
1582 if (rc != 0)
1583 (*errors)++;
1584 else if (s == NULL || strcasecmp(s, "none") == 0)
1585 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
1586 else if (strcasecmp(s, "name") == 0)
1587 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NAME;
1588 else if (strcasecmp(s, "idmu") == 0)
1589 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_IDMU;
1590 else {
1591 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
1592 idmapdlog(LOG_ERR,
1593 "config/directory_based_mapping: invalid value \"%s\" ignored",
1595 (*errors)++;
1597 free(s);
1599 rc = get_val_int(handles, "list_size_limit",
1600 &pgcfg->list_size_limit, SCF_TYPE_COUNT);
1601 if (rc != 0)
1602 (*errors)++;
1604 rc = get_val_int(handles, "id_cache_timeout",
1605 &pgcfg->id_cache_timeout, SCF_TYPE_COUNT);
1606 if (rc != 0)
1607 (*errors)++;
1608 if (pgcfg->id_cache_timeout == 0)
1609 pgcfg->id_cache_timeout = ID_CACHE_TMO_DEFAULT;
1611 rc = get_val_int(handles, "name_cache_timeout",
1612 &pgcfg->name_cache_timeout, SCF_TYPE_COUNT);
1613 if (rc != 0)
1614 (*errors)++;
1615 if (pgcfg->name_cache_timeout == 0)
1616 pgcfg->name_cache_timeout = NAME_CACHE_TMO_DEFAULT;
1618 rc = get_val_int(handles, "rediscovery_interval",
1619 &pgcfg->rediscovery_interval, SCF_TYPE_COUNT);
1620 if (rc != 0)
1621 (*errors)++;
1622 if (pgcfg->rediscovery_interval == 0)
1623 pgcfg->rediscovery_interval = REDISCOVERY_INTERVAL_DEFAULT;
1625 rc = get_val_astring(handles, "domain_name",
1626 &pgcfg->domain_name);
1627 if (rc != 0)
1628 (*errors)++;
1629 else {
1630 if (pgcfg->domain_name != NULL &&
1631 pgcfg->domain_name[0] == '\0') {
1632 free(pgcfg->domain_name);
1633 pgcfg->domain_name = NULL;
1635 (void) ad_disc_set_DomainName(handles->ad_ctx,
1636 pgcfg->domain_name);
1637 pgcfg->domain_name_auto_disc = B_FALSE;
1640 rc = get_val_astring(handles, "default_domain",
1641 &pgcfg->default_domain);
1642 if (rc != 0) {
1644 * SCF failures fetching config/default_domain we treat
1645 * as fatal as they may leave ID mapping rules that
1646 * match unqualified winnames flapping in the wind.
1648 return (-2);
1651 if (pgcfg->default_domain == NULL && pgcfg->domain_name != NULL) {
1652 pgcfg->default_domain = strdup(pgcfg->domain_name);
1655 rc = get_val_astring(handles, "domain_guid", &s);
1656 if (rc != 0) {
1657 (*errors)++;
1658 } else if (s == NULL || s[0] == '\0') {
1659 /* OK, not set. */
1660 free(s);
1661 } else {
1662 uuid_t u;
1664 if (uuid_parse(s, u) != 0) {
1665 idmapdlog(LOG_ERR,
1666 "config/domain_guid: invalid value \"%s\" ignored", s);
1667 free(s);
1668 (*errors)++;
1669 } else {
1670 pgcfg->domain_guid = s;
1671 pgcfg->domain_guid_auto_disc = B_FALSE;
1672 (void) ad_disc_set_DomainGUID(handles->ad_ctx, u);
1676 rc = get_val_astring(handles, "machine_uuid", &pgcfg->machine_uuid);
1677 if (rc != 0)
1678 (*errors)++;
1679 if (pgcfg->machine_uuid == NULL) {
1680 /* If machine_uuid not configured, generate one */
1681 if (generate_machine_uuid(&pgcfg->machine_uuid) < 0)
1682 return (-2);
1683 rc = set_val_astring(handles, handles->config_pg,
1684 "machine_uuid", pgcfg->machine_uuid);
1685 if (rc != 0)
1686 (*errors)++;
1689 rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid);
1690 if (rc != 0)
1691 (*errors)++;
1692 if (pgcfg->machine_sid == NULL) {
1694 * If machine_sid not configured, generate one
1695 * from the machine UUID.
1697 if (generate_machine_sid(&pgcfg->machine_sid,
1698 pgcfg->machine_uuid) < 0)
1699 return (-2);
1700 rc = set_val_astring(handles, handles->config_pg,
1701 "machine_sid", pgcfg->machine_sid);
1702 if (rc != 0)
1703 (*errors)++;
1706 rc = get_val_ds(handles, "domain_controller", 389,
1707 &pgcfg->domain_controller);
1708 if (rc != 0)
1709 (*errors)++;
1710 else {
1711 (void) ad_disc_set_DomainController(handles->ad_ctx,
1712 pgcfg->domain_controller);
1713 pgcfg->domain_controller_auto_disc = B_FALSE;
1716 rc = get_val_ds(handles, "preferred_dc", 389,
1717 &pgcfg->preferred_dc);
1718 if (rc != 0)
1719 (*errors)++;
1720 else {
1721 (void) ad_disc_set_PreferredDC(handles->ad_ctx,
1722 pgcfg->preferred_dc);
1723 pgcfg->preferred_dc_auto_disc = B_FALSE;
1726 rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name);
1727 if (rc != 0)
1728 (*errors)++;
1729 else {
1730 (void) ad_disc_set_ForestName(handles->ad_ctx,
1731 pgcfg->forest_name);
1732 pgcfg->forest_name_auto_disc = B_FALSE;
1735 rc = get_val_astring(handles, "site_name", &pgcfg->site_name);
1736 if (rc != 0)
1737 (*errors)++;
1738 else
1739 (void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name);
1741 rc = get_val_ds(handles, "global_catalog", 3268,
1742 &pgcfg->global_catalog);
1743 if (rc != 0)
1744 (*errors)++;
1745 else {
1746 (void) ad_disc_set_GlobalCatalog(handles->ad_ctx,
1747 pgcfg->global_catalog);
1748 pgcfg->global_catalog_auto_disc = B_FALSE;
1751 /* Unless we're doing directory-based name mapping, we're done. */
1752 if (pgcfg->directory_based_mapping != DIRECTORY_MAPPING_NAME)
1753 return (0);
1755 rc = get_val_astring(handles, "ad_unixuser_attr",
1756 &pgcfg->ad_unixuser_attr);
1757 if (rc != 0)
1758 return (-2);
1759 if (pgcfg->ad_unixuser_attr != NULL &&
1760 !valid_ldap_attr(pgcfg->ad_unixuser_attr)) {
1761 idmapdlog(LOG_ERR, "config/ad_unixuser_attr=%s is not a "
1762 "valid LDAP attribute name", pgcfg->ad_unixuser_attr);
1763 return (-3);
1766 rc = get_val_astring(handles, "ad_unixgroup_attr",
1767 &pgcfg->ad_unixgroup_attr);
1768 if (rc != 0)
1769 return (-2);
1770 if (pgcfg->ad_unixgroup_attr != NULL &&
1771 !valid_ldap_attr(pgcfg->ad_unixgroup_attr)) {
1772 idmapdlog(LOG_ERR, "config/ad_unixgroup_attr=%s is not a "
1773 "valid LDAP attribute name", pgcfg->ad_unixgroup_attr);
1774 return (-3);
1777 rc = get_val_astring(handles, "nldap_winname_attr",
1778 &pgcfg->nldap_winname_attr);
1779 if (rc != 0)
1780 return (-2);
1781 if (pgcfg->nldap_winname_attr != NULL &&
1782 !valid_ldap_attr(pgcfg->nldap_winname_attr)) {
1783 idmapdlog(LOG_ERR, "config/nldap_winname_attr=%s is not a "
1784 "valid LDAP attribute name", pgcfg->nldap_winname_attr);
1785 return (-3);
1787 if (pgcfg->ad_unixuser_attr == NULL &&
1788 pgcfg->ad_unixgroup_attr == NULL &&
1789 pgcfg->nldap_winname_attr == NULL) {
1790 idmapdlog(LOG_ERR,
1791 "If config/directory_based_mapping property is set to "
1792 "\"name\" then at least one of the following name mapping "
1793 "attributes must be specified. (config/ad_unixuser_attr OR "
1794 "config/ad_unixgroup_attr OR config/nldap_winname_attr)");
1795 return (-3);
1798 return (rc);
1801 static
1802 void
1803 log_if_unable(const void *val, const char *what)
1805 if (val == NULL) {
1806 idmapdlog(LOG_DEBUG, "unable to discover %s", what);
1810 static
1811 void
1812 discover_trusted_domains(idmap_pg_config_t *pgcfg, ad_disc_t ad_ctx)
1814 ad_disc_t trusted_ctx;
1815 int i, j, k, l;
1816 char *forestname;
1817 int num_trusteddomains;
1818 boolean_t new_forest;
1819 char *trusteddomain;
1820 ad_disc_ds_t *globalcatalog;
1821 idmap_trustedforest_t *trustedforests;
1822 ad_disc_domainsinforest_t *domainsinforest;
1824 pgcfg->trusted_domains =
1825 ad_disc_get_TrustedDomains(ad_ctx, NULL);
1827 if (pgcfg->forest_name != NULL && pgcfg->trusted_domains != NULL &&
1828 pgcfg->trusted_domains[0].domain[0] != '\0') {
1830 * We have trusted domains. We need to go through every
1831 * one and find its forest. If it is a new forest we then need
1832 * to find its Global Catalog and the domains in the forest
1834 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++)
1835 continue;
1836 num_trusteddomains = i;
1838 trustedforests = calloc(num_trusteddomains,
1839 sizeof (idmap_trustedforest_t));
1840 j = 0;
1841 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++) {
1842 trusteddomain = pgcfg->trusted_domains[i].domain;
1843 trusted_ctx = ad_disc_init();
1844 (void) ad_disc_set_DomainName(trusted_ctx,
1845 trusteddomain);
1846 forestname =
1847 ad_disc_get_ForestName(trusted_ctx, NULL);
1848 if (forestname == NULL) {
1849 if (DBG(CONFIG, 1)) {
1850 idmapdlog(LOG_DEBUG,
1851 "unable to discover Forest Name"
1852 " for the trusted domain %s",
1853 trusteddomain);
1855 ad_disc_fini(trusted_ctx);
1856 continue;
1859 if (strcasecmp(forestname, pgcfg->forest_name) == 0) {
1861 * Ignore the domain as it is part of
1862 * the primary forest
1864 free(forestname);
1865 ad_disc_fini(trusted_ctx);
1866 continue;
1869 /* Is this a new forest? */
1870 new_forest = B_TRUE;
1871 for (k = 0; k < j; k++) {
1872 if (strcasecmp(forestname,
1873 trustedforests[k].forest_name) == 0) {
1874 new_forest = B_FALSE;
1875 domainsinforest =
1876 trustedforests[k].domains_in_forest;
1877 break;
1880 if (!new_forest) {
1881 /* Mark the domain as trusted */
1882 for (l = 0;
1883 domainsinforest[l].domain[0] != '\0'; l++) {
1884 if (domain_eq(trusteddomain,
1885 domainsinforest[l].domain)) {
1886 domainsinforest[l].trusted =
1887 TRUE;
1888 break;
1891 free(forestname);
1892 ad_disc_fini(trusted_ctx);
1893 continue;
1897 * Get the Global Catalog and the domains in
1898 * this new forest.
1900 globalcatalog =
1901 ad_disc_get_GlobalCatalog(trusted_ctx,
1902 AD_DISC_PREFER_SITE, NULL);
1903 if (globalcatalog == NULL) {
1904 if (DBG(CONFIG, 1)) {
1905 idmapdlog(LOG_DEBUG,
1906 "unable to discover Global Catalog"
1907 " for the trusted domain %s",
1908 trusteddomain);
1910 free(forestname);
1911 ad_disc_fini(trusted_ctx);
1912 continue;
1914 domainsinforest =
1915 ad_disc_get_DomainsInForest(trusted_ctx, NULL);
1916 if (domainsinforest == NULL) {
1917 if (DBG(CONFIG, 1)) {
1918 idmapdlog(LOG_DEBUG,
1919 "unable to discover Domains in the"
1920 " Forest for the trusted domain %s",
1921 trusteddomain);
1923 free(globalcatalog);
1924 free(forestname);
1925 ad_disc_fini(trusted_ctx);
1926 continue;
1929 trustedforests[j].forest_name = forestname;
1930 trustedforests[j].global_catalog = globalcatalog;
1931 trustedforests[j].domains_in_forest = domainsinforest;
1932 j++;
1933 /* Mark the domain as trusted */
1934 for (l = 0; domainsinforest[l].domain[0] != '\0';
1935 l++) {
1936 if (domain_eq(trusteddomain,
1937 domainsinforest[l].domain)) {
1938 domainsinforest[l].trusted = TRUE;
1939 break;
1942 ad_disc_fini(trusted_ctx);
1944 if (j > 0) {
1945 pgcfg->num_trusted_forests = j;
1946 pgcfg->trusted_forests = trustedforests;
1947 } else {
1948 free(trustedforests);
1954 * This is the half of idmap_cfg_load() that auto-discovers values of
1955 * discoverable properties that weren't already set via SMF properties.
1957 * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it
1958 * needs to be careful not to overwrite any properties set in SMF.
1960 static void
1961 idmap_cfg_discover1(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg)
1963 ad_disc_t ad_ctx = handles->ad_ctx;
1964 FILE *status_fp = NULL;
1965 time_t t0, t1;
1967 t0 = time(NULL);
1968 if (DBG(CONFIG, 1))
1969 idmapdlog(LOG_DEBUG, "Running domain discovery.");
1971 (void) unlink(IDMAP_CACHEDIR "/discovery.log");
1972 status_fp = fopen(IDMAP_CACHEDIR "/discovery.log", "w");
1973 if (status_fp) {
1974 (void) fchmod(fileno(status_fp), 0644);
1975 ad_disc_set_StatusFP(ad_ctx, status_fp);
1978 if (pgcfg->domain_name == NULL) {
1979 idmapdlog(LOG_DEBUG, "No domain name specified.");
1980 if (status_fp)
1981 (void) fprintf(status_fp, "(no domain name)\n");
1982 goto out;
1985 if (pgcfg->domain_controller == NULL)
1986 pgcfg->domain_controller =
1987 ad_disc_get_DomainController(ad_ctx,
1988 AD_DISC_PREFER_SITE,
1989 &pgcfg->domain_controller_auto_disc);
1991 if (pgcfg->domain_guid == NULL) {
1992 char buf[UUID_PRINTABLE_STRING_LENGTH];
1993 uchar_t *u = ad_disc_get_DomainGUID(ad_ctx,
1994 &pgcfg->domain_guid_auto_disc);
1995 (void) memset(buf, 0, sizeof (buf));
1996 if (u != NULL) {
1997 uuid_unparse(u, buf);
1998 pgcfg->domain_guid = strdup(buf);
2002 if (pgcfg->forest_name == NULL)
2003 pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx,
2004 &pgcfg->forest_name_auto_disc);
2006 if (pgcfg->site_name == NULL)
2007 pgcfg->site_name = ad_disc_get_SiteName(ad_ctx,
2008 &pgcfg->site_name_auto_disc);
2010 if (DBG(CONFIG, 1)) {
2011 log_if_unable(pgcfg->domain_name, "Domain Name");
2012 log_if_unable(pgcfg->domain_controller,
2013 "Domain Controller");
2014 log_if_unable(pgcfg->domain_guid, "Domain GUID");
2015 log_if_unable(pgcfg->forest_name, "Forest Name");
2016 log_if_unable(pgcfg->site_name, "Site Name");
2019 out:
2020 if (status_fp) {
2021 ad_disc_set_StatusFP(ad_ctx, NULL);
2022 (void) fclose(status_fp);
2023 status_fp = NULL;
2026 if (DBG(CONFIG, 1))
2027 idmapdlog(LOG_DEBUG, "Domain discovery done.");
2030 * Log when this took more than 15 sec.
2032 t1 = time(NULL);
2033 if (t1 > (t0 + 15)) {
2034 idmapdlog(LOG_NOTICE, "Domain discovery took %d sec.",
2035 (int)(t1 - t0));
2036 idmapdlog(LOG_NOTICE, "Check the DNS configuration.");
2041 * This is the second part of discovery, which can take a while.
2042 * We don't want to hold up parties who just want to know what
2043 * domain controller we're using (like smbd), so this part runs
2044 * after we've updated that info in the "live" config and told
2045 * such consumers to go ahead.
2047 * This is a lot like idmap_cfg_discover(), but used LDAP queries
2048 * get the forest information from the global catalog servers.
2050 * Note: the previous update_* calls have usually nuked any
2051 * useful information from pgcfg before we get here, so we
2052 * can only use it store discovery results, not to read.
2054 static void
2055 idmap_cfg_discover2(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg)
2057 ad_disc_t ad_ctx = handles->ad_ctx;
2058 FILE *status_fp = NULL;
2059 time_t t0, t1;
2061 t0 = time(NULL);
2062 if (DBG(CONFIG, 1))
2063 idmapdlog(LOG_DEBUG, "Running forest discovery.");
2065 status_fp = fopen(IDMAP_CACHEDIR "/discovery.log", "a");
2066 if (status_fp)
2067 ad_disc_set_StatusFP(ad_ctx, status_fp);
2069 if (pgcfg->global_catalog == NULL)
2070 pgcfg->global_catalog =
2071 ad_disc_get_GlobalCatalog(ad_ctx,
2072 AD_DISC_PREFER_SITE,
2073 &pgcfg->global_catalog_auto_disc);
2075 if (pgcfg->global_catalog != NULL) {
2076 pgcfg->domains_in_forest =
2077 ad_disc_get_DomainsInForest(ad_ctx, NULL);
2079 if (!pgcfg->disable_cross_forest_trusts)
2080 discover_trusted_domains(pgcfg, ad_ctx);
2083 if (DBG(CONFIG, 1)) {
2084 log_if_unable(pgcfg->global_catalog, "Global Catalog");
2085 log_if_unable(pgcfg->domains_in_forest,
2086 "Domains in the Forest");
2087 /* Empty trusted domains list is OK. */
2090 if (status_fp) {
2091 ad_disc_set_StatusFP(ad_ctx, NULL);
2092 (void) fclose(status_fp);
2093 status_fp = NULL;
2096 if (DBG(CONFIG, 1))
2097 idmapdlog(LOG_DEBUG, "Forest discovery done.");
2100 * Log when this took more than 30 sec.
2102 t1 = time(NULL);
2103 if (t1 > (t0 + 30)) {
2104 idmapdlog(LOG_NOTICE, "Forest discovery took %d sec.",
2105 (int)(t1 - t0));
2106 idmapdlog(LOG_NOTICE, "Check AD join status.");
2112 * idmap_cfg_load() is called at startup, and periodically via the
2113 * update thread when the auto-discovery TTLs expire, as well as part of
2114 * the refresh method, to update the current configuration. It always
2115 * reads from SMF, but you still have to refresh the service after
2116 * changing the config pg in order for the changes to take effect.
2118 * There is one flag:
2120 * - CFG_DISCOVER
2122 * If CFG_DISCOVER is set then idmap_cfg_load() calls
2123 * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property
2124 * values that weren't set in SMF.
2126 * idmap_cfg_load() will log (to LOG_NOTICE) whether the configuration
2127 * changed.
2129 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
2130 * reading from SMF.
2133 idmap_cfg_load(idmap_cfg_t *cfg, int flags)
2135 const ad_disc_t ad_ctx = cfg->handles.ad_ctx;
2136 int rc = 0;
2137 int errors;
2138 int changed = 0;
2139 int dc_changed = 0;
2140 int ad_reload_required = 0;
2141 idmap_pg_config_t new_pgcfg, *live_pgcfg;
2143 if (DBG(CONFIG, 1))
2144 idmapdlog(LOG_DEBUG, "Loading configuration.");
2146 live_pgcfg = &cfg->pgcfg;
2147 (void) memset(&new_pgcfg, 0, sizeof (new_pgcfg));
2149 (void) pthread_mutex_lock(&cfg->handles.mutex);
2151 if ((rc = idmap_cfg_load_smf(&cfg->handles, &new_pgcfg, &errors)) < -1)
2152 goto err;
2154 if (flags & CFG_DISCOVER) {
2156 ad_disc_refresh(ad_ctx);
2159 * Unless we've been asked to forget the current DC,
2160 * give preference (in order) to the preferred DC if
2161 * configured, or the current DC. These preferences
2162 * reduce undesirable DC changes.
2164 if (flags & CFG_FORGET_DC) {
2165 (void) ad_disc_set_PreferredDC(ad_ctx, NULL);
2166 } else if (new_pgcfg.preferred_dc != NULL) {
2167 (void) ad_disc_set_PreferredDC(ad_ctx,
2168 new_pgcfg.preferred_dc);
2169 } else if (live_pgcfg->domain_controller != NULL) {
2170 (void) ad_disc_set_PreferredDC(ad_ctx,
2171 live_pgcfg->domain_controller);
2172 } else {
2173 (void) ad_disc_set_PreferredDC(ad_ctx, NULL);
2177 * We want a way to tell adspriv_getdcname_1_svc()
2178 * (and others) that discovery is running and therefore
2179 * they may want to wait a bit or return an error...
2181 (void) mutex_lock(&_idmapdstate.addisc_lk);
2182 _idmapdstate.addisc_st |= ADDISC_ST_RUNNING;
2183 (void) mutex_unlock(&_idmapdstate.addisc_lk);
2185 idmap_cfg_discover1(&cfg->handles, &new_pgcfg);
2187 WRLOCK_CONFIG();
2188 (void) mutex_lock(&_idmapdstate.addisc_lk);
2189 _idmapdstate.addisc_st = 0;
2190 (void) cond_broadcast(&_idmapdstate.addisc_cv);
2191 (void) mutex_unlock(&_idmapdstate.addisc_lk);
2192 } else {
2193 WRLOCK_CONFIG();
2196 /* Non-discoverable props updated here */
2198 changed += update_uint64(&live_pgcfg->list_size_limit,
2199 &new_pgcfg.list_size_limit, "list_size_limit");
2201 changed += update_uint64(&live_pgcfg->id_cache_timeout,
2202 &new_pgcfg.id_cache_timeout, "id_cache_timeout");
2204 changed += update_uint64(&live_pgcfg->name_cache_timeout,
2205 &new_pgcfg.name_cache_timeout, "name_cache_timeout");
2207 changed += update_uint64(&live_pgcfg->rediscovery_interval,
2208 &new_pgcfg.rediscovery_interval, "rediscovery_interval");
2210 changed += update_string(&live_pgcfg->machine_sid,
2211 &new_pgcfg.machine_sid, "machine_sid");
2213 changed += update_bool(&live_pgcfg->eph_map_unres_sids,
2214 &new_pgcfg.eph_map_unres_sids, "unresolvable_sid_mapping");
2216 changed += update_bool(&live_pgcfg->use_ads,
2217 &new_pgcfg.use_ads, "use_ads");
2219 changed += update_bool(&live_pgcfg->use_lsa,
2220 &new_pgcfg.use_lsa, "use_lsa");
2222 changed += update_bool(&live_pgcfg->disable_cross_forest_trusts,
2223 &new_pgcfg.disable_cross_forest_trusts,
2224 "disable_cross_forest_trusts");
2226 changed += update_enum(&live_pgcfg->directory_based_mapping,
2227 &new_pgcfg.directory_based_mapping, "directory_based_mapping",
2228 directory_mapping_map);
2230 changed += update_string(&live_pgcfg->ad_unixuser_attr,
2231 &new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr");
2233 changed += update_string(&live_pgcfg->ad_unixgroup_attr,
2234 &new_pgcfg.ad_unixgroup_attr, "ad_unixgroup_attr");
2236 changed += update_string(&live_pgcfg->nldap_winname_attr,
2237 &new_pgcfg.nldap_winname_attr, "nldap_winname_attr");
2239 changed += update_string(&live_pgcfg->default_domain,
2240 &new_pgcfg.default_domain, "default_domain");
2242 changed += update_dirs(&live_pgcfg->preferred_dc,
2243 &new_pgcfg.preferred_dc, "preferred_dc");
2245 /* Props that can be discovered or set in SMF updated here */
2247 if (update_string(&live_pgcfg->domain_name,
2248 &new_pgcfg.domain_name, "domain_name")) {
2249 changed++;
2250 ad_reload_required = TRUE;
2251 idmapd_set_krb5_realm(live_pgcfg->domain_name);
2253 live_pgcfg->domain_name_auto_disc = new_pgcfg.domain_name_auto_disc;
2255 changed += update_string(&live_pgcfg->domain_guid,
2256 &new_pgcfg.domain_guid, "domain_guid");
2257 live_pgcfg->domain_guid_auto_disc = new_pgcfg.domain_guid_auto_disc;
2259 dc_changed = update_dirs(&live_pgcfg->domain_controller,
2260 &new_pgcfg.domain_controller, "domain_controller");
2261 changed += dc_changed;
2262 live_pgcfg->domain_controller_auto_disc =
2263 new_pgcfg.domain_controller_auto_disc;
2265 changed += update_string(&live_pgcfg->forest_name,
2266 &new_pgcfg.forest_name, "forest_name");
2267 live_pgcfg->forest_name_auto_disc = new_pgcfg.forest_name_auto_disc;
2269 changed += update_string(&live_pgcfg->site_name,
2270 &new_pgcfg.site_name, "site_name");
2271 live_pgcfg->site_name_auto_disc = new_pgcfg.site_name_auto_disc;
2273 if (DBG(CONFIG, 1)) {
2274 if (changed)
2275 idmapdlog(LOG_NOTICE, "Configuration changed");
2276 else
2277 idmapdlog(LOG_NOTICE, "Configuration unchanged");
2280 UNLOCK_CONFIG();
2282 if (dc_changed != 0) {
2283 notify_dc_changed();
2287 * Discovery2 can take a while.
2289 if (flags & CFG_DISCOVER) {
2290 if (live_pgcfg->domain_name != NULL &&
2291 live_pgcfg->forest_name != NULL)
2292 idmap_cfg_discover2(&cfg->handles, &new_pgcfg);
2293 ad_disc_done(ad_ctx);
2296 WRLOCK_CONFIG();
2298 /* More props that can be discovered or set in SMF */
2300 changed += update_dirs(&live_pgcfg->global_catalog,
2301 &new_pgcfg.global_catalog, "global_catalog");
2302 live_pgcfg->global_catalog_auto_disc =
2303 new_pgcfg.global_catalog_auto_disc;
2305 /* Props that are only discovered (never in SMF) */
2307 if (update_domains_in_forest(&live_pgcfg->domains_in_forest,
2308 &new_pgcfg.domains_in_forest, "domains_in_forest")) {
2309 changed++;
2310 ad_reload_required = TRUE;
2313 if (update_trusted_domains(&live_pgcfg->trusted_domains,
2314 &new_pgcfg.trusted_domains, "trusted_domains")) {
2315 changed++;
2316 if (live_pgcfg->trusted_domains != NULL &&
2317 live_pgcfg->trusted_domains[0].domain[0] != '\0')
2318 ad_reload_required = TRUE;
2321 if (update_trusted_forest(&live_pgcfg->trusted_forests,
2322 &live_pgcfg->num_trusted_forests, &new_pgcfg.trusted_forests,
2323 &new_pgcfg.num_trusted_forests, "trusted_forest")) {
2324 changed++;
2325 if (live_pgcfg->trusted_forests != NULL)
2326 ad_reload_required = TRUE;
2329 if (DBG(CONFIG, 1)) {
2330 if (changed)
2331 idmapdlog(LOG_NOTICE, "Configuration changed");
2332 else
2333 idmapdlog(LOG_NOTICE, "Configuration unchanged");
2336 UNLOCK_CONFIG();
2338 if (ad_reload_required)
2339 reload_ad();
2341 idmap_cfg_unload(&new_pgcfg);
2343 err:
2344 (void) pthread_mutex_unlock(&cfg->handles.mutex);
2346 if (rc < -1)
2347 return (rc);
2349 return ((errors == 0) ? 0 : -1);
2353 * Initialize 'cfg'.
2355 idmap_cfg_t *
2356 idmap_cfg_init()
2358 idmap_cfg_handles_t *handles;
2360 /* First the smf repository handles: */
2361 idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t));
2362 if (!cfg) {
2363 idmapdlog(LOG_ERR, "Out of memory");
2364 return (NULL);
2366 handles = &cfg->handles;
2368 (void) pthread_mutex_init(&handles->mutex, NULL);
2370 if (!(handles->main = scf_handle_create(SCF_VERSION))) {
2371 idmapdlog(LOG_ERR, "scf_handle_create() failed: %s",
2372 scf_strerror(scf_error()));
2373 goto error;
2376 if (scf_handle_bind(handles->main) < 0) {
2377 idmapdlog(LOG_ERR, "scf_handle_bind() failed: %s",
2378 scf_strerror(scf_error()));
2379 goto error;
2382 if (!(handles->service = scf_service_create(handles->main)) ||
2383 !(handles->instance = scf_instance_create(handles->main)) ||
2384 !(handles->config_pg = scf_pg_create(handles->main)) ||
2385 !(handles->debug_pg = scf_pg_create(handles->main))) {
2386 idmapdlog(LOG_ERR, "scf handle creation failed: %s",
2387 scf_strerror(scf_error()));
2388 goto error;
2391 if (scf_handle_decode_fmri(handles->main,
2392 FMRI_BASE "/:properties/" CONFIG_PG,
2393 NULL, /* scope */
2394 handles->service, /* service */
2395 handles->instance, /* instance */
2396 handles->config_pg, /* pg */
2397 NULL, /* prop */
2398 SCF_DECODE_FMRI_EXACT) < 0) {
2399 idmapdlog(LOG_ERR, "scf_handle_decode_fmri() failed: %s",
2400 scf_strerror(scf_error()));
2401 goto error;
2404 if (scf_service_get_pg(handles->service,
2405 DEBUG_PG, handles->debug_pg) < 0) {
2406 idmapdlog(LOG_ERR, "Property group \"%s\": %s",
2407 DEBUG_PG, scf_strerror(scf_error()));
2408 goto error;
2411 check_smf_debug_mode(handles);
2413 /* Initialize AD Auto Discovery context */
2414 handles->ad_ctx = ad_disc_init();
2415 if (handles->ad_ctx == NULL)
2416 goto error;
2418 return (cfg);
2420 error:
2421 (void) idmap_cfg_fini(cfg);
2422 return (NULL);
2425 void
2426 idmap_cfg_unload(idmap_pg_config_t *pgcfg)
2429 if (pgcfg->default_domain) {
2430 free(pgcfg->default_domain);
2431 pgcfg->default_domain = NULL;
2433 if (pgcfg->domain_name) {
2434 free(pgcfg->domain_name);
2435 pgcfg->domain_name = NULL;
2437 if (pgcfg->domain_guid) {
2438 free(pgcfg->domain_guid);
2439 pgcfg->domain_guid = NULL;
2441 if (pgcfg->machine_sid) {
2442 free(pgcfg->machine_sid);
2443 pgcfg->machine_sid = NULL;
2445 if (pgcfg->domain_controller) {
2446 free(pgcfg->domain_controller);
2447 pgcfg->domain_controller = NULL;
2449 if (pgcfg->forest_name) {
2450 free(pgcfg->forest_name);
2451 pgcfg->forest_name = NULL;
2453 if (pgcfg->site_name) {
2454 free(pgcfg->site_name);
2455 pgcfg->site_name = NULL;
2457 if (pgcfg->global_catalog) {
2458 free(pgcfg->global_catalog);
2459 pgcfg->global_catalog = NULL;
2461 if (pgcfg->trusted_domains) {
2462 free(pgcfg->trusted_domains);
2463 pgcfg->trusted_domains = NULL;
2465 if (pgcfg->trusted_forests)
2466 free_trusted_forests(&pgcfg->trusted_forests,
2467 &pgcfg->num_trusted_forests);
2469 if (pgcfg->ad_unixuser_attr) {
2470 free(pgcfg->ad_unixuser_attr);
2471 pgcfg->ad_unixuser_attr = NULL;
2473 if (pgcfg->ad_unixgroup_attr) {
2474 free(pgcfg->ad_unixgroup_attr);
2475 pgcfg->ad_unixgroup_attr = NULL;
2477 if (pgcfg->nldap_winname_attr) {
2478 free(pgcfg->nldap_winname_attr);
2479 pgcfg->nldap_winname_attr = NULL;
2484 idmap_cfg_fini(idmap_cfg_t *cfg)
2486 idmap_cfg_handles_t *handles = &cfg->handles;
2487 idmap_cfg_unload(&cfg->pgcfg);
2489 (void) pthread_mutex_destroy(&handles->mutex);
2490 scf_pg_destroy(handles->config_pg);
2491 if (handles->debug_pg != NULL)
2492 scf_pg_destroy(handles->debug_pg);
2493 scf_instance_destroy(handles->instance);
2494 scf_service_destroy(handles->service);
2495 scf_handle_destroy(handles->main);
2496 if (handles->ad_ctx != NULL)
2497 ad_disc_fini(handles->ad_ctx);
2498 free(cfg);
2500 return (0);
2503 void
2504 idmap_cfg_poke_updates(void)
2506 int prev_st;
2508 if (DBG(CONFIG, 1)) {
2509 idmapdlog(LOG_INFO, "idmap_cfg_poke_updates");
2512 (void) mutex_lock(&_idmapdstate.addisc_lk);
2513 prev_st = _idmapdstate.addisc_st;
2514 _idmapdstate.addisc_st |= ADDISC_ST_REQUESTED;
2515 (void) mutex_unlock(&_idmapdstate.addisc_lk);
2517 if (prev_st & ADDISC_ST_REQUESTED) {
2518 idmapdlog(LOG_DEBUG, "already poked");
2519 } else {
2520 idmapdlog(LOG_DEBUG, "port send poke");
2521 (void) port_send(idmapd_ev_port, POKE_AUTO_DISCOVERY, NULL);
2525 void
2526 idmap_cfg_force_rediscovery(void)
2528 int prev_st;
2530 if (DBG(CONFIG, 1)) {
2531 idmapdlog(LOG_INFO, "idmap_cfg_force_rediscovery");
2534 (void) mutex_lock(&_idmapdstate.addisc_lk);
2535 prev_st = _idmapdstate.addisc_st;
2536 _idmapdstate.addisc_st |= ADDISC_ST_REQUESTED;
2537 (void) mutex_unlock(&_idmapdstate.addisc_lk);
2539 if (prev_st & ADDISC_ST_REQUESTED) {
2540 idmapdlog(LOG_DEBUG, "already kicked");
2541 } else {
2542 idmapdlog(LOG_DEBUG, "port send kick");
2543 (void) port_send(idmapd_ev_port, KICK_AUTO_DISCOVERY, NULL);
2547 /*ARGSUSED*/
2548 void
2549 idmap_cfg_hup_handler(int sig)
2551 if (idmapd_ev_port >= 0)
2552 (void) port_send(idmapd_ev_port, RECONFIGURE, NULL);
2556 * Upgrade the debug flags.
2558 * We're replacing a single debug flag with a fine-grained mechanism that
2559 * is also capable of considerably more verbosity. We'll take a stab at
2560 * producing roughly the same level of output.
2562 static
2564 upgrade_debug(idmap_cfg_handles_t *handles)
2566 boolean_t debug_present;
2567 const char DEBUG_PROP[] = "debug";
2568 int rc;
2570 rc = prop_exists(handles, DEBUG_PROP, &debug_present);
2572 if (rc != 0)
2573 return (rc);
2575 if (!debug_present)
2576 return (0);
2578 idmapdlog(LOG_INFO,
2579 "Upgrading old %s/%s setting to %s/* settings.",
2580 CONFIG_PG, DEBUG_PROP, DEBUG_PG);
2582 rc = set_val_integer(handles, handles->debug_pg, "config", 1);
2583 if (rc != 0)
2584 return (rc);
2585 rc = set_val_integer(handles, handles->debug_pg, "discovery", 1);
2586 if (rc != 0)
2587 return (rc);
2589 rc = del_val(handles, handles->config_pg, DEBUG_PROP);
2590 if (rc != 0)
2591 return (rc);
2593 return (0);
2597 * Upgrade the DS mapping flags.
2599 * If the old ds_name_mapping_enabled flag is present, then
2600 * if the new directory_based_mapping value is present, then
2601 * if the two are compatible, delete the old and note it
2602 * else delete the old and warn
2603 * else
2604 * set the new based on the old, and note it
2605 * delete the old
2607 static
2609 upgrade_directory_mapping(idmap_cfg_handles_t *handles)
2611 boolean_t legacy_ds_name_mapping_present;
2612 const char DS_NAME_MAPPING_ENABLED[] = "ds_name_mapping_enabled";
2613 const char DIRECTORY_BASED_MAPPING[] = "directory_based_mapping";
2614 int rc;
2616 rc = prop_exists(handles, DS_NAME_MAPPING_ENABLED,
2617 &legacy_ds_name_mapping_present);
2619 if (rc != 0)
2620 return (rc);
2622 if (!legacy_ds_name_mapping_present)
2623 return (0);
2625 boolean_t legacy_ds_name_mapping_enabled;
2626 rc = get_val_bool(handles, DS_NAME_MAPPING_ENABLED,
2627 &legacy_ds_name_mapping_enabled, B_FALSE);
2628 if (rc != 0)
2629 return (rc);
2631 char *legacy_mode;
2632 char *legacy_bool_string;
2633 if (legacy_ds_name_mapping_enabled) {
2634 legacy_mode = "name";
2635 legacy_bool_string = "true";
2636 } else {
2637 legacy_mode = "none";
2638 legacy_bool_string = "false";
2641 char *directory_based_mapping;
2642 rc = get_val_astring(handles, DIRECTORY_BASED_MAPPING,
2643 &directory_based_mapping);
2644 if (rc != 0)
2645 return (rc);
2647 if (directory_based_mapping == NULL) {
2648 idmapdlog(LOG_INFO,
2649 "Upgrading old %s=%s setting\n"
2650 "to %s=%s.",
2651 DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2652 DIRECTORY_BASED_MAPPING, legacy_mode);
2653 rc = set_val_astring(handles, handles->config_pg,
2654 DIRECTORY_BASED_MAPPING, legacy_mode);
2655 if (rc != 0)
2656 return (rc);
2657 } else {
2658 boolean_t new_name_mapping;
2659 if (strcasecmp(directory_based_mapping, "name") == 0)
2660 new_name_mapping = B_TRUE;
2661 else
2662 new_name_mapping = B_FALSE;
2664 if (legacy_ds_name_mapping_enabled == new_name_mapping) {
2665 idmapdlog(LOG_INFO,
2666 "Automatically removing old %s=%s setting\n"
2667 "in favor of %s=%s.",
2668 DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2669 DIRECTORY_BASED_MAPPING, directory_based_mapping);
2670 } else {
2671 idmapdlog(LOG_WARNING,
2672 "Removing conflicting %s=%s setting\n"
2673 "in favor of %s=%s.",
2674 DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2675 DIRECTORY_BASED_MAPPING, directory_based_mapping);
2677 free(directory_based_mapping);
2680 rc = del_val(handles, handles->config_pg, DS_NAME_MAPPING_ENABLED);
2681 if (rc != 0)
2682 return (rc);
2684 return (0);
2688 * Do whatever is necessary to upgrade idmap's configuration before
2689 * we load it.
2692 idmap_cfg_upgrade(idmap_cfg_t *cfg)
2694 int rc;
2696 rc = upgrade_directory_mapping(&cfg->handles);
2697 if (rc != 0)
2698 return (rc);
2700 rc = upgrade_debug(&cfg->handles);
2701 if (rc != 0)
2702 return (rc);
2704 return (0);
2708 * The LDAP code passes principal names lacking any
2709 * realm information, which causes mech_krb5 to do
2710 * awful things trying to figure out the realm.
2711 * Avoid that by making sure it has a default,
2712 * even when krb5.conf is not configured.
2714 static void
2715 idmapd_set_krb5_realm(char *domain)
2717 static char realm[MAXHOSTNAMELEN];
2718 size_t ilen, olen;
2719 int err;
2721 if (domain == NULL) {
2722 (void) unsetenv("KRB5_DEFAULT_REALM");
2723 return;
2726 /* Convert to upper case, in place. */
2727 (void) strlcpy(realm, domain, sizeof (realm));
2728 olen = ilen = strlen(realm);
2729 (void) u8_textprep_str(realm, &ilen, realm, &olen,
2730 U8_TEXTPREP_TOUPPER, U8_UNICODE_LATEST, &err);
2732 (void) setenv("KRB5_DEFAULT_REALM", realm, 1);