dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / idmap / idmapd / idmap_config.c
blob30ac75ceff831533257ebd413edb84874a34fcb4
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 free(*val);
586 *val = NULL;
589 return (rc);
593 static int
594 del_val(
595 idmap_cfg_handles_t *handles,
596 scf_propertygroup_t *pg,
597 const char *name)
599 int rc = -1;
600 int ret;
601 scf_transaction_t *tx = NULL;
602 scf_transaction_entry_t *ent = NULL;
604 if ((tx = scf_transaction_create(handles->main)) == NULL) {
605 idmapdlog(LOG_ERR,
606 "scf_transaction_create() failed: %s",
607 scf_strerror(scf_error()));
608 goto destruction;
610 if ((ent = scf_entry_create(handles->main)) == NULL) {
611 idmapdlog(LOG_ERR,
612 "scf_entry_create() failed: %s",
613 scf_strerror(scf_error()));
614 goto destruction;
617 do {
618 if (scf_pg_update(pg) == -1) {
619 idmapdlog(LOG_ERR,
620 "scf_pg_update(%s) failed: %s",
621 name, scf_strerror(scf_error()));
622 goto destruction;
624 if (scf_transaction_start(tx, pg) != 0) {
625 idmapdlog(LOG_ERR,
626 "scf_transaction_start(%s) failed: %s",
627 name, scf_strerror(scf_error()));
628 goto destruction;
631 if (scf_transaction_property_delete(tx, ent, name) != 0) {
632 /* Don't complain if it already doesn't exist. */
633 if (scf_error() != SCF_ERROR_NOT_FOUND) {
634 idmapdlog(LOG_ERR,
635 "scf_transaction_property_delete() failed:"
636 " %s",
637 scf_strerror(scf_error()));
639 goto destruction;
642 ret = scf_transaction_commit(tx);
644 if (ret == 0)
645 scf_transaction_reset(tx);
646 } while (ret == 0);
648 if (ret == -1) {
649 idmapdlog(LOG_ERR,
650 "scf_transaction_commit(%s) failed: %s",
651 name, scf_strerror(scf_error()));
652 goto destruction;
655 rc = 0;
657 destruction:
658 if (ent != NULL)
659 scf_entry_destroy(ent);
660 if (tx != NULL)
661 scf_transaction_destroy(tx);
662 return (rc);
666 static int
667 set_val(
668 idmap_cfg_handles_t *handles,
669 scf_propertygroup_t *pg,
670 const char *name,
671 scf_value_t *value)
673 int rc = -1;
674 int i;
675 scf_property_t *prop = NULL;
676 scf_transaction_t *tx = NULL;
677 scf_transaction_entry_t *ent = NULL;
679 if ((prop = scf_property_create(handles->main)) == NULL ||
680 (tx = scf_transaction_create(handles->main)) == NULL ||
681 (ent = scf_entry_create(handles->main)) == NULL) {
682 idmapdlog(LOG_ERR, "Unable to set property %s",
683 name, scf_strerror(scf_error()));
684 goto destruction;
687 for (i = 0; i < MAX_TRIES; i++) {
688 int ret;
690 if (scf_pg_update(pg) == -1) {
691 idmapdlog(LOG_ERR,
692 "scf_pg_update() failed: %s",
693 scf_strerror(scf_error()));
694 goto destruction;
697 if (scf_transaction_start(tx, pg) == -1) {
698 idmapdlog(LOG_ERR,
699 "scf_transaction_start(%s) failed: %s",
700 name, scf_strerror(scf_error()));
701 goto destruction;
704 ret = scf_pg_get_property(pg, name, prop);
705 if (ret == SCF_SUCCESS) {
706 if (scf_transaction_property_change_type(tx, ent, name,
707 scf_value_type(value)) < 0) {
708 idmapdlog(LOG_ERR,
709 "scf_transaction_property_change_type(%s)"
710 " failed: %s",
711 name, scf_strerror(scf_error()));
712 goto destruction;
714 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
715 if (scf_transaction_property_new(tx, ent, name,
716 scf_value_type(value)) < 0) {
717 idmapdlog(LOG_ERR,
718 "scf_transaction_property_new() failed: %s",
719 scf_strerror(scf_error()));
720 goto destruction;
722 } else {
723 idmapdlog(LOG_ERR,
724 "scf_pg_get_property(%s) failed: %s",
725 name, scf_strerror(scf_error()));
726 goto destruction;
729 if (scf_entry_add_value(ent, value) == -1) {
730 idmapdlog(LOG_ERR,
731 "scf_entry_add_value() failed: %s",
732 scf_strerror(scf_error()));
733 goto destruction;
736 ret = scf_transaction_commit(tx);
737 if (ret == 0) {
739 * Property group set in scf_transaction_start()
740 * is not the most recent. Update pg, reset tx and
741 * retry tx.
743 idmapdlog(LOG_WARNING,
744 "scf_transaction_commit(%s) failed: %s",
745 name, scf_strerror(scf_error()));
746 scf_transaction_reset(tx);
747 continue;
749 if (ret != 1) {
750 idmapdlog(LOG_ERR,
751 "scf_transaction_commit(%s) failed: %s",
752 name, scf_strerror(scf_error()));
753 goto destruction;
755 /* Success! */
756 rc = 0;
757 break;
760 destruction:
761 scf_entry_destroy(ent);
762 scf_transaction_destroy(tx);
763 scf_property_destroy(prop);
764 return (rc);
767 static int
768 set_val_integer(
769 idmap_cfg_handles_t *handles,
770 scf_propertygroup_t *pg,
771 const char *name,
772 int64_t val)
774 scf_value_t *value = NULL;
775 int rc;
777 if ((value = scf_value_create(handles->main)) == NULL) {
778 idmapdlog(LOG_ERR, "Unable to set property %s",
779 name, scf_strerror(scf_error()));
780 return (-1);
783 scf_value_set_integer(value, val);
785 rc = set_val(handles, pg, name, value);
787 scf_value_destroy(value);
789 return (rc);
793 static int
794 set_val_astring(
795 idmap_cfg_handles_t *handles,
796 scf_propertygroup_t *pg,
797 const char *name,
798 const char *val)
800 scf_value_t *value = NULL;
801 int rc = -1;
803 if ((value = scf_value_create(handles->main)) == NULL) {
804 idmapdlog(LOG_ERR, "Unable to set property %s",
805 name, scf_strerror(scf_error()));
806 goto out;
809 if (scf_value_set_astring(value, val) == -1) {
810 idmapdlog(LOG_ERR,
811 "scf_value_set_astring() failed: %s",
812 scf_strerror(scf_error()));
813 goto out;
816 rc = set_val(handles, pg, name, value);
818 out:
819 scf_value_destroy(value);
820 return (rc);
826 * This function updates a boolean value.
827 * If nothing has changed it returns 0 else 1
829 static int
830 update_bool(boolean_t *value, boolean_t *new, char *name)
832 if (*value == *new)
833 return (0);
835 if (DBG(CONFIG, 1)) {
836 idmapdlog(LOG_INFO, "change %s=%s", name,
837 *new ? "true" : "false");
840 *value = *new;
841 return (1);
845 * This function updates a uint64_t value.
846 * If nothing has changed it returns 0 else 1
848 static int
849 update_uint64(uint64_t *value, uint64_t *new, char *name)
851 if (*value == *new)
852 return (0);
854 if (DBG(CONFIG, 1))
855 idmapdlog(LOG_INFO, "change %s=%llu", name, *new);
857 *value = *new;
858 return (1);
862 * This function updates a string value.
863 * If nothing has changed it returns 0 else 1
865 static int
866 update_string(char **value, char **new, char *name)
868 int changed;
870 if (*new == NULL && *value != NULL)
871 changed = 1;
872 else if (*new != NULL && *value == NULL)
873 changed = 1;
874 else if (*new != NULL && *value != NULL && strcmp(*new, *value) != 0)
875 changed = 1;
876 else
877 changed = 0;
880 * Note that even if unchanged we can't just return; we must free one
881 * of the values.
884 if (DBG(CONFIG, 1) && changed)
885 idmapdlog(LOG_INFO, "change %s=%s", name, CHECK_NULL(*new));
887 free(*value);
888 *value = *new;
889 *new = NULL;
890 return (changed);
893 static int
894 update_enum(int *value, int *new, char *name, struct enum_lookup_map *map)
896 if (*value == *new)
897 return (0);
899 if (DBG(CONFIG, 1)) {
900 idmapdlog(LOG_INFO, "change %s=%s", name,
901 enum_lookup(*new, map));
904 *value = *new;
906 return (1);
910 * This function updates a directory service structure.
911 * If nothing has changed it returns 0 else 1
913 static int
914 update_dirs(ad_disc_ds_t **value, ad_disc_ds_t **new, char *name)
917 if (*value == *new)
918 /* Nothing to do */
919 return (0);
921 if (*value != NULL && *new != NULL &&
922 ad_disc_compare_ds(*value, *new) == 0) {
923 free(*new);
924 *new = NULL;
925 return (0);
928 if (*value != NULL)
929 free(*value);
931 *value = *new;
932 *new = NULL;
934 if (*value == NULL) {
935 /* We're unsetting this DS property */
936 if (DBG(CONFIG, 1))
937 idmapdlog(LOG_INFO, "change %s=<none>", name);
938 return (1);
941 if (DBG(CONFIG, 1)) {
942 /* List all the new DSs */
943 char buf[64];
944 ad_disc_ds_t *ds;
945 for (ds = *value; ds->host[0] != '\0'; ds++) {
946 if (ad_disc_getnameinfo(buf, sizeof (buf), &ds->addr))
947 (void) strlcpy(buf, "?", sizeof (buf));
948 idmapdlog(LOG_INFO, "change %s=%s addr=%s port=%d",
949 name, ds->host, buf, ds->port);
952 return (1);
956 * This function updates a trusted domains structure.
957 * If nothing has changed it returns 0 else 1
959 static int
960 update_trusted_domains(ad_disc_trusteddomains_t **value,
961 ad_disc_trusteddomains_t **new, char *name)
963 int i;
965 if (*value == *new)
966 /* Nothing to do */
967 return (0);
969 if (*value != NULL && *new != NULL &&
970 ad_disc_compare_trusteddomains(*value, *new) == 0) {
971 free(*new);
972 *new = NULL;
973 return (0);
976 if (*value != NULL)
977 free(*value);
979 *value = *new;
980 *new = NULL;
982 if (*value == NULL) {
983 /* We're unsetting this DS property */
984 if (DBG(CONFIG, 1))
985 idmapdlog(LOG_INFO, "change %s=<none>", name);
986 return (1);
989 if (DBG(CONFIG, 1)) {
990 /* List all the new domains */
991 for (i = 0; (*value)[i].domain[0] != '\0'; i++) {
992 idmapdlog(LOG_INFO, "change %s=%s direction=%s", name,
993 (*value)[i].domain,
994 enum_lookup((*value)[i].direction, trust_dir_map));
997 return (1);
1002 * This function updates a domains in a forest structure.
1003 * If nothing has changed it returns 0 else 1
1005 static int
1006 update_domains_in_forest(ad_disc_domainsinforest_t **value,
1007 ad_disc_domainsinforest_t **new, char *name)
1009 int i;
1011 if (*value == *new)
1012 /* Nothing to do */
1013 return (0);
1015 if (*value != NULL && *new != NULL &&
1016 ad_disc_compare_domainsinforest(*value, *new) == 0) {
1017 free(*new);
1018 *new = NULL;
1019 return (0);
1022 if (*value != NULL)
1023 free(*value);
1025 *value = *new;
1026 *new = NULL;
1028 if (*value == NULL) {
1029 /* We're unsetting this DS property */
1030 if (DBG(CONFIG, 1))
1031 idmapdlog(LOG_INFO, "change %s=<none>", name);
1032 return (1);
1035 if (DBG(CONFIG, 1)) {
1036 /* List all the new domains */
1037 for (i = 0; (*value)[i].domain[0] != '\0'; i++) {
1038 idmapdlog(LOG_INFO, "change %s=%s", name,
1039 (*value)[i].domain);
1042 return (1);
1046 static void
1047 free_trusted_forests(idmap_trustedforest_t **value, int *num_values)
1049 int i;
1051 for (i = 0; i < *num_values; i++) {
1052 free((*value)[i].forest_name);
1053 free((*value)[i].global_catalog);
1054 free((*value)[i].domains_in_forest);
1056 free(*value);
1057 *value = NULL;
1058 *num_values = 0;
1062 static int
1063 compare_trusteddomainsinforest(ad_disc_domainsinforest_t *df1,
1064 ad_disc_domainsinforest_t *df2)
1066 int i, j;
1067 int num_df1 = 0;
1068 int num_df2 = 0;
1069 boolean_t match;
1071 for (i = 0; df1[i].domain[0] != '\0'; i++)
1072 if (df1[i].trusted)
1073 num_df1++;
1075 for (j = 0; df2[j].domain[0] != '\0'; j++)
1076 if (df2[j].trusted)
1077 num_df2++;
1079 if (num_df1 != num_df2)
1080 return (1);
1082 for (i = 0; df1[i].domain[0] != '\0'; i++) {
1083 if (df1[i].trusted) {
1084 match = B_FALSE;
1085 for (j = 0; df2[j].domain[0] != '\0'; j++) {
1086 if (df2[j].trusted &&
1087 domain_eq(df1[i].domain, df2[j].domain) &&
1088 strcmp(df1[i].sid, df2[j].sid) == 0) {
1089 match = B_TRUE;
1090 break;
1093 if (!match)
1094 return (1);
1097 return (0);
1103 * This function updates trusted forest structure.
1104 * If nothing has changed it returns 0 else 1
1106 static int
1107 update_trusted_forest(idmap_trustedforest_t **value, int *num_value,
1108 idmap_trustedforest_t **new, int *num_new, char *name)
1110 int i, j;
1111 boolean_t match;
1113 if (*value == *new)
1114 /* Nothing to do */
1115 return (0);
1117 if (*value != NULL && *new != NULL) {
1118 if (*num_value != *num_new)
1119 goto not_equal;
1120 for (i = 0; i < *num_value; i++) {
1121 match = B_FALSE;
1122 for (j = 0; j < *num_new; j++) {
1123 if (strcmp((*value)[i].forest_name,
1124 (*new)[j].forest_name) == 0 &&
1125 ad_disc_compare_ds(
1126 (*value)[i].global_catalog,
1127 (*new)[j].global_catalog) == 0 &&
1128 compare_trusteddomainsinforest(
1129 (*value)[i].domains_in_forest,
1130 (*new)[j].domains_in_forest) == 0) {
1131 match = B_TRUE;
1132 break;
1135 if (!match)
1136 goto not_equal;
1138 free_trusted_forests(new, num_new);
1139 return (0);
1141 not_equal:
1142 if (*value != NULL)
1143 free_trusted_forests(value, num_value);
1144 *value = *new;
1145 *num_value = *num_new;
1146 *new = NULL;
1147 *num_new = 0;
1149 if (*value == NULL) {
1150 /* We're unsetting this DS property */
1151 if (DBG(CONFIG, 1))
1152 idmapdlog(LOG_INFO, "change %s=<none>", name);
1153 return (1);
1156 if (DBG(CONFIG, 1)) {
1157 /* List all the trusted forests */
1158 for (i = 0; i < *num_value; i++) {
1159 idmap_trustedforest_t *f = &(*value)[i];
1160 for (j = 0;
1161 f->domains_in_forest[j].domain[0] != '\0';
1162 j++) {
1163 /* List trusted Domains in the forest. */
1164 if (f->domains_in_forest[j].trusted)
1165 idmapdlog(LOG_INFO,
1166 "change %s=%s domain=%s",
1167 name, f->forest_name,
1168 f->domains_in_forest[j].domain);
1170 /* List the hosts */
1171 for (j = 0;
1172 f->global_catalog[j].host[0] != '\0';
1173 j++) {
1174 idmapdlog(LOG_INFO,
1175 "change %s=%s host=%s port=%d",
1176 name, f->forest_name,
1177 f->global_catalog[j].host,
1178 f->global_catalog[j].port);
1182 return (1);
1185 const char *
1186 enum_lookup(int value, struct enum_lookup_map *map)
1188 for (; map->string != NULL; map++) {
1189 if (value == map->value) {
1190 return (map->string);
1193 return ("(invalid)");
1197 * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the
1198 * interfaces.
1200 * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON.
1202 static
1203 boolean_t
1204 pfroute_event_is_interesting(int rt_sock)
1206 int nbytes;
1207 int64_t msg[2048 / 8];
1208 struct rt_msghdr *rtm;
1209 boolean_t is_interesting = B_FALSE;
1211 for (;;) {
1212 if ((nbytes = read(rt_sock, msg, sizeof (msg))) <= 0)
1213 break;
1214 rtm = (struct rt_msghdr *)msg;
1215 if (rtm->rtm_version != RTM_VERSION)
1216 continue;
1217 if (nbytes < rtm->rtm_msglen)
1218 continue;
1219 switch (rtm->rtm_type) {
1220 case RTM_NEWADDR:
1221 case RTM_DELADDR:
1222 case RTM_IFINFO:
1223 is_interesting = B_TRUE;
1224 break;
1225 default:
1226 break;
1229 return (is_interesting);
1233 * Wait for an event, and report what kind of event occurred.
1235 * Note that there are cases where we are awoken but don't care about
1236 * the lower-level event. We can't just loop here because we can't
1237 * readily calculate how long to sleep the next time. We return
1238 * EVENT_NOTHING and let the caller loop.
1240 static
1241 enum event_type
1242 wait_for_event(struct timespec *timeoutp)
1244 port_event_t pe;
1246 (void) memset(&pe, 0, sizeof (pe));
1247 if (port_get(idmapd_ev_port, &pe, timeoutp) != 0) {
1248 switch (errno) {
1249 case EINTR:
1250 return (EVENT_NOTHING);
1251 case ETIME:
1252 /* Timeout */
1253 return (EVENT_TIMEOUT);
1254 default:
1255 /* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */
1256 idmapdlog(LOG_ERR, "Event port failed: %s",
1257 strerror(errno));
1258 exit(1);
1259 /* NOTREACHED */
1264 switch (pe.portev_source) {
1265 case 0:
1267 * This isn't documented, but seems to be what you get if
1268 * the timeout is zero seconds and there are no events
1269 * pending.
1271 return (EVENT_TIMEOUT);
1273 case PORT_SOURCE_USER:
1274 switch (pe.portev_events) {
1275 case RECONFIGURE:
1276 return (EVENT_REFRESH);
1277 case POKE_AUTO_DISCOVERY:
1278 return (EVENT_POKED);
1279 case KICK_AUTO_DISCOVERY:
1280 return (EVENT_KICKED);
1282 return (EVENT_NOTHING);
1284 case PORT_SOURCE_FD:
1285 if (pe.portev_object == rt_sock) {
1287 * PF_ROUTE socket read event:
1288 * re-associate fd
1289 * handle event
1291 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD,
1292 rt_sock, POLLIN, NULL) != 0) {
1293 idmapdlog(LOG_ERR, "Failed to re-associate the "
1294 "routing socket with the event port: %s",
1295 strerror(errno));
1296 abort();
1299 * The network configuration may still be in flux.
1300 * No matter, the resolver will re-transmit and
1301 * timeout if need be.
1303 if (pfroute_event_is_interesting(rt_sock)) {
1304 if (DBG(CONFIG, 1)) {
1305 idmapdlog(LOG_DEBUG,
1306 "Interesting routing event");
1308 return (EVENT_ROUTING);
1309 } else {
1310 if (DBG(CONFIG, 2)) {
1311 idmapdlog(LOG_DEBUG,
1312 "Boring routing event");
1314 return (EVENT_NOTHING);
1317 /* Event on an FD other than the routing FD? Ignore it. */
1318 break;
1321 return (EVENT_NOTHING);
1324 void *
1325 idmap_cfg_update_thread(void *arg)
1327 NOTE(ARGUNUSED(arg))
1328 idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg;
1329 const ad_disc_t ad_ctx = _idmapdstate.cfg->handles.ad_ctx;
1330 int flags = CFG_DISCOVER;
1332 for (;;) {
1333 struct timespec timeout;
1334 struct timespec *timeoutp;
1335 int rc;
1336 int ttl, max_ttl;
1338 (void) ad_disc_SubnetChanged(ad_ctx);
1340 rc = idmap_cfg_load(_idmapdstate.cfg, flags);
1341 if (rc < -1) {
1342 idmapdlog(LOG_ERR, "Fatal errors while reading "
1343 "SMF properties");
1344 exit(1);
1345 } else if (rc == -1) {
1346 idmapdlog(LOG_WARNING,
1347 "Errors re-loading configuration may cause AD "
1348 "lookups to fail");
1352 * Wait for an interesting event. Note that we might get
1353 * boring events between interesting events. If so, we loop.
1355 flags = CFG_DISCOVER;
1356 for (;;) {
1358 * If we don't know our domain name, don't bother
1359 * with rediscovery until the next config change.
1360 * Avoids hourly noise in workgroup mode.
1362 if (pgcfg->domain_name == NULL)
1363 ttl = -1;
1364 else
1365 ttl = ad_disc_get_TTL(ad_ctx);
1366 if (ttl < 0) {
1367 timeoutp = NULL;
1368 } else {
1369 max_ttl = (int)pgcfg->rediscovery_interval;
1370 if (ttl > max_ttl)
1371 ttl = max_ttl;
1372 if (ttl < MIN_REDISCOVERY_INTERVAL)
1373 ttl = MIN_REDISCOVERY_INTERVAL;
1374 timeout.tv_sec = ttl;
1375 timeout.tv_nsec = 0;
1376 timeoutp = &timeout;
1379 if (DBG(CONFIG, 1))
1380 idmapdlog(LOG_DEBUG,
1381 "_cfg_update_thread waiting");
1383 switch (wait_for_event(timeoutp)) {
1384 case EVENT_NOTHING:
1385 if (DBG(CONFIG, 2))
1386 idmapdlog(LOG_DEBUG, "Boring event.");
1387 continue;
1388 case EVENT_REFRESH:
1389 if (DBG(CONFIG, 1))
1390 idmapdlog(LOG_INFO, "SMF refresh");
1392 * Forget any DC we had previously.
1394 flags |= CFG_FORGET_DC;
1397 * Blow away the ccache, we might have
1398 * re-joined the domain or joined a new one
1400 (void) unlink(IDMAP_CACHEDIR "/ccache");
1401 break;
1402 case EVENT_POKED:
1403 if (DBG(CONFIG, 1))
1404 idmapdlog(LOG_DEBUG, "poked");
1405 break;
1406 case EVENT_KICKED:
1407 if (DBG(CONFIG, 1))
1408 idmapdlog(LOG_DEBUG, "kicked");
1409 flags |= CFG_FORGET_DC;
1410 break;
1411 case EVENT_TIMEOUT:
1412 if (DBG(CONFIG, 1))
1413 idmapdlog(LOG_DEBUG, "TTL expired");
1414 break;
1415 case EVENT_ROUTING:
1416 /* Already logged to DEBUG */
1417 break;
1419 /* An interesting event! */
1420 break;
1424 * Lint isn't happy with the concept of a function declared to
1425 * return something, that doesn't return. Of course, merely adding
1426 * the return isn't enough, because it's never reached...
1428 /*NOTREACHED*/
1429 return (NULL);
1433 idmap_cfg_start_updates(void)
1435 if ((idmapd_ev_port = port_create()) < 0) {
1436 idmapdlog(LOG_ERR, "Failed to create event port: %s",
1437 strerror(errno));
1438 return (-1);
1441 if ((rt_sock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
1442 idmapdlog(LOG_ERR, "Failed to open routing socket: %s",
1443 strerror(errno));
1444 (void) close(idmapd_ev_port);
1445 return (-1);
1448 if (fcntl(rt_sock, F_SETFL, O_NDELAY|O_NONBLOCK) < 0) {
1449 idmapdlog(LOG_ERR, "Failed to set routing socket flags: %s",
1450 strerror(errno));
1451 (void) close(rt_sock);
1452 (void) close(idmapd_ev_port);
1453 return (-1);
1456 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD,
1457 rt_sock, POLLIN, NULL) != 0) {
1458 idmapdlog(LOG_ERR, "Failed to associate the routing "
1459 "socket with the event port: %s", strerror(errno));
1460 (void) close(rt_sock);
1461 (void) close(idmapd_ev_port);
1462 return (-1);
1465 if ((errno = pthread_create(&update_thread_handle, NULL,
1466 idmap_cfg_update_thread, NULL)) != 0) {
1467 idmapdlog(LOG_ERR, "Failed to start update thread: %s",
1468 strerror(errno));
1469 (void) port_dissociate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock);
1470 (void) close(rt_sock);
1471 (void) close(idmapd_ev_port);
1472 return (-1);
1475 return (0);
1479 * Reject attribute names with invalid characters.
1481 static
1483 valid_ldap_attr(const char *attr) {
1484 for (; *attr; attr++) {
1485 if (!isalnum(*attr) && *attr != '-' &&
1486 *attr != '_' && *attr != '.' && *attr != ';')
1487 return (0);
1489 return (1);
1492 static
1493 void
1494 idmapd_set_debug(
1495 idmap_cfg_handles_t *handles,
1496 enum idmapd_debug item,
1497 const char *name)
1499 int val;
1501 if (item < 0 || item > IDMAPD_DEBUG_MAX)
1502 return;
1504 val = get_debug(handles, name);
1506 if (val != _idmapdstate.debug[item])
1507 idmapdlog(LOG_DEBUG, "%s/%s = %d", DEBUG_PG, name, val);
1509 _idmapdstate.debug[item] = val;
1512 static
1513 void
1514 check_smf_debug_mode(idmap_cfg_handles_t *handles)
1516 idmapd_set_debug(handles, IDMAPD_DEBUG_ALL, "all");
1517 idmapd_set_debug(handles, IDMAPD_DEBUG_CONFIG, "config");
1518 idmapd_set_debug(handles, IDMAPD_DEBUG_MAPPING, "mapping");
1519 idmapd_set_debug(handles, IDMAPD_DEBUG_DISC, "discovery");
1520 idmapd_set_debug(handles, IDMAPD_DEBUG_DNS, "dns");
1521 idmapd_set_debug(handles, IDMAPD_DEBUG_LDAP, "ldap");
1523 adutils_set_debug(AD_DEBUG_ALL, _idmapdstate.debug[IDMAPD_DEBUG_ALL]);
1524 adutils_set_debug(AD_DEBUG_DISC, _idmapdstate.debug[IDMAPD_DEBUG_DISC]);
1525 adutils_set_debug(AD_DEBUG_DNS, _idmapdstate.debug[IDMAPD_DEBUG_DNS]);
1526 adutils_set_debug(AD_DEBUG_LDAP, _idmapdstate.debug[IDMAPD_DEBUG_LDAP]);
1530 * This is the half of idmap_cfg_load() that loads property values from
1531 * SMF (using the config/ property group of the idmap FMRI).
1533 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
1534 * -3 -> hard smf config failures
1535 * reading from SMF.
1537 static int
1538 idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
1539 int * const errors)
1541 int rc;
1542 char *s;
1544 *errors = 0;
1546 if (scf_pg_update(handles->config_pg) < 0) {
1547 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
1548 scf_strerror(scf_error()));
1549 return (-2);
1552 if (scf_pg_update(handles->debug_pg) < 0) {
1553 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
1554 scf_strerror(scf_error()));
1555 return (-2);
1558 check_smf_debug_mode(handles);
1560 rc = get_val_bool(handles, "unresolvable_sid_mapping",
1561 &pgcfg->eph_map_unres_sids, B_TRUE);
1562 if (rc != 0)
1563 (*errors)++;
1565 rc = get_val_bool(handles, "use_ads",
1566 &pgcfg->use_ads, B_TRUE);
1567 if (rc != 0)
1568 (*errors)++;
1570 rc = get_val_bool(handles, "use_lsa",
1571 &pgcfg->use_lsa, B_TRUE);
1572 if (rc != 0)
1573 (*errors)++;
1575 rc = get_val_bool(handles, "disable_cross_forest_trusts",
1576 &pgcfg->disable_cross_forest_trusts, B_TRUE);
1577 if (rc != 0)
1578 (*errors)++;
1580 rc = get_val_astring(handles, "directory_based_mapping", &s);
1581 if (rc != 0)
1582 (*errors)++;
1583 else if (s == NULL || strcasecmp(s, "none") == 0)
1584 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
1585 else if (strcasecmp(s, "name") == 0)
1586 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NAME;
1587 else if (strcasecmp(s, "idmu") == 0)
1588 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_IDMU;
1589 else {
1590 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
1591 idmapdlog(LOG_ERR,
1592 "config/directory_based_mapping: invalid value \"%s\" ignored",
1594 (*errors)++;
1596 free(s);
1598 rc = get_val_int(handles, "list_size_limit",
1599 &pgcfg->list_size_limit, SCF_TYPE_COUNT);
1600 if (rc != 0)
1601 (*errors)++;
1603 rc = get_val_int(handles, "id_cache_timeout",
1604 &pgcfg->id_cache_timeout, SCF_TYPE_COUNT);
1605 if (rc != 0)
1606 (*errors)++;
1607 if (pgcfg->id_cache_timeout == 0)
1608 pgcfg->id_cache_timeout = ID_CACHE_TMO_DEFAULT;
1610 rc = get_val_int(handles, "name_cache_timeout",
1611 &pgcfg->name_cache_timeout, SCF_TYPE_COUNT);
1612 if (rc != 0)
1613 (*errors)++;
1614 if (pgcfg->name_cache_timeout == 0)
1615 pgcfg->name_cache_timeout = NAME_CACHE_TMO_DEFAULT;
1617 rc = get_val_int(handles, "rediscovery_interval",
1618 &pgcfg->rediscovery_interval, SCF_TYPE_COUNT);
1619 if (rc != 0)
1620 (*errors)++;
1621 if (pgcfg->rediscovery_interval == 0)
1622 pgcfg->rediscovery_interval = REDISCOVERY_INTERVAL_DEFAULT;
1624 rc = get_val_astring(handles, "domain_name",
1625 &pgcfg->domain_name);
1626 if (rc != 0)
1627 (*errors)++;
1628 else {
1629 if (pgcfg->domain_name != NULL &&
1630 pgcfg->domain_name[0] == '\0') {
1631 free(pgcfg->domain_name);
1632 pgcfg->domain_name = NULL;
1634 (void) ad_disc_set_DomainName(handles->ad_ctx,
1635 pgcfg->domain_name);
1636 pgcfg->domain_name_auto_disc = B_FALSE;
1639 rc = get_val_astring(handles, "default_domain",
1640 &pgcfg->default_domain);
1641 if (rc != 0) {
1643 * SCF failures fetching config/default_domain we treat
1644 * as fatal as they may leave ID mapping rules that
1645 * match unqualified winnames flapping in the wind.
1647 return (-2);
1650 if (pgcfg->default_domain == NULL && pgcfg->domain_name != NULL) {
1651 pgcfg->default_domain = strdup(pgcfg->domain_name);
1654 rc = get_val_astring(handles, "domain_guid", &s);
1655 if (rc != 0) {
1656 (*errors)++;
1657 } else if (s == NULL || s[0] == '\0') {
1658 /* OK, not set. */
1659 free(s);
1660 } else {
1661 uuid_t u;
1663 if (uuid_parse(s, u) != 0) {
1664 idmapdlog(LOG_ERR,
1665 "config/domain_guid: invalid value \"%s\" ignored", s);
1666 free(s);
1667 (*errors)++;
1668 } else {
1669 pgcfg->domain_guid = s;
1670 pgcfg->domain_guid_auto_disc = B_FALSE;
1671 (void) ad_disc_set_DomainGUID(handles->ad_ctx, u);
1675 rc = get_val_astring(handles, "machine_uuid", &pgcfg->machine_uuid);
1676 if (rc != 0)
1677 (*errors)++;
1678 if (pgcfg->machine_uuid == NULL) {
1679 /* If machine_uuid not configured, generate one */
1680 if (generate_machine_uuid(&pgcfg->machine_uuid) < 0)
1681 return (-2);
1682 rc = set_val_astring(handles, handles->config_pg,
1683 "machine_uuid", pgcfg->machine_uuid);
1684 if (rc != 0)
1685 (*errors)++;
1688 rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid);
1689 if (rc != 0)
1690 (*errors)++;
1691 if (pgcfg->machine_sid == NULL) {
1693 * If machine_sid not configured, generate one
1694 * from the machine UUID.
1696 if (generate_machine_sid(&pgcfg->machine_sid,
1697 pgcfg->machine_uuid) < 0)
1698 return (-2);
1699 rc = set_val_astring(handles, handles->config_pg,
1700 "machine_sid", pgcfg->machine_sid);
1701 if (rc != 0)
1702 (*errors)++;
1705 rc = get_val_ds(handles, "domain_controller", 389,
1706 &pgcfg->domain_controller);
1707 if (rc != 0)
1708 (*errors)++;
1709 else {
1710 (void) ad_disc_set_DomainController(handles->ad_ctx,
1711 pgcfg->domain_controller);
1712 pgcfg->domain_controller_auto_disc = B_FALSE;
1715 rc = get_val_ds(handles, "preferred_dc", 389,
1716 &pgcfg->preferred_dc);
1717 if (rc != 0)
1718 (*errors)++;
1719 else {
1720 (void) ad_disc_set_PreferredDC(handles->ad_ctx,
1721 pgcfg->preferred_dc);
1722 pgcfg->preferred_dc_auto_disc = B_FALSE;
1725 rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name);
1726 if (rc != 0)
1727 (*errors)++;
1728 else {
1729 (void) ad_disc_set_ForestName(handles->ad_ctx,
1730 pgcfg->forest_name);
1731 pgcfg->forest_name_auto_disc = B_FALSE;
1734 rc = get_val_astring(handles, "site_name", &pgcfg->site_name);
1735 if (rc != 0)
1736 (*errors)++;
1737 else
1738 (void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name);
1740 rc = get_val_ds(handles, "global_catalog", 3268,
1741 &pgcfg->global_catalog);
1742 if (rc != 0)
1743 (*errors)++;
1744 else {
1745 (void) ad_disc_set_GlobalCatalog(handles->ad_ctx,
1746 pgcfg->global_catalog);
1747 pgcfg->global_catalog_auto_disc = B_FALSE;
1750 /* Unless we're doing directory-based name mapping, we're done. */
1751 if (pgcfg->directory_based_mapping != DIRECTORY_MAPPING_NAME)
1752 return (0);
1754 rc = get_val_astring(handles, "ad_unixuser_attr",
1755 &pgcfg->ad_unixuser_attr);
1756 if (rc != 0)
1757 return (-2);
1758 if (pgcfg->ad_unixuser_attr != NULL &&
1759 !valid_ldap_attr(pgcfg->ad_unixuser_attr)) {
1760 idmapdlog(LOG_ERR, "config/ad_unixuser_attr=%s is not a "
1761 "valid LDAP attribute name", pgcfg->ad_unixuser_attr);
1762 return (-3);
1765 rc = get_val_astring(handles, "ad_unixgroup_attr",
1766 &pgcfg->ad_unixgroup_attr);
1767 if (rc != 0)
1768 return (-2);
1769 if (pgcfg->ad_unixgroup_attr != NULL &&
1770 !valid_ldap_attr(pgcfg->ad_unixgroup_attr)) {
1771 idmapdlog(LOG_ERR, "config/ad_unixgroup_attr=%s is not a "
1772 "valid LDAP attribute name", pgcfg->ad_unixgroup_attr);
1773 return (-3);
1776 rc = get_val_astring(handles, "nldap_winname_attr",
1777 &pgcfg->nldap_winname_attr);
1778 if (rc != 0)
1779 return (-2);
1780 if (pgcfg->nldap_winname_attr != NULL &&
1781 !valid_ldap_attr(pgcfg->nldap_winname_attr)) {
1782 idmapdlog(LOG_ERR, "config/nldap_winname_attr=%s is not a "
1783 "valid LDAP attribute name", pgcfg->nldap_winname_attr);
1784 return (-3);
1786 if (pgcfg->ad_unixuser_attr == NULL &&
1787 pgcfg->ad_unixgroup_attr == NULL &&
1788 pgcfg->nldap_winname_attr == NULL) {
1789 idmapdlog(LOG_ERR,
1790 "If config/directory_based_mapping property is set to "
1791 "\"name\" then at least one of the following name mapping "
1792 "attributes must be specified. (config/ad_unixuser_attr OR "
1793 "config/ad_unixgroup_attr OR config/nldap_winname_attr)");
1794 return (-3);
1797 return (rc);
1800 static
1801 void
1802 log_if_unable(const void *val, const char *what)
1804 if (val == NULL) {
1805 idmapdlog(LOG_DEBUG, "unable to discover %s", what);
1809 static
1810 void
1811 discover_trusted_domains(idmap_pg_config_t *pgcfg, ad_disc_t ad_ctx)
1813 ad_disc_t trusted_ctx;
1814 int i, j, k, l;
1815 char *forestname;
1816 int num_trusteddomains;
1817 boolean_t new_forest;
1818 char *trusteddomain;
1819 ad_disc_ds_t *globalcatalog;
1820 idmap_trustedforest_t *trustedforests;
1821 ad_disc_domainsinforest_t *domainsinforest;
1823 pgcfg->trusted_domains =
1824 ad_disc_get_TrustedDomains(ad_ctx, NULL);
1826 if (pgcfg->forest_name != NULL && pgcfg->trusted_domains != NULL &&
1827 pgcfg->trusted_domains[0].domain[0] != '\0') {
1829 * We have trusted domains. We need to go through every
1830 * one and find its forest. If it is a new forest we then need
1831 * to find its Global Catalog and the domains in the forest
1833 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++)
1834 continue;
1835 num_trusteddomains = i;
1837 trustedforests = calloc(num_trusteddomains,
1838 sizeof (idmap_trustedforest_t));
1839 j = 0;
1840 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++) {
1841 trusteddomain = pgcfg->trusted_domains[i].domain;
1842 trusted_ctx = ad_disc_init();
1843 (void) ad_disc_set_DomainName(trusted_ctx,
1844 trusteddomain);
1845 forestname =
1846 ad_disc_get_ForestName(trusted_ctx, NULL);
1847 if (forestname == NULL) {
1848 if (DBG(CONFIG, 1)) {
1849 idmapdlog(LOG_DEBUG,
1850 "unable to discover Forest Name"
1851 " for the trusted domain %s",
1852 trusteddomain);
1854 ad_disc_fini(trusted_ctx);
1855 continue;
1858 if (strcasecmp(forestname, pgcfg->forest_name) == 0) {
1860 * Ignore the domain as it is part of
1861 * the primary forest
1863 free(forestname);
1864 ad_disc_fini(trusted_ctx);
1865 continue;
1868 /* Is this a new forest? */
1869 new_forest = B_TRUE;
1870 for (k = 0; k < j; k++) {
1871 if (strcasecmp(forestname,
1872 trustedforests[k].forest_name) == 0) {
1873 new_forest = B_FALSE;
1874 domainsinforest =
1875 trustedforests[k].domains_in_forest;
1876 break;
1879 if (!new_forest) {
1880 /* Mark the domain as trusted */
1881 for (l = 0;
1882 domainsinforest[l].domain[0] != '\0'; l++) {
1883 if (domain_eq(trusteddomain,
1884 domainsinforest[l].domain)) {
1885 domainsinforest[l].trusted =
1886 TRUE;
1887 break;
1890 free(forestname);
1891 ad_disc_fini(trusted_ctx);
1892 continue;
1896 * Get the Global Catalog and the domains in
1897 * this new forest.
1899 globalcatalog =
1900 ad_disc_get_GlobalCatalog(trusted_ctx,
1901 AD_DISC_PREFER_SITE, NULL);
1902 if (globalcatalog == NULL) {
1903 if (DBG(CONFIG, 1)) {
1904 idmapdlog(LOG_DEBUG,
1905 "unable to discover Global Catalog"
1906 " for the trusted domain %s",
1907 trusteddomain);
1909 free(forestname);
1910 ad_disc_fini(trusted_ctx);
1911 continue;
1913 domainsinforest =
1914 ad_disc_get_DomainsInForest(trusted_ctx, NULL);
1915 if (domainsinforest == NULL) {
1916 if (DBG(CONFIG, 1)) {
1917 idmapdlog(LOG_DEBUG,
1918 "unable to discover Domains in the"
1919 " Forest for the trusted domain %s",
1920 trusteddomain);
1922 free(globalcatalog);
1923 free(forestname);
1924 ad_disc_fini(trusted_ctx);
1925 continue;
1928 trustedforests[j].forest_name = forestname;
1929 trustedforests[j].global_catalog = globalcatalog;
1930 trustedforests[j].domains_in_forest = domainsinforest;
1931 j++;
1932 /* Mark the domain as trusted */
1933 for (l = 0; domainsinforest[l].domain[0] != '\0';
1934 l++) {
1935 if (domain_eq(trusteddomain,
1936 domainsinforest[l].domain)) {
1937 domainsinforest[l].trusted = TRUE;
1938 break;
1941 ad_disc_fini(trusted_ctx);
1943 if (j > 0) {
1944 pgcfg->num_trusted_forests = j;
1945 pgcfg->trusted_forests = trustedforests;
1946 } else {
1947 free(trustedforests);
1953 * This is the half of idmap_cfg_load() that auto-discovers values of
1954 * discoverable properties that weren't already set via SMF properties.
1956 * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it
1957 * needs to be careful not to overwrite any properties set in SMF.
1959 static void
1960 idmap_cfg_discover1(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg)
1962 ad_disc_t ad_ctx = handles->ad_ctx;
1963 FILE *status_fp = NULL;
1964 time_t t0, t1;
1966 t0 = time(NULL);
1967 if (DBG(CONFIG, 1))
1968 idmapdlog(LOG_DEBUG, "Running domain discovery.");
1970 (void) unlink(IDMAP_CACHEDIR "/discovery.log");
1971 status_fp = fopen(IDMAP_CACHEDIR "/discovery.log", "w");
1972 if (status_fp) {
1973 (void) fchmod(fileno(status_fp), 0644);
1974 ad_disc_set_StatusFP(ad_ctx, status_fp);
1977 if (pgcfg->domain_name == NULL) {
1978 idmapdlog(LOG_DEBUG, "No domain name specified.");
1979 if (status_fp)
1980 (void) fprintf(status_fp, "(no domain name)\n");
1981 goto out;
1984 if (pgcfg->domain_controller == NULL)
1985 pgcfg->domain_controller =
1986 ad_disc_get_DomainController(ad_ctx,
1987 AD_DISC_PREFER_SITE,
1988 &pgcfg->domain_controller_auto_disc);
1990 if (pgcfg->domain_guid == NULL) {
1991 char buf[UUID_PRINTABLE_STRING_LENGTH];
1992 uchar_t *u = ad_disc_get_DomainGUID(ad_ctx,
1993 &pgcfg->domain_guid_auto_disc);
1994 (void) memset(buf, 0, sizeof (buf));
1995 if (u != NULL) {
1996 uuid_unparse(u, buf);
1997 pgcfg->domain_guid = strdup(buf);
2001 if (pgcfg->forest_name == NULL)
2002 pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx,
2003 &pgcfg->forest_name_auto_disc);
2005 if (pgcfg->site_name == NULL)
2006 pgcfg->site_name = ad_disc_get_SiteName(ad_ctx,
2007 &pgcfg->site_name_auto_disc);
2009 if (DBG(CONFIG, 1)) {
2010 log_if_unable(pgcfg->domain_name, "Domain Name");
2011 log_if_unable(pgcfg->domain_controller,
2012 "Domain Controller");
2013 log_if_unable(pgcfg->domain_guid, "Domain GUID");
2014 log_if_unable(pgcfg->forest_name, "Forest Name");
2015 log_if_unable(pgcfg->site_name, "Site Name");
2018 out:
2019 if (status_fp) {
2020 ad_disc_set_StatusFP(ad_ctx, NULL);
2021 (void) fclose(status_fp);
2022 status_fp = NULL;
2025 if (DBG(CONFIG, 1))
2026 idmapdlog(LOG_DEBUG, "Domain discovery done.");
2029 * Log when this took more than 15 sec.
2031 t1 = time(NULL);
2032 if (t1 > (t0 + 15)) {
2033 idmapdlog(LOG_NOTICE, "Domain discovery took %d sec.",
2034 (int)(t1 - t0));
2035 idmapdlog(LOG_NOTICE, "Check the DNS configuration.");
2040 * This is the second part of discovery, which can take a while.
2041 * We don't want to hold up parties who just want to know what
2042 * domain controller we're using (like smbd), so this part runs
2043 * after we've updated that info in the "live" config and told
2044 * such consumers to go ahead.
2046 * This is a lot like idmap_cfg_discover(), but used LDAP queries
2047 * get the forest information from the global catalog servers.
2049 * Note: the previous update_* calls have usually nuked any
2050 * useful information from pgcfg before we get here, so we
2051 * can only use it store discovery results, not to read.
2053 static void
2054 idmap_cfg_discover2(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg)
2056 ad_disc_t ad_ctx = handles->ad_ctx;
2057 FILE *status_fp = NULL;
2058 time_t t0, t1;
2060 t0 = time(NULL);
2061 if (DBG(CONFIG, 1))
2062 idmapdlog(LOG_DEBUG, "Running forest discovery.");
2064 status_fp = fopen(IDMAP_CACHEDIR "/discovery.log", "a");
2065 if (status_fp)
2066 ad_disc_set_StatusFP(ad_ctx, status_fp);
2068 if (pgcfg->global_catalog == NULL)
2069 pgcfg->global_catalog =
2070 ad_disc_get_GlobalCatalog(ad_ctx,
2071 AD_DISC_PREFER_SITE,
2072 &pgcfg->global_catalog_auto_disc);
2074 if (pgcfg->global_catalog != NULL) {
2075 pgcfg->domains_in_forest =
2076 ad_disc_get_DomainsInForest(ad_ctx, NULL);
2078 if (!pgcfg->disable_cross_forest_trusts)
2079 discover_trusted_domains(pgcfg, ad_ctx);
2082 if (DBG(CONFIG, 1)) {
2083 log_if_unable(pgcfg->global_catalog, "Global Catalog");
2084 log_if_unable(pgcfg->domains_in_forest,
2085 "Domains in the Forest");
2086 /* Empty trusted domains list is OK. */
2089 if (status_fp) {
2090 ad_disc_set_StatusFP(ad_ctx, NULL);
2091 (void) fclose(status_fp);
2092 status_fp = NULL;
2095 if (DBG(CONFIG, 1))
2096 idmapdlog(LOG_DEBUG, "Forest discovery done.");
2099 * Log when this took more than 30 sec.
2101 t1 = time(NULL);
2102 if (t1 > (t0 + 30)) {
2103 idmapdlog(LOG_NOTICE, "Forest discovery took %d sec.",
2104 (int)(t1 - t0));
2105 idmapdlog(LOG_NOTICE, "Check AD join status.");
2111 * idmap_cfg_load() is called at startup, and periodically via the
2112 * update thread when the auto-discovery TTLs expire, as well as part of
2113 * the refresh method, to update the current configuration. It always
2114 * reads from SMF, but you still have to refresh the service after
2115 * changing the config pg in order for the changes to take effect.
2117 * There is one flag:
2119 * - CFG_DISCOVER
2121 * If CFG_DISCOVER is set then idmap_cfg_load() calls
2122 * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property
2123 * values that weren't set in SMF.
2125 * idmap_cfg_load() will log (to LOG_NOTICE) whether the configuration
2126 * changed.
2128 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
2129 * reading from SMF.
2132 idmap_cfg_load(idmap_cfg_t *cfg, int flags)
2134 const ad_disc_t ad_ctx = cfg->handles.ad_ctx;
2135 int rc = 0;
2136 int errors;
2137 int changed = 0;
2138 int dc_changed = 0;
2139 int ad_reload_required = 0;
2140 idmap_pg_config_t new_pgcfg, *live_pgcfg;
2142 if (DBG(CONFIG, 1))
2143 idmapdlog(LOG_DEBUG, "Loading configuration.");
2145 live_pgcfg = &cfg->pgcfg;
2146 (void) memset(&new_pgcfg, 0, sizeof (new_pgcfg));
2148 (void) pthread_mutex_lock(&cfg->handles.mutex);
2150 if ((rc = idmap_cfg_load_smf(&cfg->handles, &new_pgcfg, &errors)) < -1)
2151 goto err;
2153 if (flags & CFG_DISCOVER) {
2155 ad_disc_refresh(ad_ctx);
2158 * Unless we've been asked to forget the current DC,
2159 * give preference (in order) to the preferred DC if
2160 * configured, or the current DC. These preferences
2161 * reduce undesirable DC changes.
2163 if (flags & CFG_FORGET_DC) {
2164 (void) ad_disc_set_PreferredDC(ad_ctx, NULL);
2165 } else if (new_pgcfg.preferred_dc != NULL) {
2166 (void) ad_disc_set_PreferredDC(ad_ctx,
2167 new_pgcfg.preferred_dc);
2168 } else if (live_pgcfg->domain_controller != NULL) {
2169 (void) ad_disc_set_PreferredDC(ad_ctx,
2170 live_pgcfg->domain_controller);
2171 } else {
2172 (void) ad_disc_set_PreferredDC(ad_ctx, NULL);
2176 * We want a way to tell adspriv_getdcname_1_svc()
2177 * (and others) that discovery is running and therefore
2178 * they may want to wait a bit or return an error...
2180 (void) mutex_lock(&_idmapdstate.addisc_lk);
2181 _idmapdstate.addisc_st |= ADDISC_ST_RUNNING;
2182 (void) mutex_unlock(&_idmapdstate.addisc_lk);
2184 idmap_cfg_discover1(&cfg->handles, &new_pgcfg);
2186 WRLOCK_CONFIG();
2187 (void) mutex_lock(&_idmapdstate.addisc_lk);
2188 _idmapdstate.addisc_st = 0;
2189 (void) cond_broadcast(&_idmapdstate.addisc_cv);
2190 (void) mutex_unlock(&_idmapdstate.addisc_lk);
2191 } else {
2192 WRLOCK_CONFIG();
2195 /* Non-discoverable props updated here */
2197 changed += update_uint64(&live_pgcfg->list_size_limit,
2198 &new_pgcfg.list_size_limit, "list_size_limit");
2200 changed += update_uint64(&live_pgcfg->id_cache_timeout,
2201 &new_pgcfg.id_cache_timeout, "id_cache_timeout");
2203 changed += update_uint64(&live_pgcfg->name_cache_timeout,
2204 &new_pgcfg.name_cache_timeout, "name_cache_timeout");
2206 changed += update_uint64(&live_pgcfg->rediscovery_interval,
2207 &new_pgcfg.rediscovery_interval, "rediscovery_interval");
2209 changed += update_string(&live_pgcfg->machine_sid,
2210 &new_pgcfg.machine_sid, "machine_sid");
2212 changed += update_bool(&live_pgcfg->eph_map_unres_sids,
2213 &new_pgcfg.eph_map_unres_sids, "unresolvable_sid_mapping");
2215 changed += update_bool(&live_pgcfg->use_ads,
2216 &new_pgcfg.use_ads, "use_ads");
2218 changed += update_bool(&live_pgcfg->use_lsa,
2219 &new_pgcfg.use_lsa, "use_lsa");
2221 changed += update_bool(&live_pgcfg->disable_cross_forest_trusts,
2222 &new_pgcfg.disable_cross_forest_trusts,
2223 "disable_cross_forest_trusts");
2225 changed += update_enum(&live_pgcfg->directory_based_mapping,
2226 &new_pgcfg.directory_based_mapping, "directory_based_mapping",
2227 directory_mapping_map);
2229 changed += update_string(&live_pgcfg->ad_unixuser_attr,
2230 &new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr");
2232 changed += update_string(&live_pgcfg->ad_unixgroup_attr,
2233 &new_pgcfg.ad_unixgroup_attr, "ad_unixgroup_attr");
2235 changed += update_string(&live_pgcfg->nldap_winname_attr,
2236 &new_pgcfg.nldap_winname_attr, "nldap_winname_attr");
2238 changed += update_string(&live_pgcfg->default_domain,
2239 &new_pgcfg.default_domain, "default_domain");
2241 changed += update_dirs(&live_pgcfg->preferred_dc,
2242 &new_pgcfg.preferred_dc, "preferred_dc");
2244 /* Props that can be discovered or set in SMF updated here */
2246 if (update_string(&live_pgcfg->domain_name,
2247 &new_pgcfg.domain_name, "domain_name")) {
2248 changed++;
2249 ad_reload_required = TRUE;
2250 idmapd_set_krb5_realm(live_pgcfg->domain_name);
2252 live_pgcfg->domain_name_auto_disc = new_pgcfg.domain_name_auto_disc;
2254 changed += update_string(&live_pgcfg->domain_guid,
2255 &new_pgcfg.domain_guid, "domain_guid");
2256 live_pgcfg->domain_guid_auto_disc = new_pgcfg.domain_guid_auto_disc;
2258 dc_changed = update_dirs(&live_pgcfg->domain_controller,
2259 &new_pgcfg.domain_controller, "domain_controller");
2260 changed += dc_changed;
2261 live_pgcfg->domain_controller_auto_disc =
2262 new_pgcfg.domain_controller_auto_disc;
2264 changed += update_string(&live_pgcfg->forest_name,
2265 &new_pgcfg.forest_name, "forest_name");
2266 live_pgcfg->forest_name_auto_disc = new_pgcfg.forest_name_auto_disc;
2268 changed += update_string(&live_pgcfg->site_name,
2269 &new_pgcfg.site_name, "site_name");
2270 live_pgcfg->site_name_auto_disc = new_pgcfg.site_name_auto_disc;
2272 if (DBG(CONFIG, 1)) {
2273 if (changed)
2274 idmapdlog(LOG_NOTICE, "Configuration changed");
2275 else
2276 idmapdlog(LOG_NOTICE, "Configuration unchanged");
2279 UNLOCK_CONFIG();
2281 if (dc_changed != 0) {
2282 notify_dc_changed();
2286 * Discovery2 can take a while.
2288 if (flags & CFG_DISCOVER) {
2289 if (live_pgcfg->domain_name != NULL &&
2290 live_pgcfg->forest_name != NULL)
2291 idmap_cfg_discover2(&cfg->handles, &new_pgcfg);
2292 ad_disc_done(ad_ctx);
2295 WRLOCK_CONFIG();
2297 /* More props that can be discovered or set in SMF */
2299 changed += update_dirs(&live_pgcfg->global_catalog,
2300 &new_pgcfg.global_catalog, "global_catalog");
2301 live_pgcfg->global_catalog_auto_disc =
2302 new_pgcfg.global_catalog_auto_disc;
2304 /* Props that are only discovered (never in SMF) */
2306 if (update_domains_in_forest(&live_pgcfg->domains_in_forest,
2307 &new_pgcfg.domains_in_forest, "domains_in_forest")) {
2308 changed++;
2309 ad_reload_required = TRUE;
2312 if (update_trusted_domains(&live_pgcfg->trusted_domains,
2313 &new_pgcfg.trusted_domains, "trusted_domains")) {
2314 changed++;
2315 if (live_pgcfg->trusted_domains != NULL &&
2316 live_pgcfg->trusted_domains[0].domain[0] != '\0')
2317 ad_reload_required = TRUE;
2320 if (update_trusted_forest(&live_pgcfg->trusted_forests,
2321 &live_pgcfg->num_trusted_forests, &new_pgcfg.trusted_forests,
2322 &new_pgcfg.num_trusted_forests, "trusted_forest")) {
2323 changed++;
2324 if (live_pgcfg->trusted_forests != NULL)
2325 ad_reload_required = TRUE;
2328 if (DBG(CONFIG, 1)) {
2329 if (changed)
2330 idmapdlog(LOG_NOTICE, "Configuration changed");
2331 else
2332 idmapdlog(LOG_NOTICE, "Configuration unchanged");
2335 UNLOCK_CONFIG();
2337 if (ad_reload_required)
2338 reload_ad();
2340 idmap_cfg_unload(&new_pgcfg);
2342 err:
2343 (void) pthread_mutex_unlock(&cfg->handles.mutex);
2345 if (rc < -1)
2346 return (rc);
2348 return ((errors == 0) ? 0 : -1);
2352 * Initialize 'cfg'.
2354 idmap_cfg_t *
2355 idmap_cfg_init()
2357 idmap_cfg_handles_t *handles;
2359 /* First the smf repository handles: */
2360 idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t));
2361 if (!cfg) {
2362 idmapdlog(LOG_ERR, "Out of memory");
2363 return (NULL);
2365 handles = &cfg->handles;
2367 (void) pthread_mutex_init(&handles->mutex, NULL);
2369 if (!(handles->main = scf_handle_create(SCF_VERSION))) {
2370 idmapdlog(LOG_ERR, "scf_handle_create() failed: %s",
2371 scf_strerror(scf_error()));
2372 goto error;
2375 if (scf_handle_bind(handles->main) < 0) {
2376 idmapdlog(LOG_ERR, "scf_handle_bind() failed: %s",
2377 scf_strerror(scf_error()));
2378 goto error;
2381 if (!(handles->service = scf_service_create(handles->main)) ||
2382 !(handles->instance = scf_instance_create(handles->main)) ||
2383 !(handles->config_pg = scf_pg_create(handles->main)) ||
2384 !(handles->debug_pg = scf_pg_create(handles->main))) {
2385 idmapdlog(LOG_ERR, "scf handle creation failed: %s",
2386 scf_strerror(scf_error()));
2387 goto error;
2390 if (scf_handle_decode_fmri(handles->main,
2391 FMRI_BASE "/:properties/" CONFIG_PG,
2392 NULL, /* scope */
2393 handles->service, /* service */
2394 handles->instance, /* instance */
2395 handles->config_pg, /* pg */
2396 NULL, /* prop */
2397 SCF_DECODE_FMRI_EXACT) < 0) {
2398 idmapdlog(LOG_ERR, "scf_handle_decode_fmri() failed: %s",
2399 scf_strerror(scf_error()));
2400 goto error;
2403 if (scf_service_get_pg(handles->service,
2404 DEBUG_PG, handles->debug_pg) < 0) {
2405 idmapdlog(LOG_ERR, "Property group \"%s\": %s",
2406 DEBUG_PG, scf_strerror(scf_error()));
2407 goto error;
2410 check_smf_debug_mode(handles);
2412 /* Initialize AD Auto Discovery context */
2413 handles->ad_ctx = ad_disc_init();
2414 if (handles->ad_ctx == NULL)
2415 goto error;
2417 return (cfg);
2419 error:
2420 (void) idmap_cfg_fini(cfg);
2421 return (NULL);
2424 void
2425 idmap_cfg_unload(idmap_pg_config_t *pgcfg)
2428 if (pgcfg->default_domain) {
2429 free(pgcfg->default_domain);
2430 pgcfg->default_domain = NULL;
2432 if (pgcfg->domain_name) {
2433 free(pgcfg->domain_name);
2434 pgcfg->domain_name = NULL;
2436 if (pgcfg->domain_guid) {
2437 free(pgcfg->domain_guid);
2438 pgcfg->domain_guid = NULL;
2440 if (pgcfg->machine_sid) {
2441 free(pgcfg->machine_sid);
2442 pgcfg->machine_sid = NULL;
2444 if (pgcfg->domain_controller) {
2445 free(pgcfg->domain_controller);
2446 pgcfg->domain_controller = NULL;
2448 if (pgcfg->forest_name) {
2449 free(pgcfg->forest_name);
2450 pgcfg->forest_name = NULL;
2452 if (pgcfg->site_name) {
2453 free(pgcfg->site_name);
2454 pgcfg->site_name = NULL;
2456 if (pgcfg->global_catalog) {
2457 free(pgcfg->global_catalog);
2458 pgcfg->global_catalog = NULL;
2460 if (pgcfg->trusted_domains) {
2461 free(pgcfg->trusted_domains);
2462 pgcfg->trusted_domains = NULL;
2464 if (pgcfg->trusted_forests)
2465 free_trusted_forests(&pgcfg->trusted_forests,
2466 &pgcfg->num_trusted_forests);
2468 if (pgcfg->ad_unixuser_attr) {
2469 free(pgcfg->ad_unixuser_attr);
2470 pgcfg->ad_unixuser_attr = NULL;
2472 if (pgcfg->ad_unixgroup_attr) {
2473 free(pgcfg->ad_unixgroup_attr);
2474 pgcfg->ad_unixgroup_attr = NULL;
2476 if (pgcfg->nldap_winname_attr) {
2477 free(pgcfg->nldap_winname_attr);
2478 pgcfg->nldap_winname_attr = NULL;
2483 idmap_cfg_fini(idmap_cfg_t *cfg)
2485 idmap_cfg_handles_t *handles = &cfg->handles;
2486 idmap_cfg_unload(&cfg->pgcfg);
2488 (void) pthread_mutex_destroy(&handles->mutex);
2489 scf_pg_destroy(handles->config_pg);
2490 if (handles->debug_pg != NULL)
2491 scf_pg_destroy(handles->debug_pg);
2492 scf_instance_destroy(handles->instance);
2493 scf_service_destroy(handles->service);
2494 scf_handle_destroy(handles->main);
2495 if (handles->ad_ctx != NULL)
2496 ad_disc_fini(handles->ad_ctx);
2497 free(cfg);
2499 return (0);
2502 void
2503 idmap_cfg_poke_updates(void)
2505 int prev_st;
2507 if (DBG(CONFIG, 1)) {
2508 idmapdlog(LOG_INFO, "idmap_cfg_poke_updates");
2511 (void) mutex_lock(&_idmapdstate.addisc_lk);
2512 prev_st = _idmapdstate.addisc_st;
2513 _idmapdstate.addisc_st |= ADDISC_ST_REQUESTED;
2514 (void) mutex_unlock(&_idmapdstate.addisc_lk);
2516 if (prev_st & ADDISC_ST_REQUESTED) {
2517 idmapdlog(LOG_DEBUG, "already poked");
2518 } else {
2519 idmapdlog(LOG_DEBUG, "port send poke");
2520 (void) port_send(idmapd_ev_port, POKE_AUTO_DISCOVERY, NULL);
2524 void
2525 idmap_cfg_force_rediscovery(void)
2527 int prev_st;
2529 if (DBG(CONFIG, 1)) {
2530 idmapdlog(LOG_INFO, "idmap_cfg_force_rediscovery");
2533 (void) mutex_lock(&_idmapdstate.addisc_lk);
2534 prev_st = _idmapdstate.addisc_st;
2535 _idmapdstate.addisc_st |= ADDISC_ST_REQUESTED;
2536 (void) mutex_unlock(&_idmapdstate.addisc_lk);
2538 if (prev_st & ADDISC_ST_REQUESTED) {
2539 idmapdlog(LOG_DEBUG, "already kicked");
2540 } else {
2541 idmapdlog(LOG_DEBUG, "port send kick");
2542 (void) port_send(idmapd_ev_port, KICK_AUTO_DISCOVERY, NULL);
2546 /*ARGSUSED*/
2547 void
2548 idmap_cfg_hup_handler(int sig)
2550 if (idmapd_ev_port >= 0)
2551 (void) port_send(idmapd_ev_port, RECONFIGURE, NULL);
2555 * Upgrade the debug flags.
2557 * We're replacing a single debug flag with a fine-grained mechanism that
2558 * is also capable of considerably more verbosity. We'll take a stab at
2559 * producing roughly the same level of output.
2561 static
2563 upgrade_debug(idmap_cfg_handles_t *handles)
2565 boolean_t debug_present;
2566 const char DEBUG_PROP[] = "debug";
2567 int rc;
2569 rc = prop_exists(handles, DEBUG_PROP, &debug_present);
2571 if (rc != 0)
2572 return (rc);
2574 if (!debug_present)
2575 return (0);
2577 idmapdlog(LOG_INFO,
2578 "Upgrading old %s/%s setting to %s/* settings.",
2579 CONFIG_PG, DEBUG_PROP, DEBUG_PG);
2581 rc = set_val_integer(handles, handles->debug_pg, "config", 1);
2582 if (rc != 0)
2583 return (rc);
2584 rc = set_val_integer(handles, handles->debug_pg, "discovery", 1);
2585 if (rc != 0)
2586 return (rc);
2588 rc = del_val(handles, handles->config_pg, DEBUG_PROP);
2589 if (rc != 0)
2590 return (rc);
2592 return (0);
2596 * Upgrade the DS mapping flags.
2598 * If the old ds_name_mapping_enabled flag is present, then
2599 * if the new directory_based_mapping value is present, then
2600 * if the two are compatible, delete the old and note it
2601 * else delete the old and warn
2602 * else
2603 * set the new based on the old, and note it
2604 * delete the old
2606 static
2608 upgrade_directory_mapping(idmap_cfg_handles_t *handles)
2610 boolean_t legacy_ds_name_mapping_present;
2611 const char DS_NAME_MAPPING_ENABLED[] = "ds_name_mapping_enabled";
2612 const char DIRECTORY_BASED_MAPPING[] = "directory_based_mapping";
2613 int rc;
2615 rc = prop_exists(handles, DS_NAME_MAPPING_ENABLED,
2616 &legacy_ds_name_mapping_present);
2618 if (rc != 0)
2619 return (rc);
2621 if (!legacy_ds_name_mapping_present)
2622 return (0);
2624 boolean_t legacy_ds_name_mapping_enabled;
2625 rc = get_val_bool(handles, DS_NAME_MAPPING_ENABLED,
2626 &legacy_ds_name_mapping_enabled, B_FALSE);
2627 if (rc != 0)
2628 return (rc);
2630 char *legacy_mode;
2631 char *legacy_bool_string;
2632 if (legacy_ds_name_mapping_enabled) {
2633 legacy_mode = "name";
2634 legacy_bool_string = "true";
2635 } else {
2636 legacy_mode = "none";
2637 legacy_bool_string = "false";
2640 char *directory_based_mapping;
2641 rc = get_val_astring(handles, DIRECTORY_BASED_MAPPING,
2642 &directory_based_mapping);
2643 if (rc != 0)
2644 return (rc);
2646 if (directory_based_mapping == NULL) {
2647 idmapdlog(LOG_INFO,
2648 "Upgrading old %s=%s setting\n"
2649 "to %s=%s.",
2650 DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2651 DIRECTORY_BASED_MAPPING, legacy_mode);
2652 rc = set_val_astring(handles, handles->config_pg,
2653 DIRECTORY_BASED_MAPPING, legacy_mode);
2654 if (rc != 0)
2655 return (rc);
2656 } else {
2657 boolean_t new_name_mapping;
2658 if (strcasecmp(directory_based_mapping, "name") == 0)
2659 new_name_mapping = B_TRUE;
2660 else
2661 new_name_mapping = B_FALSE;
2663 if (legacy_ds_name_mapping_enabled == new_name_mapping) {
2664 idmapdlog(LOG_INFO,
2665 "Automatically removing old %s=%s setting\n"
2666 "in favor of %s=%s.",
2667 DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2668 DIRECTORY_BASED_MAPPING, directory_based_mapping);
2669 } else {
2670 idmapdlog(LOG_WARNING,
2671 "Removing conflicting %s=%s setting\n"
2672 "in favor of %s=%s.",
2673 DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2674 DIRECTORY_BASED_MAPPING, directory_based_mapping);
2676 free(directory_based_mapping);
2679 rc = del_val(handles, handles->config_pg, DS_NAME_MAPPING_ENABLED);
2680 if (rc != 0)
2681 return (rc);
2683 return (0);
2687 * Do whatever is necessary to upgrade idmap's configuration before
2688 * we load it.
2691 idmap_cfg_upgrade(idmap_cfg_t *cfg)
2693 int rc;
2695 rc = upgrade_directory_mapping(&cfg->handles);
2696 if (rc != 0)
2697 return (rc);
2699 rc = upgrade_debug(&cfg->handles);
2700 if (rc != 0)
2701 return (rc);
2703 return (0);
2707 * The LDAP code passes principal names lacking any
2708 * realm information, which causes mech_krb5 to do
2709 * awful things trying to figure out the realm.
2710 * Avoid that by making sure it has a default,
2711 * even when krb5.conf is not configured.
2713 static void
2714 idmapd_set_krb5_realm(char *domain)
2716 static char realm[MAXHOSTNAMELEN];
2717 size_t ilen, olen;
2718 int err;
2720 if (domain == NULL) {
2721 (void) unsetenv("KRB5_DEFAULT_REALM");
2722 return;
2725 /* Convert to upper case, in place. */
2726 (void) strlcpy(realm, domain, sizeof (realm));
2727 olen = ilen = strlen(realm);
2728 (void) u8_textprep_str(realm, &ilen, realm, &olen,
2729 U8_TEXTPREP_TOUPPER, U8_UNICODE_LATEST, &err);
2731 (void) setenv("KRB5_DEFAULT_REALM", realm, 1);