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]
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)
38 #include <uuid/uuid.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>
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"
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
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" },
104 struct enum_lookup_map trust_dir_map
[] = {
105 { 1, "they trust us" },
106 { 2, "we trust them" },
107 { 3, "we trust each other" },
112 generate_machine_uuid(char **machine_uuid
)
116 *machine_uuid
= calloc(1, UUID_PRINTABLE_STRING_LENGTH
+ 1);
117 if (*machine_uuid
== NULL
) {
118 idmapdlog(LOG_ERR
, "Out of memory");
123 uuid_generate_time(uu
);
124 uuid_unparse(uu
, *machine_uuid
);
130 generate_machine_sid(char **machine_sid
, char *machine_uuid
)
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
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");
164 /* In the case of error, exists is set to FALSE anyway */
166 prop_exists(idmap_cfg_handles_t
*handles
, const char *name
, boolean_t
*exists
)
169 scf_property_t
*scf_prop
;
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()));
180 if (scf_pg_get_property(handles
->config_pg
, name
, scf_prop
) == 0)
183 scf_property_destroy(scf_prop
);
189 get_debug(idmap_cfg_handles_t
*handles
, const char *name
)
193 scf_property_t
*scf_prop
;
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()));
202 value
= scf_value_create(handles
->main
);
204 idmapdlog(LOG_ERR
, "scf_value_create() failed: %s",
205 scf_strerror(scf_error()));
209 if (scf_pg_get_property(handles
->debug_pg
, name
, scf_prop
) < 0) {
210 /* this is OK: the property is just undefined */
215 if (scf_property_get_value(scf_prop
, value
) < 0) {
216 /* It is still OK when a property doesn't have any value */
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()));
227 scf_value_destroy(value
);
228 scf_property_destroy(scf_prop
);
234 get_val_bool(idmap_cfg_handles_t
*handles
, const char *name
,
235 boolean_t
*val
, boolean_t default_val
)
239 scf_property_t
*scf_prop
;
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()));
250 value
= scf_value_create(handles
->main
);
252 idmapdlog(LOG_ERR
, "scf_value_create() failed: %s",
253 scf_strerror(scf_error()));
254 scf_property_destroy(scf_prop
);
258 /* It is OK if the property is undefined */
259 if (scf_pg_get_property(handles
->config_pg
, name
, scf_prop
) < 0)
263 /* It is still OK when a property doesn't have any value */
264 if (scf_property_get_value(scf_prop
, value
) < 0)
268 rc
= scf_value_get_boolean(value
, &b
);
274 scf_value_destroy(value
);
275 scf_property_destroy(scf_prop
);
281 get_val_int(idmap_cfg_handles_t
*handles
, const char *name
,
282 void *val
, scf_type_t type
)
286 scf_property_t
*scf_prop
;
291 *(uint64_t *)val
= 0;
293 case SCF_TYPE_INTEGER
:
297 idmapdlog(LOG_ERR
, "Invalid scf integer type (%d)",
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()));
308 value
= scf_value_create(handles
->main
);
310 idmapdlog(LOG_ERR
, "scf_value_create() failed: %s",
311 scf_strerror(scf_error()));
312 scf_property_destroy(scf_prop
);
316 if (scf_pg_get_property(handles
->config_pg
, name
, scf_prop
) < 0)
317 /* this is OK: the property is just undefined */
321 if (scf_property_get_value(scf_prop
, value
) < 0)
322 /* It is still OK when a property doesn't have any value */
327 rc
= scf_value_get_count(value
, val
);
329 case SCF_TYPE_INTEGER
:
330 rc
= scf_value_get_integer(value
, val
);
333 abort(); /* tested above */
338 idmapdlog(LOG_ERR
, "Can not retrieve config/%s: %s",
339 name
, scf_strerror(scf_error()));
343 scf_value_destroy(value
);
344 scf_property_destroy(scf_prop
);
350 scf_value2string(const char *name
, scf_value_t
*value
)
352 static size_t 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()));
364 char *s
= strdup(buf
);
366 idmapdlog(LOG_ERR
, "Out of memory");
372 get_val_ds(idmap_cfg_handles_t
*handles
, const char *name
, int defport
,
376 struct addrinfo hints
;
378 ad_disc_ds_t
*servers
= NULL
;
379 scf_property_t
*scf_prop
;
382 char *host
, *portstr
;
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()));
397 value
= scf_value_create(handles
->main
);
399 idmapdlog(LOG_ERR
, "scf_value_create() failed: %s",
400 scf_strerror(scf_error()));
401 scf_property_destroy(scf_prop
);
405 iter
= scf_iter_create(handles
->main
);
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
);
414 if (scf_pg_get_property(handles
->config_pg
, name
, scf_prop
) < 0) {
415 /* this is OK: the property is just undefined */
420 if (scf_iter_property_values(iter
, scf_prop
) < 0) {
422 "scf_iter_property_values(%s) failed: %s",
423 name
, scf_strerror(scf_error()));
427 /* Workaround scf bugs -- can't reset an iteration */
429 while (scf_iter_next_value(iter
, value
) > 0)
438 scf_value_destroy(value
);
439 scf_iter_destroy(iter
);
440 scf_property_destroy(scf_prop
);
444 if ((servers
= calloc(count
+ 1, sizeof (*servers
))) == NULL
) {
445 idmapdlog(LOG_ERR
, "Out of memory");
449 (void) memset(&hints
, 0, sizeof (hints
));
450 hints
.ai_protocol
= IPPROTO_TCP
;
451 hints
.ai_socktype
= SOCK_STREAM
;
455 while (i
< count
&& scf_iter_next_value(iter
, value
) > 0) {
460 servers
[i
].priority
= 0;
461 servers
[i
].weight
= 100;
462 servers
[i
].port
= defport
;
463 if ((host
= scf_value2string(name
, value
)) == NULL
)
465 if ((portstr
= strchr(host
, ':')) != NULL
) {
467 servers
[i
].port
= strtol(portstr
,
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++)
479 if (DBG(CONFIG
, 1)) {
480 idmapdlog(LOG_INFO
, "%s host=\"\"", name
);
484 if (len
>= sizeof (servers
->host
)) {
485 idmapdlog(LOG_ERR
, "Host name too long: %s", host
);
486 idmapdlog(LOG_ERR
, "ignoring %s value", name
);
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
);
497 err
= getaddrinfo(host
, port_str
, &hints
, &ai
);
499 idmapdlog(LOG_ERR
, "No address for host: %s (%s)",
500 host
, gai_strerror(err
));
501 idmapdlog(LOG_ERR
, "ignoring %s value", name
);
505 (void) strlcpy(servers
[i
].host
, host
,
506 sizeof (servers
->host
));
507 (void) memcpy(&servers
[i
].addr
, ai
->ai_addr
, ai
->ai_addrlen
);
510 /* Added a DS to the array. */
516 if (DBG(CONFIG
, 1)) {
517 idmapdlog(LOG_INFO
, "%s is empty", name
);
527 scf_value_destroy(value
);
528 scf_iter_destroy(iter
);
529 scf_property_destroy(scf_prop
);
541 get_val_astring(idmap_cfg_handles_t
*handles
, const char *name
, char **val
)
545 scf_property_t
*scf_prop
;
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()));
554 value
= scf_value_create(handles
->main
);
556 idmapdlog(LOG_ERR
, "scf_value_create() failed: %s",
557 scf_strerror(scf_error()));
558 scf_property_destroy(scf_prop
);
564 if (scf_pg_get_property(handles
->config_pg
, name
, scf_prop
) < 0)
565 /* this is OK: the property is just undefined */
568 if (scf_property_get_value(scf_prop
, value
) < 0) {
570 "scf_property_get_value(%s) failed: %s",
571 name
, scf_strerror(scf_error()));
576 *val
= scf_value2string(name
, value
);
581 scf_value_destroy(value
);
582 scf_property_destroy(scf_prop
);
596 idmap_cfg_handles_t
*handles
,
597 scf_propertygroup_t
*pg
,
602 scf_transaction_t
*tx
= NULL
;
603 scf_transaction_entry_t
*ent
= NULL
;
605 if ((tx
= scf_transaction_create(handles
->main
)) == NULL
) {
607 "scf_transaction_create() failed: %s",
608 scf_strerror(scf_error()));
611 if ((ent
= scf_entry_create(handles
->main
)) == NULL
) {
613 "scf_entry_create() failed: %s",
614 scf_strerror(scf_error()));
619 if (scf_pg_update(pg
) == -1) {
621 "scf_pg_update(%s) failed: %s",
622 name
, scf_strerror(scf_error()));
625 if (scf_transaction_start(tx
, pg
) != 0) {
627 "scf_transaction_start(%s) failed: %s",
628 name
, scf_strerror(scf_error()));
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
) {
636 "scf_transaction_property_delete() failed:"
638 scf_strerror(scf_error()));
643 ret
= scf_transaction_commit(tx
);
646 scf_transaction_reset(tx
);
651 "scf_transaction_commit(%s) failed: %s",
652 name
, scf_strerror(scf_error()));
660 scf_entry_destroy(ent
);
662 scf_transaction_destroy(tx
);
669 idmap_cfg_handles_t
*handles
,
670 scf_propertygroup_t
*pg
,
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()));
688 for (i
= 0; i
< MAX_TRIES
; i
++) {
691 if (scf_pg_update(pg
) == -1) {
693 "scf_pg_update() failed: %s",
694 scf_strerror(scf_error()));
698 if (scf_transaction_start(tx
, pg
) == -1) {
700 "scf_transaction_start(%s) failed: %s",
701 name
, scf_strerror(scf_error()));
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) {
710 "scf_transaction_property_change_type(%s)"
712 name
, scf_strerror(scf_error()));
715 } else if (scf_error() == SCF_ERROR_NOT_FOUND
) {
716 if (scf_transaction_property_new(tx
, ent
, name
,
717 scf_value_type(value
)) < 0) {
719 "scf_transaction_property_new() failed: %s",
720 scf_strerror(scf_error()));
725 "scf_pg_get_property(%s) failed: %s",
726 name
, scf_strerror(scf_error()));
730 if (scf_entry_add_value(ent
, value
) == -1) {
732 "scf_entry_add_value() failed: %s",
733 scf_strerror(scf_error()));
737 ret
= scf_transaction_commit(tx
);
740 * Property group set in scf_transaction_start()
741 * is not the most recent. Update pg, reset tx and
744 idmapdlog(LOG_WARNING
,
745 "scf_transaction_commit(%s) failed: %s",
746 name
, scf_strerror(scf_error()));
747 scf_transaction_reset(tx
);
752 "scf_transaction_commit(%s) failed: %s",
753 name
, scf_strerror(scf_error()));
762 scf_entry_destroy(ent
);
763 scf_transaction_destroy(tx
);
764 scf_property_destroy(prop
);
770 idmap_cfg_handles_t
*handles
,
771 scf_propertygroup_t
*pg
,
775 scf_value_t
*value
= NULL
;
778 if ((value
= scf_value_create(handles
->main
)) == NULL
) {
779 idmapdlog(LOG_ERR
, "Unable to set property %s",
780 name
, scf_strerror(scf_error()));
784 scf_value_set_integer(value
, val
);
786 rc
= set_val(handles
, pg
, name
, value
);
788 scf_value_destroy(value
);
796 idmap_cfg_handles_t
*handles
,
797 scf_propertygroup_t
*pg
,
801 scf_value_t
*value
= NULL
;
804 if ((value
= scf_value_create(handles
->main
)) == NULL
) {
805 idmapdlog(LOG_ERR
, "Unable to set property %s",
806 name
, scf_strerror(scf_error()));
810 if (scf_value_set_astring(value
, val
) == -1) {
812 "scf_value_set_astring() failed: %s",
813 scf_strerror(scf_error()));
817 rc
= set_val(handles
, pg
, name
, value
);
820 scf_value_destroy(value
);
827 * This function updates a boolean value.
828 * If nothing has changed it returns 0 else 1
831 update_bool(boolean_t
*value
, boolean_t
*new, char *name
)
836 if (DBG(CONFIG
, 1)) {
837 idmapdlog(LOG_INFO
, "change %s=%s", name
,
838 *new ? "true" : "false");
846 * This function updates a uint64_t value.
847 * If nothing has changed it returns 0 else 1
850 update_uint64(uint64_t *value
, uint64_t *new, char *name
)
856 idmapdlog(LOG_INFO
, "change %s=%llu", name
, *new);
863 * This function updates a string value.
864 * If nothing has changed it returns 0 else 1
867 update_string(char **value
, char **new, char *name
)
871 if (*new == NULL
&& *value
!= NULL
)
873 else if (*new != NULL
&& *value
== NULL
)
875 else if (*new != NULL
&& *value
!= NULL
&& strcmp(*new, *value
) != 0)
881 * Note that even if unchanged we can't just return; we must free one
885 if (DBG(CONFIG
, 1) && changed
)
886 idmapdlog(LOG_INFO
, "change %s=%s", name
, CHECK_NULL(*new));
895 update_enum(int *value
, int *new, char *name
, struct enum_lookup_map
*map
)
900 if (DBG(CONFIG
, 1)) {
901 idmapdlog(LOG_INFO
, "change %s=%s", name
,
902 enum_lookup(*new, map
));
911 * This function updates a directory service structure.
912 * If nothing has changed it returns 0 else 1
915 update_dirs(ad_disc_ds_t
**value
, ad_disc_ds_t
**new, char *name
)
922 if (*value
!= NULL
&& *new != NULL
&&
923 ad_disc_compare_ds(*value
, *new) == 0) {
935 if (*value
== NULL
) {
936 /* We're unsetting this DS property */
938 idmapdlog(LOG_INFO
, "change %s=<none>", name
);
942 if (DBG(CONFIG
, 1)) {
943 /* List all the new DSs */
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
);
957 * This function updates a trusted domains structure.
958 * If nothing has changed it returns 0 else 1
961 update_trusted_domains(ad_disc_trusteddomains_t
**value
,
962 ad_disc_trusteddomains_t
**new, char *name
)
970 if (*value
!= NULL
&& *new != NULL
&&
971 ad_disc_compare_trusteddomains(*value
, *new) == 0) {
983 if (*value
== NULL
) {
984 /* We're unsetting this DS property */
986 idmapdlog(LOG_INFO
, "change %s=<none>", name
);
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
,
995 enum_lookup((*value
)[i
].direction
, trust_dir_map
));
1003 * This function updates a domains in a forest structure.
1004 * If nothing has changed it returns 0 else 1
1007 update_domains_in_forest(ad_disc_domainsinforest_t
**value
,
1008 ad_disc_domainsinforest_t
**new, char *name
)
1016 if (*value
!= NULL
&& *new != NULL
&&
1017 ad_disc_compare_domainsinforest(*value
, *new) == 0) {
1029 if (*value
== NULL
) {
1030 /* We're unsetting this DS property */
1032 idmapdlog(LOG_INFO
, "change %s=<none>", name
);
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
);
1048 free_trusted_forests(idmap_trustedforest_t
**value
, int *num_values
)
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
);
1064 compare_trusteddomainsinforest(ad_disc_domainsinforest_t
*df1
,
1065 ad_disc_domainsinforest_t
*df2
)
1072 for (i
= 0; df1
[i
].domain
[0] != '\0'; i
++)
1076 for (j
= 0; df2
[j
].domain
[0] != '\0'; j
++)
1080 if (num_df1
!= num_df2
)
1083 for (i
= 0; df1
[i
].domain
[0] != '\0'; i
++) {
1084 if (df1
[i
].trusted
) {
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) {
1104 * This function updates trusted forest structure.
1105 * If nothing has changed it returns 0 else 1
1108 update_trusted_forest(idmap_trustedforest_t
**value
, int *num_value
,
1109 idmap_trustedforest_t
**new, int *num_new
, char *name
)
1118 if (*value
!= NULL
&& *new != NULL
) {
1119 if (*num_value
!= *num_new
)
1121 for (i
= 0; i
< *num_value
; i
++) {
1123 for (j
= 0; j
< *num_new
; j
++) {
1124 if (strcmp((*value
)[i
].forest_name
,
1125 (*new)[j
].forest_name
) == 0 &&
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) {
1139 free_trusted_forests(new, num_new
);
1144 free_trusted_forests(value
, num_value
);
1146 *num_value
= *num_new
;
1150 if (*value
== NULL
) {
1151 /* We're unsetting this DS property */
1153 idmapdlog(LOG_INFO
, "change %s=<none>", name
);
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
];
1162 f
->domains_in_forest
[j
].domain
[0] != '\0';
1164 /* List trusted Domains in the forest. */
1165 if (f
->domains_in_forest
[j
].trusted
)
1167 "change %s=%s domain=%s",
1168 name
, f
->forest_name
,
1169 f
->domains_in_forest
[j
].domain
);
1171 /* List the hosts */
1173 f
->global_catalog
[j
].host
[0] != '\0';
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
);
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
1201 * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON.
1205 pfroute_event_is_interesting(int rt_sock
)
1208 int64_t msg
[2048 / 8];
1209 struct rt_msghdr
*rtm
;
1210 boolean_t is_interesting
= B_FALSE
;
1213 if ((nbytes
= read(rt_sock
, msg
, sizeof (msg
))) <= 0)
1215 rtm
= (struct rt_msghdr
*)msg
;
1216 if (rtm
->rtm_version
!= RTM_VERSION
)
1218 if (nbytes
< rtm
->rtm_msglen
)
1220 switch (rtm
->rtm_type
) {
1224 is_interesting
= B_TRUE
;
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.
1243 wait_for_event(struct timespec
*timeoutp
)
1247 (void) memset(&pe
, 0, sizeof (pe
));
1248 if (port_get(idmapd_ev_port
, &pe
, timeoutp
) != 0) {
1251 return (EVENT_NOTHING
);
1254 return (EVENT_TIMEOUT
);
1256 /* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */
1257 idmapdlog(LOG_ERR
, "Event port failed: %s",
1265 switch (pe
.portev_source
) {
1268 * This isn't documented, but seems to be what you get if
1269 * the timeout is zero seconds and there are no events
1272 return (EVENT_TIMEOUT
);
1274 case PORT_SOURCE_USER
:
1275 switch (pe
.portev_events
) {
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:
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",
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
);
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. */
1322 return (EVENT_NOTHING
);
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
;
1334 struct timespec timeout
;
1335 struct timespec
*timeoutp
;
1339 (void) ad_disc_SubnetChanged(ad_ctx
);
1341 rc
= idmap_cfg_load(_idmapdstate
.cfg
, flags
);
1343 idmapdlog(LOG_ERR
, "Fatal errors while reading "
1346 } else if (rc
== -1) {
1347 idmapdlog(LOG_WARNING
,
1348 "Errors re-loading configuration may cause AD "
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
;
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
)
1366 ttl
= ad_disc_get_TTL(ad_ctx
);
1370 max_ttl
= (int)pgcfg
->rediscovery_interval
;
1373 if (ttl
< MIN_REDISCOVERY_INTERVAL
)
1374 ttl
= MIN_REDISCOVERY_INTERVAL
;
1375 timeout
.tv_sec
= ttl
;
1376 timeout
.tv_nsec
= 0;
1377 timeoutp
= &timeout
;
1381 idmapdlog(LOG_DEBUG
,
1382 "_cfg_update_thread waiting");
1384 switch (wait_for_event(timeoutp
)) {
1387 idmapdlog(LOG_DEBUG
, "Boring event.");
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");
1405 idmapdlog(LOG_DEBUG
, "poked");
1409 idmapdlog(LOG_DEBUG
, "kicked");
1410 flags
|= CFG_FORGET_DC
;
1414 idmapdlog(LOG_DEBUG
, "TTL expired");
1417 /* Already logged to DEBUG */
1420 /* An interesting event! */
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...
1434 idmap_cfg_start_updates(void)
1436 if ((idmapd_ev_port
= port_create()) < 0) {
1437 idmapdlog(LOG_ERR
, "Failed to create event port: %s",
1442 if ((rt_sock
= socket(PF_ROUTE
, SOCK_RAW
, 0)) < 0) {
1443 idmapdlog(LOG_ERR
, "Failed to open routing socket: %s",
1445 (void) close(idmapd_ev_port
);
1449 if (fcntl(rt_sock
, F_SETFL
, O_NDELAY
|O_NONBLOCK
) < 0) {
1450 idmapdlog(LOG_ERR
, "Failed to set routing socket flags: %s",
1452 (void) close(rt_sock
);
1453 (void) close(idmapd_ev_port
);
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
);
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",
1470 (void) port_dissociate(idmapd_ev_port
, PORT_SOURCE_FD
, rt_sock
);
1471 (void) close(rt_sock
);
1472 (void) close(idmapd_ev_port
);
1480 * Reject attribute names with invalid characters.
1484 valid_ldap_attr(const char *attr
) {
1485 for (; *attr
; attr
++) {
1486 if (!isalnum(*attr
) && *attr
!= '-' &&
1487 *attr
!= '_' && *attr
!= '.' && *attr
!= ';')
1496 idmap_cfg_handles_t
*handles
,
1497 enum idmapd_debug item
,
1502 if (item
< 0 || item
> IDMAPD_DEBUG_MAX
)
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
;
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
1539 idmap_cfg_load_smf(idmap_cfg_handles_t
*handles
, idmap_pg_config_t
*pgcfg
,
1547 if (scf_pg_update(handles
->config_pg
) < 0) {
1548 idmapdlog(LOG_ERR
, "scf_pg_update() failed: %s",
1549 scf_strerror(scf_error()));
1553 if (scf_pg_update(handles
->debug_pg
) < 0) {
1554 idmapdlog(LOG_ERR
, "scf_pg_update() failed: %s",
1555 scf_strerror(scf_error()));
1559 check_smf_debug_mode(handles
);
1561 rc
= get_val_bool(handles
, "unresolvable_sid_mapping",
1562 &pgcfg
->eph_map_unres_sids
, B_TRUE
);
1566 rc
= get_val_bool(handles
, "use_ads",
1567 &pgcfg
->use_ads
, B_TRUE
);
1571 rc
= get_val_bool(handles
, "use_lsa",
1572 &pgcfg
->use_lsa
, B_TRUE
);
1576 rc
= get_val_bool(handles
, "disable_cross_forest_trusts",
1577 &pgcfg
->disable_cross_forest_trusts
, B_TRUE
);
1581 rc
= get_val_astring(handles
, "directory_based_mapping", &s
);
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
;
1591 pgcfg
->directory_based_mapping
= DIRECTORY_MAPPING_NONE
;
1593 "config/directory_based_mapping: invalid value \"%s\" ignored",
1599 rc
= get_val_int(handles
, "list_size_limit",
1600 &pgcfg
->list_size_limit
, SCF_TYPE_COUNT
);
1604 rc
= get_val_int(handles
, "id_cache_timeout",
1605 &pgcfg
->id_cache_timeout
, SCF_TYPE_COUNT
);
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
);
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
);
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
);
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
);
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.
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
);
1658 } else if (s
== NULL
|| s
[0] == '\0') {
1664 if (uuid_parse(s
, u
) != 0) {
1666 "config/domain_guid: invalid value \"%s\" ignored", s
);
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
);
1679 if (pgcfg
->machine_uuid
== NULL
) {
1680 /* If machine_uuid not configured, generate one */
1681 if (generate_machine_uuid(&pgcfg
->machine_uuid
) < 0)
1683 rc
= set_val_astring(handles
, handles
->config_pg
,
1684 "machine_uuid", pgcfg
->machine_uuid
);
1689 rc
= get_val_astring(handles
, "machine_sid", &pgcfg
->machine_sid
);
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)
1700 rc
= set_val_astring(handles
, handles
->config_pg
,
1701 "machine_sid", pgcfg
->machine_sid
);
1706 rc
= get_val_ds(handles
, "domain_controller", 389,
1707 &pgcfg
->domain_controller
);
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
);
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
);
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
);
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
);
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
)
1755 rc
= get_val_astring(handles
, "ad_unixuser_attr",
1756 &pgcfg
->ad_unixuser_attr
);
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
);
1766 rc
= get_val_astring(handles
, "ad_unixgroup_attr",
1767 &pgcfg
->ad_unixgroup_attr
);
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
);
1777 rc
= get_val_astring(handles
, "nldap_winname_attr",
1778 &pgcfg
->nldap_winname_attr
);
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
);
1787 if (pgcfg
->ad_unixuser_attr
== NULL
&&
1788 pgcfg
->ad_unixgroup_attr
== NULL
&&
1789 pgcfg
->nldap_winname_attr
== NULL
) {
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)");
1803 log_if_unable(const void *val
, const char *what
)
1806 idmapdlog(LOG_DEBUG
, "unable to discover %s", what
);
1812 discover_trusted_domains(idmap_pg_config_t
*pgcfg
, ad_disc_t ad_ctx
)
1814 ad_disc_t trusted_ctx
;
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
++)
1836 num_trusteddomains
= i
;
1838 trustedforests
= calloc(num_trusteddomains
,
1839 sizeof (idmap_trustedforest_t
));
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
,
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",
1855 ad_disc_fini(trusted_ctx
);
1859 if (strcasecmp(forestname
, pgcfg
->forest_name
) == 0) {
1861 * Ignore the domain as it is part of
1862 * the primary forest
1865 ad_disc_fini(trusted_ctx
);
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
;
1876 trustedforests
[k
].domains_in_forest
;
1881 /* Mark the domain as trusted */
1883 domainsinforest
[l
].domain
[0] != '\0'; l
++) {
1884 if (domain_eq(trusteddomain
,
1885 domainsinforest
[l
].domain
)) {
1886 domainsinforest
[l
].trusted
=
1892 ad_disc_fini(trusted_ctx
);
1897 * Get the Global Catalog and the domains in
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",
1911 ad_disc_fini(trusted_ctx
);
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",
1923 free(globalcatalog
);
1925 ad_disc_fini(trusted_ctx
);
1929 trustedforests
[j
].forest_name
= forestname
;
1930 trustedforests
[j
].global_catalog
= globalcatalog
;
1931 trustedforests
[j
].domains_in_forest
= domainsinforest
;
1933 /* Mark the domain as trusted */
1934 for (l
= 0; domainsinforest
[l
].domain
[0] != '\0';
1936 if (domain_eq(trusteddomain
,
1937 domainsinforest
[l
].domain
)) {
1938 domainsinforest
[l
].trusted
= TRUE
;
1942 ad_disc_fini(trusted_ctx
);
1945 pgcfg
->num_trusted_forests
= j
;
1946 pgcfg
->trusted_forests
= trustedforests
;
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.
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
;
1969 idmapdlog(LOG_DEBUG
, "Running domain discovery.");
1971 (void) unlink(IDMAP_CACHEDIR
"/discovery.log");
1972 status_fp
= fopen(IDMAP_CACHEDIR
"/discovery.log", "w");
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.");
1981 (void) fprintf(status_fp
, "(no domain name)\n");
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
));
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");
2021 ad_disc_set_StatusFP(ad_ctx
, NULL
);
2022 (void) fclose(status_fp
);
2027 idmapdlog(LOG_DEBUG
, "Domain discovery done.");
2030 * Log when this took more than 15 sec.
2033 if (t1
> (t0
+ 15)) {
2034 idmapdlog(LOG_NOTICE
, "Domain discovery took %d sec.",
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.
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
;
2063 idmapdlog(LOG_DEBUG
, "Running forest discovery.");
2065 status_fp
= fopen(IDMAP_CACHEDIR
"/discovery.log", "a");
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. */
2091 ad_disc_set_StatusFP(ad_ctx
, NULL
);
2092 (void) fclose(status_fp
);
2097 idmapdlog(LOG_DEBUG
, "Forest discovery done.");
2100 * Log when this took more than 30 sec.
2103 if (t1
> (t0
+ 30)) {
2104 idmapdlog(LOG_NOTICE
, "Forest discovery took %d sec.",
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:
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
2129 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
2133 idmap_cfg_load(idmap_cfg_t
*cfg
, int flags
)
2135 const ad_disc_t ad_ctx
= cfg
->handles
.ad_ctx
;
2140 int ad_reload_required
= 0;
2141 idmap_pg_config_t new_pgcfg
, *live_pgcfg
;
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)
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
);
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
);
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
);
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")) {
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)) {
2275 idmapdlog(LOG_NOTICE
, "Configuration changed");
2277 idmapdlog(LOG_NOTICE
, "Configuration unchanged");
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
);
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")) {
2310 ad_reload_required
= TRUE
;
2313 if (update_trusted_domains(&live_pgcfg
->trusted_domains
,
2314 &new_pgcfg
.trusted_domains
, "trusted_domains")) {
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")) {
2325 if (live_pgcfg
->trusted_forests
!= NULL
)
2326 ad_reload_required
= TRUE
;
2329 if (DBG(CONFIG
, 1)) {
2331 idmapdlog(LOG_NOTICE
, "Configuration changed");
2333 idmapdlog(LOG_NOTICE
, "Configuration unchanged");
2338 if (ad_reload_required
)
2341 idmap_cfg_unload(&new_pgcfg
);
2344 (void) pthread_mutex_unlock(&cfg
->handles
.mutex
);
2349 return ((errors
== 0) ? 0 : -1);
2358 idmap_cfg_handles_t
*handles
;
2360 /* First the smf repository handles: */
2361 idmap_cfg_t
*cfg
= calloc(1, sizeof (idmap_cfg_t
));
2363 idmapdlog(LOG_ERR
, "Out of memory");
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()));
2376 if (scf_handle_bind(handles
->main
) < 0) {
2377 idmapdlog(LOG_ERR
, "scf_handle_bind() failed: %s",
2378 scf_strerror(scf_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()));
2391 if (scf_handle_decode_fmri(handles
->main
,
2392 FMRI_BASE
"/:properties/" CONFIG_PG
,
2394 handles
->service
, /* service */
2395 handles
->instance
, /* instance */
2396 handles
->config_pg
, /* pg */
2398 SCF_DECODE_FMRI_EXACT
) < 0) {
2399 idmapdlog(LOG_ERR
, "scf_handle_decode_fmri() failed: %s",
2400 scf_strerror(scf_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()));
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
)
2421 (void) idmap_cfg_fini(cfg
);
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
);
2504 idmap_cfg_poke_updates(void)
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");
2520 idmapdlog(LOG_DEBUG
, "port send poke");
2521 (void) port_send(idmapd_ev_port
, POKE_AUTO_DISCOVERY
, NULL
);
2526 idmap_cfg_force_rediscovery(void)
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");
2542 idmapdlog(LOG_DEBUG
, "port send kick");
2543 (void) port_send(idmapd_ev_port
, KICK_AUTO_DISCOVERY
, NULL
);
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.
2564 upgrade_debug(idmap_cfg_handles_t
*handles
)
2566 boolean_t debug_present
;
2567 const char DEBUG_PROP
[] = "debug";
2570 rc
= prop_exists(handles
, DEBUG_PROP
, &debug_present
);
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);
2585 rc
= set_val_integer(handles
, handles
->debug_pg
, "discovery", 1);
2589 rc
= del_val(handles
, handles
->config_pg
, DEBUG_PROP
);
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
2604 * set the new based on the old, and note it
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";
2616 rc
= prop_exists(handles
, DS_NAME_MAPPING_ENABLED
,
2617 &legacy_ds_name_mapping_present
);
2622 if (!legacy_ds_name_mapping_present
)
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
);
2632 char *legacy_bool_string
;
2633 if (legacy_ds_name_mapping_enabled
) {
2634 legacy_mode
= "name";
2635 legacy_bool_string
= "true";
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
);
2647 if (directory_based_mapping
== NULL
) {
2649 "Upgrading old %s=%s setting\n"
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
);
2658 boolean_t new_name_mapping
;
2659 if (strcasecmp(directory_based_mapping
, "name") == 0)
2660 new_name_mapping
= B_TRUE
;
2662 new_name_mapping
= B_FALSE
;
2664 if (legacy_ds_name_mapping_enabled
== new_name_mapping
) {
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
);
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
);
2688 * Do whatever is necessary to upgrade idmap's configuration before
2692 idmap_cfg_upgrade(idmap_cfg_t
*cfg
)
2696 rc
= upgrade_directory_mapping(&cfg
->handles
);
2700 rc
= upgrade_debug(&cfg
->handles
);
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.
2715 idmapd_set_krb5_realm(char *domain
)
2717 static char realm
[MAXHOSTNAMELEN
];
2721 if (domain
== NULL
) {
2722 (void) unsetenv("KRB5_DEFAULT_REALM");
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);