1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2019 Nexenta Systems, Inc. All rights reserved.
24 * Copyright 2023 RackTop Systems, Inc.
25 */
26
27
28 /*
29 * Config routines common to idmap(8) and idmapd(8)
30 */
31
32 #include <stdlib.h>
33 #include <strings.h>
34 #include <libintl.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <stdio.h>
38 #include <stdarg.h>
39 #include <uuid/uuid.h>
40 #include <pthread.h>
41 #include <port.h>
42 #include <sys/socket.h>
43 #include <net/route.h>
44 #include <sys/u8_textprep.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <netdb.h>
48 #include <note.h>
49 #include <limits.h>
50 #include "idmapd.h"
51 #include "addisc.h"
52
53 #define MACHINE_SID_LEN (9 + 3 * 11)
54 #define FMRI_BASE "svc:/system/idmap"
55 #define CONFIG_PG "config"
56 #define DEBUG_PG "debug"
57 #define RECONFIGURE 1
58 #define POKE_AUTO_DISCOVERY 2
59 #define KICK_AUTO_DISCOVERY 3
60
61 /*
62 * Default cache timeouts. Can override via svccfg
63 * config/id_cache_timeout = count: seconds
64 * config/name_cache_timeout = count: seconds
65 */
66 #define ID_CACHE_TMO_DEFAULT 86400
67 #define NAME_CACHE_TMO_DEFAULT 604800
68
69 /*
70 * Default maximum time between rediscovery runs.
71 * config/rediscovery_interval = count: seconds
72 */
73 #define REDISCOVERY_INTERVAL_DEFAULT 3600
74
75 /*
76 * Minimum time between rediscovery runs, in case adutils gives us a
77 * really short TTL (which it never should, but be defensive)
78 * (not configurable) seconds.
79 */
80 #define MIN_REDISCOVERY_INTERVAL 60
81
82 /*
83 * Max number of concurrent door calls
84 */
85 #define MAX_THREADS_DEFAULT 40
86
87 /*
88 * Number of failed discovery attempts before we mark the service degraded.
89 */
90 #define DISCOVERY_RETRY_DEGRADE_CUTOFF 6
91
92 /*
93 * Default maximum time between discovery attempts when we don't have a DC.
94 * config/discovery_retry_max_delay = count: seconds
95 */
96 #define DISCOVERY_RETRY_MAX_DELAY_DEFAULT 30
97
98 /*
99 * Initial retry delay when discovery fails. Doubles on every failure.
100 */
101 #define DISCOVERY_RETRY_INITIAL_DELAY 1
102
103 enum event_type {
104 EVENT_NOTHING, /* Woke up for no good reason */
105 EVENT_TIMEOUT, /* Timeout expired */
106 EVENT_ROUTING, /* An interesting routing event happened */
107 EVENT_POKED, /* Requested from degrade_svc() */
108 EVENT_KICKED, /* Force rediscovery, i.e. DC failed. */
109 EVENT_REFRESH, /* SMF refresh */
110 };
111
112
113 static void idmapd_set_krb5_realm(char *);
114
115 static pthread_t update_thread_handle = 0;
116
117 static int idmapd_ev_port = -1;
118 static int rt_sock = -1;
119
120 struct enum_lookup_map directory_mapping_map[] = {
121 { DIRECTORY_MAPPING_NONE, "none" },
122 { DIRECTORY_MAPPING_NAME, "name" },
123 { DIRECTORY_MAPPING_IDMU, "idmu" },
124 { 0, NULL },
125 };
126
127 struct enum_lookup_map trust_dir_map[] = {
128 { 1, "they trust us" },
129 { 2, "we trust them" },
130 { 3, "we trust each other" },
131 { 0, NULL },
132 };
133
134 static int
generate_machine_uuid(char ** machine_uuid)135 generate_machine_uuid(char **machine_uuid)
136 {
137 uuid_t uu;
138
139 *machine_uuid = calloc(1, UUID_PRINTABLE_STRING_LENGTH + 1);
140 if (*machine_uuid == NULL) {
141 idmapdlog(LOG_ERR, "Out of memory");
142 return (-1);
143 }
144
145 uuid_clear(uu);
146 uuid_generate_time(uu);
147 uuid_unparse(uu, *machine_uuid);
148
149 return (0);
150 }
151
152 static int
generate_machine_sid(char ** machine_sid,char * machine_uuid)153 generate_machine_sid(char **machine_sid, char *machine_uuid)
154 {
155 union {
156 uuid_t uu;
157 uint32_t v[4];
158 } uv;
159 int len;
160
161 /*
162 * Split the 128-bit machine UUID into three 32-bit values
163 * we'll use as the "sub-authorities" of the machine SID.
164 * The machine_sid will have the form S-1-5-21-J-K-L
165 * (that's four sub-authorities altogether) where:
166 * J = last 4 bytes of node_addr,
167 * K = time_mid, time_hi_and_version
168 * L = time_low
169 * (see struct uuid)
170 */
171
172 (void) memset(&uv, 0, sizeof (uv));
173 (void) uuid_parse(machine_uuid, uv.uu);
174
175 len = asprintf(machine_sid, "S-1-5-21-%u-%u-%u",
176 uv.v[3], uv.v[0], uv.v[1]);
177
178 if (len == -1 || *machine_sid == NULL) {
179 idmapdlog(LOG_ERR, "Out of memory");
180 return (-1);
181 }
182
183 return (0);
184 }
185
186
187 /* In the case of error, exists is set to FALSE anyway */
188 static int
prop_exists(idmap_cfg_handles_t * handles,const char * name,boolean_t * exists)189 prop_exists(idmap_cfg_handles_t *handles, const char *name, boolean_t *exists)
190 {
191
192 scf_property_t *scf_prop;
193
194 *exists = B_FALSE;
195
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 return (-1);
201 }
202
203 if (scf_pg_get_property(handles->config_pg, name, scf_prop) == 0)
204 *exists = B_TRUE;
205
206 scf_property_destroy(scf_prop);
207
208 return (0);
209 }
210
211 static int
get_debug(idmap_cfg_handles_t * handles,const char * name)212 get_debug(idmap_cfg_handles_t *handles, const char *name)
213 {
214 int64_t i64 = 0;
215
216 scf_property_t *scf_prop;
217 scf_value_t *value;
218
219 scf_prop = scf_property_create(handles->main);
220 if (scf_prop == NULL) {
221 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
222 scf_strerror(scf_error()));
223 abort();
224 }
225 value = scf_value_create(handles->main);
226 if (value == NULL) {
227 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
228 scf_strerror(scf_error()));
229 abort();
230 }
231
232 if (scf_pg_get_property(handles->debug_pg, name, scf_prop) < 0) {
233 /* this is OK: the property is just undefined */
234 goto destruction;
235 }
236
237
238 if (scf_property_get_value(scf_prop, value) < 0) {
239 /* It is still OK when a property doesn't have any value */
240 goto destruction;
241 }
242
243 if (scf_value_get_integer(value, &i64) != 0) {
244 idmapdlog(LOG_ERR, "Can not retrieve %s/%s: %s",
245 DEBUG_PG, name, scf_strerror(scf_error()));
246 abort();
247 }
248
249 destruction:
250 scf_value_destroy(value);
251 scf_property_destroy(scf_prop);
252
253 return ((int)i64);
254 }
255
256 static int
get_val_bool(idmap_cfg_handles_t * handles,const char * name,boolean_t * val,boolean_t default_val)257 get_val_bool(idmap_cfg_handles_t *handles, const char *name,
258 boolean_t *val, boolean_t default_val)
259 {
260 int rc = 0;
261
262 scf_property_t *scf_prop;
263 scf_value_t *value;
264
265 *val = default_val;
266
267 scf_prop = scf_property_create(handles->main);
268 if (scf_prop == NULL) {
269 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
270 scf_strerror(scf_error()));
271 return (-1);
272 }
273 value = scf_value_create(handles->main);
274 if (value == NULL) {
275 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
276 scf_strerror(scf_error()));
277 scf_property_destroy(scf_prop);
278 return (-1);
279 }
280
281 /* It is OK if the property is undefined */
282 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
283 goto destruction;
284
285
286 /* It is still OK when a property doesn't have any value */
287 if (scf_property_get_value(scf_prop, value) < 0)
288 goto destruction;
289
290 uint8_t b;
291 rc = scf_value_get_boolean(value, &b);
292
293 if (rc == 0)
294 *val = (boolean_t)b;
295
296 destruction:
297 scf_value_destroy(value);
298 scf_property_destroy(scf_prop);
299
300 return (rc);
301 }
302
303 static int
get_val_int(idmap_cfg_handles_t * handles,const char * name,void * val,scf_type_t type)304 get_val_int(idmap_cfg_handles_t *handles, const char *name,
305 void *val, scf_type_t type)
306 {
307 int rc = 0;
308
309 scf_property_t *scf_prop;
310 scf_value_t *value;
311
312 switch (type) {
313 case SCF_TYPE_COUNT:
314 *(uint64_t *)val = 0;
315 break;
316 case SCF_TYPE_INTEGER:
317 *(int64_t *)val = 0;
318 break;
319 default:
320 idmapdlog(LOG_ERR, "Invalid scf integer type (%d)",
321 type);
322 abort();
323 }
324
325 scf_prop = scf_property_create(handles->main);
326 if (scf_prop == NULL) {
327 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
328 scf_strerror(scf_error()));
329 return (-1);
330 }
331 value = scf_value_create(handles->main);
332 if (value == NULL) {
333 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
334 scf_strerror(scf_error()));
335 scf_property_destroy(scf_prop);
336 return (-1);
337 }
338
339 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
340 /* this is OK: the property is just undefined */
341 goto destruction;
342
343
344 if (scf_property_get_value(scf_prop, value) < 0)
345 /* It is still OK when a property doesn't have any value */
346 goto destruction;
347
348 switch (type) {
349 case SCF_TYPE_COUNT:
350 rc = scf_value_get_count(value, val);
351 break;
352 case SCF_TYPE_INTEGER:
353 rc = scf_value_get_integer(value, val);
354 break;
355 default:
356 abort(); /* tested above */
357 /* NOTREACHED */
358 }
359
360 if (rc != 0) {
361 idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s",
362 name, scf_strerror(scf_error()));
363 }
364
365 destruction:
366 scf_value_destroy(value);
367 scf_property_destroy(scf_prop);
368
369 return (rc);
370 }
371
372 static char *
scf_value2string(const char * name,scf_value_t * value)373 scf_value2string(const char *name, scf_value_t *value)
374 {
375 static size_t max_val = 0;
376
377 if (max_val == 0)
378 max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
379
380 char buf[max_val + 1];
381 if (scf_value_get_astring(value, buf, max_val + 1) < 0) {
382 idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s",
383 name, scf_strerror(scf_error()));
384 return (NULL);
385 }
386
387 char *s = strdup(buf);
388 if (s == NULL)
389 idmapdlog(LOG_ERR, "Out of memory");
390
391 return (s);
392 }
393
394 /*
395 * Load a domain server property. These are multi-value string properties.
396 * We'll later map these to an ad_disc_ds_t, which includes looking up
397 * the name in DNS, so don't do that before startup completes.
398 */
399 static int
get_val_ds(idmap_cfg_handles_t * handles,const char * name,char *** val)400 get_val_ds(idmap_cfg_handles_t *handles, const char *name, char ***val)
401 {
402 scf_property_t *scf_prop;
403 scf_value_t *value;
404 scf_iter_t *iter;
405 char *host, **servers = NULL;
406 int len, i;
407 int count = 0;
408 int rc = -1;
409
410 *val = NULL;
411
412 restart:
413 scf_prop = scf_property_create(handles->main);
414 if (scf_prop == NULL) {
415 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
416 scf_strerror(scf_error()));
417 return (-1);
418 }
419
420 value = scf_value_create(handles->main);
421 if (value == NULL) {
422 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
423 scf_strerror(scf_error()));
424 scf_property_destroy(scf_prop);
425 return (-1);
426 }
427
428 iter = scf_iter_create(handles->main);
429 if (iter == NULL) {
430 idmapdlog(LOG_ERR, "scf_iter_create() failed: %s",
431 scf_strerror(scf_error()));
432 scf_value_destroy(value);
433 scf_property_destroy(scf_prop);
434 return (-1);
435 }
436
437 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) {
438 /* this is OK: the property is just undefined */
439 rc = 0;
440 goto destruction;
441 }
442
443 if (scf_iter_property_values(iter, scf_prop) < 0) {
444 idmapdlog(LOG_ERR,
445 "scf_iter_property_values(%s) failed: %s",
446 name, scf_strerror(scf_error()));
447 goto destruction;
448 }
449
450 /* Workaround scf bugs -- can't reset an iteration */
451 if (count == 0) {
452 while (scf_iter_next_value(iter, value) > 0)
453 count++;
454
455 if (count == 0) {
456 /* no values */
457 rc = 0;
458 goto destruction;
459 }
460
461 scf_value_destroy(value);
462 scf_iter_destroy(iter);
463 scf_property_destroy(scf_prop);
464 goto restart;
465 }
466
467 if ((servers = calloc(count + 1, sizeof (*servers))) == NULL) {
468 idmapdlog(LOG_ERR, "Out of memory");
469 goto destruction;
470 }
471
472 i = 0;
473 while (i < count && scf_iter_next_value(iter, value) > 0) {
474 if ((host = scf_value2string(name, value)) == NULL)
475 continue;
476
477 /*
478 * Ignore this server if the hostname is too long
479 * or empty (continue without i++)
480 */
481 len = strlen(host);
482 if (len == 0) {
483 if (DBG(CONFIG, 1)) {
484 idmapdlog(LOG_INFO, "%s host=\"\"", name);
485 }
486 continue;
487 }
488 if (len >= AD_DISC_MAXHOSTNAME) {
489 idmapdlog(LOG_ERR, "Host name too long: %s", host);
490 idmapdlog(LOG_ERR, "ignoring %s value", name);
491 continue;
492 }
493
494 /* Add a DS to the array. */
495 servers[i++] = host;
496 }
497
498 if (i == 0) {
499 if (DBG(CONFIG, 1)) {
500 idmapdlog(LOG_INFO, "%s is empty", name);
501 }
502 free(servers);
503 servers = NULL;
504 }
505 *val = servers;
506
507 rc = 0;
508
509 destruction:
510 scf_value_destroy(value);
511 scf_iter_destroy(iter);
512 scf_property_destroy(scf_prop);
513
514 if (rc < 0) {
515 if (servers)
516 free(servers);
517 *val = NULL;
518 }
519
520 return (rc);
521 }
522
523 static int
resolve_ds_addr(idmap_cfg_handles_t * handles,const char * name,int defport,char ** ds,ad_disc_ds_t ** val)524 resolve_ds_addr(idmap_cfg_handles_t *handles, const char *name, int defport,
525 char **ds, ad_disc_ds_t **val)
526 {
527 struct addrinfo hints = {
528 .ai_protocol = IPPROTO_TCP,
529 .ai_socktype = SOCK_STREAM
530 };
531 struct addrinfo *ai;
532 ad_disc_ds_t *servers = NULL;
533 int err, i, num_ds = 0;
534
535 *val = NULL;
536
537 if (ds == NULL || ds[0] == NULL) {
538 if (DBG(CONFIG, 1))
539 idmapdlog(LOG_INFO, "%s is empty", name);
540 return (0);
541 }
542
543 for (i = 0; ds[i] != NULL; i++)
544 num_ds++;
545
546 if ((servers = calloc(num_ds + 1, sizeof (*servers))) == NULL) {
547 idmapdlog(LOG_ERR, "Out of memory");
548 return (-1);
549 }
550
551 i = 0;
552 while (i < num_ds && *ds != NULL) {
553 char port_str[8];
554 char *pport;
555 const char *host = *ds++;
556
557 servers[i].priority = 0;
558 servers[i].weight = 100;
559 servers[i].port = defport;
560
561 if ((pport = strchr(host, ':')) != NULL) {
562 *pport++ = '\0';
563 servers[i].port = strtol(pport,
564 (char **)NULL, 10);
565 if (servers[i].port == 0)
566 servers[i].port = defport;
567 }
568
569 /*
570 * Get the host address. If we can't, then
571 * log an error and skip this host.
572 */
573 if (DBG(CONFIG, 2))
574 idmapdlog(LOG_INFO, "%s: lookup %s:%d",
575 name, host, servers[i].port);
576
577 (void) snprintf(port_str, sizeof (port_str),
578 "%d", servers[i].port);
579 ai = NULL;
580 err = getaddrinfo(host, port_str, &hints, &ai);
581 if (err != 0) {
582 idmapdlog(LOG_ERR,
583 "%s: No address for host: %s (%s); skipping host",
584 name, host, gai_strerror(err));
585 continue;
586 }
587
588 (void) strlcpy(servers[i].host, host,
589 sizeof (servers->host));
590 (void) memcpy(&servers[i].addr, ai->ai_addr, ai->ai_addrlen);
591 freeaddrinfo(ai);
592
593 /* Added a DS to the array. */
594 i++;
595 }
596
597 if (i == 0) {
598 if (DBG(CONFIG, 1)) {
599 idmapdlog(LOG_INFO, "No valid values in %s", name);
600 }
601 free(servers);
602 servers = NULL;
603 }
604 *val = servers;
605
606 return (0);
607 }
608
609 static int
get_val_astring(idmap_cfg_handles_t * handles,const char * name,char ** val)610 get_val_astring(idmap_cfg_handles_t *handles, const char *name, char **val)
611 {
612 int rc = 0;
613
614 scf_property_t *scf_prop;
615 scf_value_t *value;
616
617 scf_prop = scf_property_create(handles->main);
618 if (scf_prop == NULL) {
619 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
620 scf_strerror(scf_error()));
621 return (-1);
622 }
623 value = scf_value_create(handles->main);
624 if (value == NULL) {
625 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
626 scf_strerror(scf_error()));
627 scf_property_destroy(scf_prop);
628 return (-1);
629 }
630
631 *val = NULL;
632
633 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
634 /* this is OK: the property is just undefined */
635 goto destruction;
636
637 if (scf_property_get_value(scf_prop, value) < 0) {
638 idmapdlog(LOG_ERR,
639 "scf_property_get_value(%s) failed: %s",
640 name, scf_strerror(scf_error()));
641 rc = -1;
642 goto destruction;
643 }
644
645 *val = scf_value2string(name, value);
646 if (*val == NULL)
647 rc = -1;
648
649 destruction:
650 scf_value_destroy(value);
651 scf_property_destroy(scf_prop);
652
653 if (rc < 0) {
654 if (*val)
655 free(*val);
656 *val = NULL;
657 }
658
659 return (rc);
660 }
661
662
663 static int
del_val(idmap_cfg_handles_t * handles,scf_propertygroup_t * pg,const char * name)664 del_val(
665 idmap_cfg_handles_t *handles,
666 scf_propertygroup_t *pg,
667 const char *name)
668 {
669 int rc = -1;
670 int ret;
671 scf_transaction_t *tx = NULL;
672 scf_transaction_entry_t *ent = NULL;
673
674 if ((tx = scf_transaction_create(handles->main)) == NULL) {
675 idmapdlog(LOG_ERR,
676 "scf_transaction_create() failed: %s",
677 scf_strerror(scf_error()));
678 goto destruction;
679 }
680 if ((ent = scf_entry_create(handles->main)) == NULL) {
681 idmapdlog(LOG_ERR,
682 "scf_entry_create() failed: %s",
683 scf_strerror(scf_error()));
684 goto destruction;
685 }
686
687 do {
688 if (scf_pg_update(pg) == -1) {
689 idmapdlog(LOG_ERR,
690 "scf_pg_update(%s) failed: %s",
691 name, scf_strerror(scf_error()));
692 goto destruction;
693 }
694 if (scf_transaction_start(tx, pg) != 0) {
695 idmapdlog(LOG_ERR,
696 "scf_transaction_start(%s) failed: %s",
697 name, scf_strerror(scf_error()));
698 goto destruction;
699 }
700
701 if (scf_transaction_property_delete(tx, ent, name) != 0) {
702 /* Don't complain if it already doesn't exist. */
703 if (scf_error() != SCF_ERROR_NOT_FOUND) {
704 idmapdlog(LOG_ERR,
705 "scf_transaction_property_delete() failed:"
706 " %s",
707 scf_strerror(scf_error()));
708 }
709 goto destruction;
710 }
711
712 ret = scf_transaction_commit(tx);
713
714 if (ret == 0)
715 scf_transaction_reset(tx);
716 } while (ret == 0);
717
718 if (ret == -1) {
719 idmapdlog(LOG_ERR,
720 "scf_transaction_commit(%s) failed: %s",
721 name, scf_strerror(scf_error()));
722 goto destruction;
723 }
724
725 rc = 0;
726
727 destruction:
728 if (ent != NULL)
729 scf_entry_destroy(ent);
730 if (tx != NULL)
731 scf_transaction_destroy(tx);
732 return (rc);
733 }
734
735
736 static int
set_val(idmap_cfg_handles_t * handles,scf_propertygroup_t * pg,const char * name,scf_value_t * value)737 set_val(
738 idmap_cfg_handles_t *handles,
739 scf_propertygroup_t *pg,
740 const char *name,
741 scf_value_t *value)
742 {
743 int rc = -1;
744 int i;
745 scf_property_t *prop = NULL;
746 scf_transaction_t *tx = NULL;
747 scf_transaction_entry_t *ent = NULL;
748
749 if ((prop = scf_property_create(handles->main)) == NULL ||
750 (tx = scf_transaction_create(handles->main)) == NULL ||
751 (ent = scf_entry_create(handles->main)) == NULL) {
752 idmapdlog(LOG_ERR, "Unable to set property %s",
753 name, scf_strerror(scf_error()));
754 goto destruction;
755 }
756
757 for (i = 0; i < MAX_TRIES; i++) {
758 int ret;
759
760 if (scf_pg_update(pg) == -1) {
761 idmapdlog(LOG_ERR,
762 "scf_pg_update() failed: %s",
763 scf_strerror(scf_error()));
764 goto destruction;
765 }
766
767 if (scf_transaction_start(tx, pg) == -1) {
768 idmapdlog(LOG_ERR,
769 "scf_transaction_start(%s) failed: %s",
770 name, scf_strerror(scf_error()));
771 goto destruction;
772 }
773
774 ret = scf_pg_get_property(pg, name, prop);
775 if (ret == SCF_SUCCESS) {
776 if (scf_transaction_property_change_type(tx, ent, name,
777 scf_value_type(value)) < 0) {
778 idmapdlog(LOG_ERR,
779 "scf_transaction_property_change_type(%s)"
780 " failed: %s",
781 name, scf_strerror(scf_error()));
782 goto destruction;
783 }
784 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
785 if (scf_transaction_property_new(tx, ent, name,
786 scf_value_type(value)) < 0) {
787 idmapdlog(LOG_ERR,
788 "scf_transaction_property_new() failed: %s",
789 scf_strerror(scf_error()));
790 goto destruction;
791 }
792 } else {
793 idmapdlog(LOG_ERR,
794 "scf_pg_get_property(%s) failed: %s",
795 name, scf_strerror(scf_error()));
796 goto destruction;
797 }
798
799 if (scf_entry_add_value(ent, value) == -1) {
800 idmapdlog(LOG_ERR,
801 "scf_entry_add_value() failed: %s",
802 scf_strerror(scf_error()));
803 goto destruction;
804 }
805
806 ret = scf_transaction_commit(tx);
807 if (ret == 0) {
808 /*
809 * Property group set in scf_transaction_start()
810 * is not the most recent. Update pg, reset tx and
811 * retry tx.
812 */
813 idmapdlog(LOG_WARNING,
814 "scf_transaction_commit(%s) failed: %s",
815 name, scf_strerror(scf_error()));
816 scf_transaction_reset(tx);
817 continue;
818 }
819 if (ret != 1) {
820 idmapdlog(LOG_ERR,
821 "scf_transaction_commit(%s) failed: %s",
822 name, scf_strerror(scf_error()));
823 goto destruction;
824 }
825 /* Success! */
826 rc = 0;
827 break;
828 }
829
830 destruction:
831 scf_entry_destroy(ent);
832 scf_transaction_destroy(tx);
833 scf_property_destroy(prop);
834 return (rc);
835 }
836
837 static int
set_val_integer(idmap_cfg_handles_t * handles,scf_propertygroup_t * pg,const char * name,int64_t val)838 set_val_integer(
839 idmap_cfg_handles_t *handles,
840 scf_propertygroup_t *pg,
841 const char *name,
842 int64_t val)
843 {
844 scf_value_t *value = NULL;
845 int rc;
846
847 if ((value = scf_value_create(handles->main)) == NULL) {
848 idmapdlog(LOG_ERR, "Unable to set property %s",
849 name, scf_strerror(scf_error()));
850 return (-1);
851 }
852
853 scf_value_set_integer(value, val);
854
855 rc = set_val(handles, pg, name, value);
856
857 scf_value_destroy(value);
858
859 return (rc);
860 }
861
862
863 static int
set_val_astring(idmap_cfg_handles_t * handles,scf_propertygroup_t * pg,const char * name,const char * val)864 set_val_astring(
865 idmap_cfg_handles_t *handles,
866 scf_propertygroup_t *pg,
867 const char *name,
868 const char *val)
869 {
870 scf_value_t *value = NULL;
871 int rc = -1;
872
873 if ((value = scf_value_create(handles->main)) == NULL) {
874 idmapdlog(LOG_ERR, "Unable to set property %s",
875 name, scf_strerror(scf_error()));
876 goto out;
877 }
878
879 if (scf_value_set_astring(value, val) == -1) {
880 idmapdlog(LOG_ERR,
881 "scf_value_set_astring() failed: %s",
882 scf_strerror(scf_error()));
883 goto out;
884 }
885
886 rc = set_val(handles, pg, name, value);
887
888 out:
889 scf_value_destroy(value);
890 return (rc);
891 }
892
893
894
895 /*
896 * This function updates a boolean value.
897 * If nothing has changed it returns 0 else 1
898 */
899 static int
update_bool(boolean_t * value,boolean_t * new,char * name)900 update_bool(boolean_t *value, boolean_t *new, char *name)
901 {
902 if (*value == *new)
903 return (0);
904
905 if (DBG(CONFIG, 1)) {
906 idmapdlog(LOG_INFO, "change %s=%s", name,
907 *new ? "true" : "false");
908 }
909
910 *value = *new;
911 return (1);
912 }
913
914 /*
915 * This function updates a uint64_t value.
916 * If nothing has changed it returns 0 else 1
917 */
918 static int
update_uint64(uint64_t * value,uint64_t * new,char * name)919 update_uint64(uint64_t *value, uint64_t *new, char *name)
920 {
921 if (*value == *new)
922 return (0);
923
924 if (DBG(CONFIG, 1))
925 idmapdlog(LOG_INFO, "change %s=%llu", name, *new);
926
927 *value = *new;
928 return (1);
929 }
930
931 /*
932 * This function updates a string value.
933 * If nothing has changed it returns 0 else 1
934 */
935 static int
update_string(char ** value,char ** new,char * name)936 update_string(char **value, char **new, char *name)
937 {
938 int changed;
939
940 if (*new == NULL && *value != NULL)
941 changed = 1;
942 else if (*new != NULL && *value == NULL)
943 changed = 1;
944 else if (*new != NULL && *value != NULL && strcmp(*new, *value) != 0)
945 changed = 1;
946 else
947 changed = 0;
948
949 /*
950 * Note that even if unchanged we can't just return; we must free one
951 * of the values.
952 */
953
954 if (DBG(CONFIG, 1) && changed)
955 idmapdlog(LOG_INFO, "change %s=%s", name, CHECK_NULL(*new));
956
957 free(*value);
958 *value = *new;
959 *new = NULL;
960 return (changed);
961 }
962
963 static int
update_enum(int * value,int * new,char * name,struct enum_lookup_map * map)964 update_enum(int *value, int *new, char *name, struct enum_lookup_map *map)
965 {
966 if (*value == *new)
967 return (0);
968
969 if (DBG(CONFIG, 1)) {
970 idmapdlog(LOG_INFO, "change %s=%s", name,
971 enum_lookup(*new, map));
972 }
973
974 *value = *new;
975
976 return (1);
977 }
978
979 /*
980 * This function updates a directory service structure.
981 * If nothing has changed it returns 0 else 1
982 */
983 static int
update_dirs(ad_disc_ds_t ** value,ad_disc_ds_t ** new,char * name)984 update_dirs(ad_disc_ds_t **value, ad_disc_ds_t **new, char *name)
985 {
986
987 if (*value == *new)
988 /* Nothing to do */
989 return (0);
990
991 if (*value != NULL && *new != NULL &&
992 ad_disc_compare_ds(*value, *new) == 0) {
993 free(*new);
994 *new = NULL;
995 return (0);
996 }
997
998 if (*value != NULL)
999 free(*value);
1000
1001 *value = *new;
1002 *new = NULL;
1003
1004 if (*value == NULL) {
1005 /* We're unsetting this DS property */
1006 if (DBG(CONFIG, 1))
1007 idmapdlog(LOG_INFO, "change %s=<none>", name);
1008 return (1);
1009 }
1010
1011 if (DBG(CONFIG, 1)) {
1012 /* List all the new DSs */
1013 char buf[64];
1014 ad_disc_ds_t *ds;
1015 for (ds = *value; ds->host[0] != '\0'; ds++) {
1016 if (ad_disc_getnameinfo(buf, sizeof (buf), &ds->addr))
1017 (void) strlcpy(buf, "?", sizeof (buf));
1018 idmapdlog(LOG_INFO, "change %s=%s addr=%s port=%d",
1019 name, ds->host, buf, ds->port);
1020 }
1021 }
1022 return (1);
1023 }
1024
1025 /*
1026 * This function updates a trusted domains structure.
1027 * If nothing has changed it returns 0 else 1
1028 */
1029 static int
update_trusted_domains(ad_disc_trusteddomains_t ** value,ad_disc_trusteddomains_t ** new,char * name)1030 update_trusted_domains(ad_disc_trusteddomains_t **value,
1031 ad_disc_trusteddomains_t **new, char *name)
1032 {
1033 int i;
1034
1035 if (*value == *new)
1036 /* Nothing to do */
1037 return (0);
1038
1039 if (*value != NULL && *new != NULL &&
1040 ad_disc_compare_trusteddomains(*value, *new) == 0) {
1041 free(*new);
1042 *new = NULL;
1043 return (0);
1044 }
1045
1046 if (*value != NULL)
1047 free(*value);
1048
1049 *value = *new;
1050 *new = NULL;
1051
1052 if (*value == NULL) {
1053 /* We're unsetting this DS property */
1054 if (DBG(CONFIG, 1))
1055 idmapdlog(LOG_INFO, "change %s=<none>", name);
1056 return (1);
1057 }
1058
1059 if (DBG(CONFIG, 1)) {
1060 /* List all the new domains */
1061 for (i = 0; (*value)[i].domain[0] != '\0'; i++) {
1062 idmapdlog(LOG_INFO, "change %s=%s direction=%s", name,
1063 (*value)[i].domain,
1064 enum_lookup((*value)[i].direction, trust_dir_map));
1065 }
1066 }
1067 return (1);
1068 }
1069
1070
1071 /*
1072 * This function updates a domains in a forest structure.
1073 * If nothing has changed it returns 0 else 1
1074 */
1075 static int
update_domains_in_forest(ad_disc_domainsinforest_t ** value,ad_disc_domainsinforest_t ** new,char * name)1076 update_domains_in_forest(ad_disc_domainsinforest_t **value,
1077 ad_disc_domainsinforest_t **new, char *name)
1078 {
1079 int i;
1080
1081 if (*value == *new)
1082 /* Nothing to do */
1083 return (0);
1084
1085 if (*value != NULL && *new != NULL &&
1086 ad_disc_compare_domainsinforest(*value, *new) == 0) {
1087 free(*new);
1088 *new = NULL;
1089 return (0);
1090 }
1091
1092 if (*value != NULL)
1093 free(*value);
1094
1095 *value = *new;
1096 *new = NULL;
1097
1098 if (*value == NULL) {
1099 /* We're unsetting this DS property */
1100 if (DBG(CONFIG, 1))
1101 idmapdlog(LOG_INFO, "change %s=<none>", name);
1102 return (1);
1103 }
1104
1105 if (DBG(CONFIG, 1)) {
1106 /* List all the new domains */
1107 for (i = 0; (*value)[i].domain[0] != '\0'; i++) {
1108 idmapdlog(LOG_INFO, "change %s=%s", name,
1109 (*value)[i].domain);
1110 }
1111 }
1112 return (1);
1113 }
1114
1115
1116 static void
free_trusted_forests(idmap_trustedforest_t ** value,int * num_values)1117 free_trusted_forests(idmap_trustedforest_t **value, int *num_values)
1118 {
1119 int i;
1120
1121 for (i = 0; i < *num_values; i++) {
1122 free((*value)[i].forest_name);
1123 free((*value)[i].global_catalog);
1124 free((*value)[i].domains_in_forest);
1125 }
1126 free(*value);
1127 *value = NULL;
1128 *num_values = 0;
1129 }
1130
1131
1132 static int
compare_trusteddomainsinforest(ad_disc_domainsinforest_t * df1,ad_disc_domainsinforest_t * df2)1133 compare_trusteddomainsinforest(ad_disc_domainsinforest_t *df1,
1134 ad_disc_domainsinforest_t *df2)
1135 {
1136 int i, j;
1137 int num_df1 = 0;
1138 int num_df2 = 0;
1139 boolean_t match;
1140
1141 for (i = 0; df1[i].domain[0] != '\0'; i++)
1142 if (df1[i].trusted)
1143 num_df1++;
1144
1145 for (j = 0; df2[j].domain[0] != '\0'; j++)
1146 if (df2[j].trusted)
1147 num_df2++;
1148
1149 if (num_df1 != num_df2)
1150 return (1);
1151
1152 for (i = 0; df1[i].domain[0] != '\0'; i++) {
1153 if (df1[i].trusted) {
1154 match = B_FALSE;
1155 for (j = 0; df2[j].domain[0] != '\0'; j++) {
1156 if (df2[j].trusted &&
1157 domain_eq(df1[i].domain, df2[j].domain) &&
1158 strcmp(df1[i].sid, df2[j].sid) == 0) {
1159 match = B_TRUE;
1160 break;
1161 }
1162 }
1163 if (!match)
1164 return (1);
1165 }
1166 }
1167 return (0);
1168 }
1169
1170
1171
1172 /*
1173 * This function updates trusted forest structure.
1174 * If nothing has changed it returns 0 else 1
1175 */
1176 static int
update_trusted_forest(idmap_trustedforest_t ** value,int * num_value,idmap_trustedforest_t ** new,int * num_new,char * name)1177 update_trusted_forest(idmap_trustedforest_t **value, int *num_value,
1178 idmap_trustedforest_t **new, int *num_new, char *name)
1179 {
1180 int i, j;
1181 boolean_t match;
1182
1183 if (*value == *new)
1184 /* Nothing to do */
1185 return (0);
1186
1187 if (*value != NULL && *new != NULL) {
1188 if (*num_value != *num_new)
1189 goto not_equal;
1190 for (i = 0; i < *num_value; i++) {
1191 match = B_FALSE;
1192 for (j = 0; j < *num_new; j++) {
1193 if (strcmp((*value)[i].forest_name,
1194 (*new)[j].forest_name) == 0 &&
1195 ad_disc_compare_ds(
1196 (*value)[i].global_catalog,
1197 (*new)[j].global_catalog) == 0 &&
1198 compare_trusteddomainsinforest(
1199 (*value)[i].domains_in_forest,
1200 (*new)[j].domains_in_forest) == 0) {
1201 match = B_TRUE;
1202 break;
1203 }
1204 }
1205 if (!match)
1206 goto not_equal;
1207 }
1208 free_trusted_forests(new, num_new);
1209 return (0);
1210 }
1211 not_equal:
1212 if (*value != NULL)
1213 free_trusted_forests(value, num_value);
1214 *value = *new;
1215 *num_value = *num_new;
1216 *new = NULL;
1217 *num_new = 0;
1218
1219 if (*value == NULL) {
1220 /* We're unsetting this DS property */
1221 if (DBG(CONFIG, 1))
1222 idmapdlog(LOG_INFO, "change %s=<none>", name);
1223 return (1);
1224 }
1225
1226 if (DBG(CONFIG, 1)) {
1227 /* List all the trusted forests */
1228 for (i = 0; i < *num_value; i++) {
1229 idmap_trustedforest_t *f = &(*value)[i];
1230 for (j = 0;
1231 f->domains_in_forest[j].domain[0] != '\0';
1232 j++) {
1233 /* List trusted Domains in the forest. */
1234 if (f->domains_in_forest[j].trusted)
1235 idmapdlog(LOG_INFO,
1236 "change %s=%s domain=%s",
1237 name, f->forest_name,
1238 f->domains_in_forest[j].domain);
1239 }
1240 /* List the hosts */
1241 for (j = 0;
1242 f->global_catalog[j].host[0] != '\0';
1243 j++) {
1244 idmapdlog(LOG_INFO,
1245 "change %s=%s host=%s port=%d",
1246 name, f->forest_name,
1247 f->global_catalog[j].host,
1248 f->global_catalog[j].port);
1249 }
1250 }
1251 }
1252 return (1);
1253 }
1254
1255 const char *
enum_lookup(int value,struct enum_lookup_map * map)1256 enum_lookup(int value, struct enum_lookup_map *map)
1257 {
1258 for (; map->string != NULL; map++) {
1259 if (value == map->value) {
1260 return (map->string);
1261 }
1262 }
1263 return ("(invalid)");
1264 }
1265
1266 /*
1267 * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the
1268 * interfaces.
1269 *
1270 * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON.
1271 */
1272 static
1273 boolean_t
pfroute_event_is_interesting(int rt_sock)1274 pfroute_event_is_interesting(int rt_sock)
1275 {
1276 int nbytes;
1277 int64_t msg[2048 / 8];
1278 struct rt_msghdr *rtm;
1279 boolean_t is_interesting = B_FALSE;
1280
1281 for (;;) {
1282 if ((nbytes = read(rt_sock, msg, sizeof (msg))) <= 0)
1283 break;
1284 rtm = (struct rt_msghdr *)msg;
1285 if (rtm->rtm_version != RTM_VERSION)
1286 continue;
1287 if (nbytes < rtm->rtm_msglen)
1288 continue;
1289 switch (rtm->rtm_type) {
1290 case RTM_NEWADDR:
1291 case RTM_DELADDR:
1292 case RTM_IFINFO:
1293 is_interesting = B_TRUE;
1294 break;
1295 default:
1296 break;
1297 }
1298 }
1299 return (is_interesting);
1300 }
1301
1302 /*
1303 * Wait for an event, and report what kind of event occurred.
1304 *
1305 * Note that there are cases where we are awoken but don't care about
1306 * the lower-level event. We can't just loop here because we can't
1307 * readily calculate how long to sleep the next time. We return
1308 * EVENT_NOTHING and let the caller loop.
1309 */
1310 static
1311 enum event_type
wait_for_event(struct timespec * timeoutp)1312 wait_for_event(struct timespec *timeoutp)
1313 {
1314 port_event_t pe;
1315
1316 (void) memset(&pe, 0, sizeof (pe));
1317 if (port_get(idmapd_ev_port, &pe, timeoutp) != 0) {
1318 switch (errno) {
1319 case EINTR:
1320 return (EVENT_NOTHING);
1321 case ETIME:
1322 /* Timeout */
1323 return (EVENT_TIMEOUT);
1324 default:
1325 /* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */
1326 idmapdlog(LOG_ERR, "Event port failed: %s",
1327 strerror(errno));
1328 exit(1);
1329 /* NOTREACHED */
1330 }
1331 }
1332
1333
1334 switch (pe.portev_source) {
1335 case 0:
1336 /*
1337 * This isn't documented, but seems to be what you get if
1338 * the timeout is zero seconds and there are no events
1339 * pending.
1340 */
1341 return (EVENT_TIMEOUT);
1342
1343 case PORT_SOURCE_USER:
1344 switch (pe.portev_events) {
1345 case RECONFIGURE:
1346 return (EVENT_REFRESH);
1347 case POKE_AUTO_DISCOVERY:
1348 return (EVENT_POKED);
1349 case KICK_AUTO_DISCOVERY:
1350 return (EVENT_KICKED);
1351 }
1352 return (EVENT_NOTHING);
1353
1354 case PORT_SOURCE_FD:
1355 if (pe.portev_object == rt_sock) {
1356 /*
1357 * PF_ROUTE socket read event:
1358 * re-associate fd
1359 * handle event
1360 */
1361 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD,
1362 rt_sock, POLLIN, NULL) != 0) {
1363 idmapdlog(LOG_ERR, "Failed to re-associate the "
1364 "routing socket with the event port: %s",
1365 strerror(errno));
1366 abort();
1367 }
1368 /*
1369 * The network configuration may still be in flux.
1370 * No matter, the resolver will re-transmit and
1371 * timeout if need be.
1372 */
1373 if (pfroute_event_is_interesting(rt_sock)) {
1374 if (DBG(CONFIG, 1)) {
1375 idmapdlog(LOG_DEBUG,
1376 "Interesting routing event");
1377 }
1378 return (EVENT_ROUTING);
1379 } else {
1380 if (DBG(CONFIG, 2)) {
1381 idmapdlog(LOG_DEBUG,
1382 "Boring routing event");
1383 }
1384 return (EVENT_NOTHING);
1385 }
1386 }
1387 /* Event on an FD other than the routing FD? Ignore it. */
1388 break;
1389 }
1390
1391 return (EVENT_NOTHING);
1392 }
1393
1394 void *
idmap_cfg_update_thread(void * arg)1395 idmap_cfg_update_thread(void *arg)
1396 {
1397 NOTE(ARGUNUSED(arg))
1398 idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg;
1399 const ad_disc_t ad_ctx = _idmapdstate.cfg->handles.ad_ctx;
1400 int flags = CFG_DISCOVER;
1401 uint_t retry_count = 0;
1402
1403 for (;;) {
1404 struct timespec timeout;
1405 struct timespec *timeoutp;
1406 int rc;
1407 int ttl, max_ttl;
1408
1409 (void) ad_disc_SubnetChanged(ad_ctx);
1410
1411 rc = idmap_cfg_load(_idmapdstate.cfg, flags);
1412 if (rc < -1) {
1413 idmapdlog(LOG_ERR, "Fatal errors while reading "
1414 "SMF properties");
1415 exit(1);
1416 } else if (rc == -1) {
1417 idmapdlog(LOG_WARNING,
1418 "Errors re-loading configuration may cause AD "
1419 "lookups to fail");
1420 }
1421
1422 /*
1423 * If we don't know our domain name, we're not in a domain;
1424 * don't bother with rediscovery until the next config change.
1425 * Avoids hourly noise in workgroup mode.
1426 *
1427 * If we don't have a DC currently, use a greatly reduced TTL
1428 * until we get one. Degrade if that takes too long.
1429 */
1430 if (pgcfg->domain_name == NULL) {
1431 ttl = -1;
1432 /* We don't need a DC if we're no longer in a domain. */
1433 if (retry_count >= DISCOVERY_RETRY_DEGRADE_CUTOFF)
1434 restore_svc();
1435 retry_count = 0;
1436 } else if (pgcfg->domain_controller == NULL ||
1437 pgcfg->global_catalog == NULL) {
1438 if (retry_count == 0)
1439 ttl = DISCOVERY_RETRY_INITIAL_DELAY;
1440 else
1441 ttl *= 2;
1442
1443 if (ttl > pgcfg->discovery_retry_max_delay)
1444 ttl = pgcfg->discovery_retry_max_delay;
1445
1446 if (++retry_count >= DISCOVERY_RETRY_DEGRADE_CUTOFF) {
1447 degrade_svc(B_FALSE,
1448 "Too many DC discovery failures");
1449 }
1450 } else {
1451 ttl = ad_disc_get_TTL(ad_ctx);
1452 max_ttl = (int)pgcfg->rediscovery_interval;
1453 if (ttl > max_ttl)
1454 ttl = max_ttl;
1455 if (ttl < MIN_REDISCOVERY_INTERVAL)
1456 ttl = MIN_REDISCOVERY_INTERVAL;
1457 if (retry_count >= DISCOVERY_RETRY_DEGRADE_CUTOFF)
1458 restore_svc();
1459 retry_count = 0;
1460 }
1461
1462 /*
1463 * Wait for an interesting event. Note that we might get
1464 * boring events between interesting events. If so, we loop.
1465 */
1466 flags = CFG_DISCOVER;
1467 for (;;) {
1468 if (ttl < 0) {
1469 timeoutp = NULL;
1470 } else {
1471 timeout.tv_sec = ttl;
1472 timeout.tv_nsec = 0;
1473 timeoutp = &timeout;
1474 }
1475
1476 if (DBG(CONFIG, 1))
1477 idmapdlog(LOG_DEBUG,
1478 "_cfg_update_thread waiting");
1479
1480 switch (wait_for_event(timeoutp)) {
1481 case EVENT_NOTHING:
1482 if (DBG(CONFIG, 2))
1483 idmapdlog(LOG_DEBUG, "Boring event.");
1484 continue;
1485 case EVENT_REFRESH:
1486 if (DBG(CONFIG, 1))
1487 idmapdlog(LOG_INFO, "SMF refresh");
1488 /*
1489 * Forget any DC we had previously.
1490 */
1491 flags |= CFG_FORGET_DC;
1492 break;
1493 case EVENT_POKED:
1494 if (DBG(CONFIG, 1))
1495 idmapdlog(LOG_DEBUG, "poked");
1496 break;
1497 case EVENT_KICKED:
1498 if (DBG(CONFIG, 1))
1499 idmapdlog(LOG_DEBUG, "kicked");
1500 flags |= CFG_FORGET_DC;
1501 break;
1502 case EVENT_TIMEOUT:
1503 if (DBG(CONFIG, 1))
1504 idmapdlog(LOG_DEBUG, "TTL expired");
1505 break;
1506 case EVENT_ROUTING:
1507 /* Already logged to DEBUG */
1508 break;
1509 }
1510 /* An interesting event! */
1511 break;
1512 }
1513 }
1514 /*
1515 * Lint isn't happy with the concept of a function declared to
1516 * return something, that doesn't return. Of course, merely adding
1517 * the return isn't enough, because it's never reached...
1518 */
1519 /*NOTREACHED*/
1520 return (NULL);
1521 }
1522
1523 int
idmap_cfg_start_updates(void)1524 idmap_cfg_start_updates(void)
1525 {
1526 if ((idmapd_ev_port = port_create()) < 0) {
1527 idmapdlog(LOG_ERR, "Failed to create event port: %s",
1528 strerror(errno));
1529 return (-1);
1530 }
1531
1532 if ((rt_sock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
1533 idmapdlog(LOG_ERR, "Failed to open routing socket: %s",
1534 strerror(errno));
1535 (void) close(idmapd_ev_port);
1536 return (-1);
1537 }
1538
1539 if (fcntl(rt_sock, F_SETFL, O_NDELAY|O_NONBLOCK) < 0) {
1540 idmapdlog(LOG_ERR, "Failed to set routing socket flags: %s",
1541 strerror(errno));
1542 (void) close(rt_sock);
1543 (void) close(idmapd_ev_port);
1544 return (-1);
1545 }
1546
1547 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD,
1548 rt_sock, POLLIN, NULL) != 0) {
1549 idmapdlog(LOG_ERR, "Failed to associate the routing "
1550 "socket with the event port: %s", strerror(errno));
1551 (void) close(rt_sock);
1552 (void) close(idmapd_ev_port);
1553 return (-1);
1554 }
1555
1556 if ((errno = pthread_create(&update_thread_handle, NULL,
1557 idmap_cfg_update_thread, NULL)) != 0) {
1558 idmapdlog(LOG_ERR, "Failed to start update thread: %s",
1559 strerror(errno));
1560 (void) port_dissociate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock);
1561 (void) close(rt_sock);
1562 (void) close(idmapd_ev_port);
1563 return (-1);
1564 }
1565
1566 return (0);
1567 }
1568
1569 /*
1570 * Reject attribute names with invalid characters.
1571 */
1572 static
1573 int
valid_ldap_attr(const char * attr)1574 valid_ldap_attr(const char *attr)
1575 {
1576 for (; *attr; attr++) {
1577 if (!isalnum(*attr) && *attr != '-' &&
1578 *attr != '_' && *attr != '.' && *attr != ';')
1579 return (0);
1580 }
1581 return (1);
1582 }
1583
1584 static
1585 void
idmapd_set_debug(idmap_cfg_handles_t * handles,enum idmapd_debug item,const char * name)1586 idmapd_set_debug(
1587 idmap_cfg_handles_t *handles,
1588 enum idmapd_debug item,
1589 const char *name)
1590 {
1591 int val;
1592
1593 if (item < 0 || item > IDMAPD_DEBUG_MAX)
1594 return;
1595
1596 val = get_debug(handles, name);
1597
1598 if (val != _idmapdstate.debug[item])
1599 idmapdlog(LOG_DEBUG, "%s/%s = %d", DEBUG_PG, name, val);
1600
1601 _idmapdstate.debug[item] = val;
1602 }
1603
1604 static
1605 void
check_smf_debug_mode(idmap_cfg_handles_t * handles)1606 check_smf_debug_mode(idmap_cfg_handles_t *handles)
1607 {
1608 idmapd_set_debug(handles, IDMAPD_DEBUG_ALL, "all");
1609 idmapd_set_debug(handles, IDMAPD_DEBUG_CONFIG, "config");
1610 idmapd_set_debug(handles, IDMAPD_DEBUG_MAPPING, "mapping");
1611 idmapd_set_debug(handles, IDMAPD_DEBUG_DISC, "discovery");
1612 idmapd_set_debug(handles, IDMAPD_DEBUG_DNS, "dns");
1613 idmapd_set_debug(handles, IDMAPD_DEBUG_LDAP, "ldap");
1614
1615 adutils_set_debug(AD_DEBUG_ALL, _idmapdstate.debug[IDMAPD_DEBUG_ALL]);
1616 adutils_set_debug(AD_DEBUG_DISC, _idmapdstate.debug[IDMAPD_DEBUG_DISC]);
1617 adutils_set_debug(AD_DEBUG_DNS, _idmapdstate.debug[IDMAPD_DEBUG_DNS]);
1618 adutils_set_debug(AD_DEBUG_LDAP, _idmapdstate.debug[IDMAPD_DEBUG_LDAP]);
1619 }
1620
1621 /*
1622 * This is the half of idmap_cfg_load() that loads property values from
1623 * SMF (using the config/ property group of the idmap FMRI).
1624 *
1625 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
1626 * -3 -> hard smf config failures
1627 * reading from SMF.
1628 */
1629 static int
idmap_cfg_load_smf(idmap_cfg_handles_t * handles,idmap_pg_config_t * pgcfg,int * const errors)1630 idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
1631 int * const errors)
1632 {
1633 int rc;
1634 char *s;
1635
1636 *errors = 0;
1637
1638 if (scf_pg_update(handles->config_pg) < 0) {
1639 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
1640 scf_strerror(scf_error()));
1641 return (-2);
1642 }
1643
1644 if (scf_pg_update(handles->debug_pg) < 0) {
1645 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
1646 scf_strerror(scf_error()));
1647 return (-2);
1648 }
1649
1650 check_smf_debug_mode(handles);
1651
1652 rc = get_val_bool(handles, "unresolvable_sid_mapping",
1653 &pgcfg->eph_map_unres_sids, B_TRUE);
1654 if (rc != 0)
1655 (*errors)++;
1656
1657 rc = get_val_bool(handles, "use_ads",
1658 &pgcfg->use_ads, B_TRUE);
1659 if (rc != 0)
1660 (*errors)++;
1661
1662 rc = get_val_bool(handles, "use_lsa",
1663 &pgcfg->use_lsa, B_TRUE);
1664 if (rc != 0)
1665 (*errors)++;
1666
1667 rc = get_val_bool(handles, "disable_cross_forest_trusts",
1668 &pgcfg->disable_cross_forest_trusts, B_TRUE);
1669 if (rc != 0)
1670 (*errors)++;
1671
1672 rc = get_val_astring(handles, "directory_based_mapping", &s);
1673 if (rc != 0)
1674 (*errors)++;
1675 else if (s == NULL || strcasecmp(s, "none") == 0)
1676 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
1677 else if (strcasecmp(s, "name") == 0)
1678 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NAME;
1679 else if (strcasecmp(s, "idmu") == 0)
1680 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_IDMU;
1681 else {
1682 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
1683 idmapdlog(LOG_ERR,
1684 "config/directory_based_mapping: invalid value \"%s\" ignored",
1685 s);
1686 (*errors)++;
1687 }
1688 free(s);
1689
1690 rc = get_val_int(handles, "list_size_limit",
1691 &pgcfg->list_size_limit, SCF_TYPE_COUNT);
1692 if (rc != 0)
1693 (*errors)++;
1694
1695 rc = get_val_int(handles, "max_threads",
1696 &pgcfg->max_threads, SCF_TYPE_COUNT);
1697 if (rc != 0)
1698 (*errors)++;
1699 if (pgcfg->max_threads == 0)
1700 pgcfg->max_threads = MAX_THREADS_DEFAULT;
1701 if (pgcfg->max_threads > UINT_MAX)
1702 pgcfg->max_threads = UINT_MAX;
1703
1704 rc = get_val_int(handles, "discovery_retry_max_delay",
1705 &pgcfg->discovery_retry_max_delay, SCF_TYPE_COUNT);
1706 if (rc != 0)
1707 (*errors)++;
1708 if (pgcfg->discovery_retry_max_delay == 0)
1709 pgcfg->discovery_retry_max_delay =
1710 DISCOVERY_RETRY_MAX_DELAY_DEFAULT;
1711
1712 rc = get_val_int(handles, "id_cache_timeout",
1713 &pgcfg->id_cache_timeout, SCF_TYPE_COUNT);
1714 if (rc != 0)
1715 (*errors)++;
1716 if (pgcfg->id_cache_timeout == 0)
1717 pgcfg->id_cache_timeout = ID_CACHE_TMO_DEFAULT;
1718
1719 rc = get_val_int(handles, "name_cache_timeout",
1720 &pgcfg->name_cache_timeout, SCF_TYPE_COUNT);
1721 if (rc != 0)
1722 (*errors)++;
1723 if (pgcfg->name_cache_timeout == 0)
1724 pgcfg->name_cache_timeout = NAME_CACHE_TMO_DEFAULT;
1725
1726 rc = get_val_int(handles, "rediscovery_interval",
1727 &pgcfg->rediscovery_interval, SCF_TYPE_COUNT);
1728 if (rc != 0)
1729 (*errors)++;
1730 if (pgcfg->rediscovery_interval == 0)
1731 pgcfg->rediscovery_interval = REDISCOVERY_INTERVAL_DEFAULT;
1732
1733 rc = get_val_astring(handles, "domain_name",
1734 &pgcfg->domain_name);
1735 if (rc != 0)
1736 (*errors)++;
1737 else {
1738 if (pgcfg->domain_name != NULL &&
1739 pgcfg->domain_name[0] == '\0') {
1740 free(pgcfg->domain_name);
1741 pgcfg->domain_name = NULL;
1742 }
1743 if (pgcfg->domain_name != NULL)
1744 pgcfg->domain_name_auto_disc = B_FALSE;
1745 (void) ad_disc_set_DomainName(handles->ad_ctx,
1746 pgcfg->domain_name);
1747 }
1748
1749 rc = get_val_astring(handles, "default_domain",
1750 &pgcfg->default_domain);
1751 if (rc != 0) {
1752 /*
1753 * SCF failures fetching config/default_domain we treat
1754 * as fatal as they may leave ID mapping rules that
1755 * match unqualified winnames flapping in the wind.
1756 */
1757 return (-2);
1758 }
1759
1760 if (pgcfg->default_domain == NULL && pgcfg->domain_name != NULL) {
1761 pgcfg->default_domain = strdup(pgcfg->domain_name);
1762 }
1763
1764 rc = get_val_astring(handles, "domain_guid", &s);
1765 if (rc != 0) {
1766 (*errors)++;
1767 } else if (s == NULL || s[0] == '\0') {
1768 /* OK, not set. */
1769 free(s);
1770 } else {
1771 uuid_t u;
1772
1773 if (uuid_parse(s, u) != 0) {
1774 idmapdlog(LOG_ERR,
1775 "config/domain_guid: invalid value \"%s\" ignored", s);
1776 free(s);
1777 (*errors)++;
1778 } else {
1779 pgcfg->domain_guid = s;
1780 pgcfg->domain_guid_auto_disc = B_FALSE;
1781 (void) ad_disc_set_DomainGUID(handles->ad_ctx, u);
1782 }
1783 }
1784
1785 rc = get_val_astring(handles, "machine_uuid", &pgcfg->machine_uuid);
1786 if (rc != 0)
1787 (*errors)++;
1788 if (pgcfg->machine_uuid == NULL) {
1789 /* If machine_uuid not configured, generate one */
1790 if (generate_machine_uuid(&pgcfg->machine_uuid) < 0)
1791 return (-2);
1792 rc = set_val_astring(handles, handles->config_pg,
1793 "machine_uuid", pgcfg->machine_uuid);
1794 if (rc != 0)
1795 (*errors)++;
1796 }
1797
1798 rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid);
1799 if (rc != 0)
1800 (*errors)++;
1801 if (pgcfg->machine_sid == NULL) {
1802 /*
1803 * If machine_sid not configured, generate one
1804 * from the machine UUID.
1805 */
1806 if (generate_machine_sid(&pgcfg->machine_sid,
1807 pgcfg->machine_uuid) < 0)
1808 return (-2);
1809 rc = set_val_astring(handles, handles->config_pg,
1810 "machine_sid", pgcfg->machine_sid);
1811 if (rc != 0)
1812 (*errors)++;
1813 }
1814
1815 rc = get_val_ds(handles, "domain_controller",
1816 &pgcfg->cfg_domain_controller);
1817 if (rc != 0)
1818 (*errors)++;
1819
1820 rc = get_val_ds(handles, "preferred_dc",
1821 &pgcfg->cfg_preferred_dc);
1822 if (rc != 0)
1823 (*errors)++;
1824
1825 rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name);
1826 if (rc != 0)
1827 (*errors)++;
1828 else {
1829 if (pgcfg->forest_name != NULL &&
1830 pgcfg->forest_name[0] == '\0') {
1831 free(pgcfg->forest_name);
1832 pgcfg->forest_name = NULL;
1833 }
1834 if (pgcfg->forest_name != NULL)
1835 pgcfg->forest_name_auto_disc = B_FALSE;
1836 (void) ad_disc_set_ForestName(handles->ad_ctx,
1837 pgcfg->forest_name);
1838 }
1839
1840 rc = get_val_astring(handles, "site_name", &pgcfg->site_name);
1841 if (rc != 0)
1842 (*errors)++;
1843 else {
1844 if (pgcfg->site_name != NULL &&
1845 pgcfg->site_name[0] == '\0') {
1846 free(pgcfg->site_name);
1847 pgcfg->site_name = NULL;
1848 }
1849 if (pgcfg->site_name != NULL)
1850 pgcfg->site_name_auto_disc = B_FALSE;
1851 (void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name);
1852 }
1853
1854 rc = get_val_ds(handles, "global_catalog",
1855 &pgcfg->cfg_global_catalog);
1856 if (rc != 0)
1857 (*errors)++;
1858
1859 /* Unless we're doing directory-based name mapping, we're done. */
1860 if (pgcfg->directory_based_mapping != DIRECTORY_MAPPING_NAME)
1861 return (0);
1862
1863 rc = get_val_astring(handles, "ad_unixuser_attr",
1864 &pgcfg->ad_unixuser_attr);
1865 if (rc != 0)
1866 return (-2);
1867 if (pgcfg->ad_unixuser_attr != NULL &&
1868 !valid_ldap_attr(pgcfg->ad_unixuser_attr)) {
1869 idmapdlog(LOG_ERR, "config/ad_unixuser_attr=%s is not a "
1870 "valid LDAP attribute name", pgcfg->ad_unixuser_attr);
1871 return (-3);
1872 }
1873
1874 rc = get_val_astring(handles, "ad_unixgroup_attr",
1875 &pgcfg->ad_unixgroup_attr);
1876 if (rc != 0)
1877 return (-2);
1878 if (pgcfg->ad_unixgroup_attr != NULL &&
1879 !valid_ldap_attr(pgcfg->ad_unixgroup_attr)) {
1880 idmapdlog(LOG_ERR, "config/ad_unixgroup_attr=%s is not a "
1881 "valid LDAP attribute name", pgcfg->ad_unixgroup_attr);
1882 return (-3);
1883 }
1884
1885 rc = get_val_astring(handles, "nldap_winname_attr",
1886 &pgcfg->nldap_winname_attr);
1887 if (rc != 0)
1888 return (-2);
1889 if (pgcfg->nldap_winname_attr != NULL &&
1890 !valid_ldap_attr(pgcfg->nldap_winname_attr)) {
1891 idmapdlog(LOG_ERR, "config/nldap_winname_attr=%s is not a "
1892 "valid LDAP attribute name", pgcfg->nldap_winname_attr);
1893 return (-3);
1894 }
1895 if (pgcfg->ad_unixuser_attr == NULL &&
1896 pgcfg->ad_unixgroup_attr == NULL &&
1897 pgcfg->nldap_winname_attr == NULL) {
1898 idmapdlog(LOG_ERR,
1899 "If config/directory_based_mapping property is set to "
1900 "\"name\" then at least one of the following name mapping "
1901 "attributes must be specified. (config/ad_unixuser_attr OR "
1902 "config/ad_unixgroup_attr OR config/nldap_winname_attr)");
1903 return (-3);
1904 }
1905
1906 return (rc);
1907 }
1908
1909 static
1910 void
log_if_unable(const void * val,const char * what)1911 log_if_unable(const void *val, const char *what)
1912 {
1913 if (val == NULL) {
1914 idmapdlog(LOG_DEBUG, "unable to discover %s", what);
1915 }
1916 }
1917
1918 static
1919 void
discover_trusted_domains(idmap_pg_config_t * pgcfg,ad_disc_t ad_ctx)1920 discover_trusted_domains(idmap_pg_config_t *pgcfg, ad_disc_t ad_ctx)
1921 {
1922 ad_disc_t trusted_ctx;
1923 int i, j, k, l;
1924 char *forestname;
1925 int num_trusteddomains;
1926 boolean_t new_forest;
1927 char *trusteddomain;
1928 ad_disc_ds_t *globalcatalog;
1929 idmap_trustedforest_t *trustedforests;
1930 ad_disc_domainsinforest_t *domainsinforest;
1931
1932 pgcfg->trusted_domains =
1933 ad_disc_get_TrustedDomains(ad_ctx, NULL);
1934
1935 if (pgcfg->forest_name != NULL && pgcfg->trusted_domains != NULL &&
1936 pgcfg->trusted_domains[0].domain[0] != '\0') {
1937 /*
1938 * We have trusted domains. We need to go through every
1939 * one and find its forest. If it is a new forest we then need
1940 * to find its Global Catalog and the domains in the forest
1941 */
1942 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++)
1943 continue;
1944 num_trusteddomains = i;
1945
1946 trustedforests = calloc(num_trusteddomains,
1947 sizeof (idmap_trustedforest_t));
1948 j = 0;
1949 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++) {
1950 trusteddomain = pgcfg->trusted_domains[i].domain;
1951 trusted_ctx = ad_disc_init();
1952 (void) ad_disc_set_DomainName(trusted_ctx,
1953 trusteddomain);
1954 forestname =
1955 ad_disc_get_ForestName(trusted_ctx, NULL);
1956 if (forestname == NULL) {
1957 if (DBG(CONFIG, 1)) {
1958 idmapdlog(LOG_DEBUG,
1959 "unable to discover Forest Name"
1960 " for the trusted domain %s",
1961 trusteddomain);
1962 }
1963 ad_disc_fini(trusted_ctx);
1964 continue;
1965 }
1966
1967 if (strcasecmp(forestname, pgcfg->forest_name) == 0) {
1968 /*
1969 * Ignore the domain as it is part of
1970 * the primary forest
1971 */
1972 free(forestname);
1973 ad_disc_fini(trusted_ctx);
1974 continue;
1975 }
1976
1977 /* Is this a new forest? */
1978 new_forest = B_TRUE;
1979 for (k = 0; k < j; k++) {
1980 if (strcasecmp(forestname,
1981 trustedforests[k].forest_name) == 0) {
1982 new_forest = B_FALSE;
1983 domainsinforest =
1984 trustedforests[k].domains_in_forest;
1985 break;
1986 }
1987 }
1988 if (!new_forest) {
1989 /* Mark the domain as trusted */
1990 for (l = 0;
1991 domainsinforest[l].domain[0] != '\0'; l++) {
1992 if (domain_eq(trusteddomain,
1993 domainsinforest[l].domain)) {
1994 domainsinforest[l].trusted =
1995 TRUE;
1996 break;
1997 }
1998 }
1999 free(forestname);
2000 ad_disc_fini(trusted_ctx);
2001 continue;
2002 }
2003
2004 /*
2005 * Get the Global Catalog and the domains in
2006 * this new forest.
2007 */
2008 globalcatalog =
2009 ad_disc_get_GlobalCatalog(trusted_ctx,
2010 AD_DISC_PREFER_SITE, NULL);
2011 if (globalcatalog == NULL) {
2012 if (DBG(CONFIG, 1)) {
2013 idmapdlog(LOG_DEBUG,
2014 "unable to discover Global Catalog"
2015 " for the trusted domain %s",
2016 trusteddomain);
2017 }
2018 free(forestname);
2019 ad_disc_fini(trusted_ctx);
2020 continue;
2021 }
2022 domainsinforest =
2023 ad_disc_get_DomainsInForest(trusted_ctx, NULL);
2024 if (domainsinforest == NULL) {
2025 if (DBG(CONFIG, 1)) {
2026 idmapdlog(LOG_DEBUG,
2027 "unable to discover Domains in the"
2028 " Forest for the trusted domain %s",
2029 trusteddomain);
2030 }
2031 free(globalcatalog);
2032 free(forestname);
2033 ad_disc_fini(trusted_ctx);
2034 continue;
2035 }
2036
2037 trustedforests[j].forest_name = forestname;
2038 trustedforests[j].global_catalog = globalcatalog;
2039 trustedforests[j].domains_in_forest = domainsinforest;
2040 j++;
2041 /* Mark the domain as trusted */
2042 for (l = 0; domainsinforest[l].domain[0] != '\0';
2043 l++) {
2044 if (domain_eq(trusteddomain,
2045 domainsinforest[l].domain)) {
2046 domainsinforest[l].trusted = TRUE;
2047 break;
2048 }
2049 }
2050 ad_disc_fini(trusted_ctx);
2051 }
2052 if (j > 0) {
2053 pgcfg->num_trusted_forests = j;
2054 pgcfg->trusted_forests = trustedforests;
2055 } else {
2056 free(trustedforests);
2057 }
2058 }
2059 }
2060
2061 /*
2062 * This is the half of idmap_cfg_load() that auto-discovers values of
2063 * discoverable properties that weren't already set via SMF properties.
2064 *
2065 * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it
2066 * needs to be careful not to overwrite any properties set in SMF.
2067 */
2068 static void
idmap_cfg_discover1(idmap_cfg_handles_t * handles,idmap_pg_config_t * pgcfg)2069 idmap_cfg_discover1(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg)
2070 {
2071 ad_disc_t ad_ctx = handles->ad_ctx;
2072 FILE *status_fp = NULL;
2073 time_t t0, t1;
2074
2075 t0 = time(NULL);
2076 if (DBG(CONFIG, 1))
2077 idmapdlog(LOG_DEBUG, "Running domain discovery.");
2078
2079 (void) unlink(IDMAP_CACHEDIR "/discovery.log");
2080 status_fp = fopen(IDMAP_CACHEDIR "/discovery.log", "w");
2081 if (status_fp) {
2082 (void) fchmod(fileno(status_fp), 0644);
2083 ad_disc_set_StatusFP(ad_ctx, status_fp);
2084 }
2085
2086 if (pgcfg->domain_name == NULL) {
2087 idmapdlog(LOG_DEBUG, "No domain name specified.");
2088 if (status_fp)
2089 (void) fprintf(status_fp, "(no domain name)\n");
2090 goto out;
2091 }
2092
2093 if (pgcfg->domain_controller == NULL)
2094 pgcfg->domain_controller =
2095 ad_disc_get_DomainController(ad_ctx,
2096 AD_DISC_PREFER_SITE,
2097 &pgcfg->domain_controller_auto_disc);
2098
2099 if (pgcfg->domain_guid == NULL) {
2100 char buf[UUID_PRINTABLE_STRING_LENGTH];
2101 uchar_t *u = ad_disc_get_DomainGUID(ad_ctx,
2102 &pgcfg->domain_guid_auto_disc);
2103 (void) memset(buf, 0, sizeof (buf));
2104 if (u != NULL) {
2105 uuid_unparse(u, buf);
2106 pgcfg->domain_guid = strdup(buf);
2107 }
2108 }
2109
2110 if (pgcfg->forest_name == NULL)
2111 pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx,
2112 &pgcfg->forest_name_auto_disc);
2113
2114 if (pgcfg->site_name == NULL)
2115 pgcfg->site_name = ad_disc_get_SiteName(ad_ctx,
2116 &pgcfg->site_name_auto_disc);
2117
2118 if (DBG(CONFIG, 1)) {
2119 log_if_unable(pgcfg->domain_name, "Domain Name");
2120 log_if_unable(pgcfg->domain_controller,
2121 "Domain Controller");
2122 log_if_unable(pgcfg->domain_guid, "Domain GUID");
2123 log_if_unable(pgcfg->forest_name, "Forest Name");
2124 log_if_unable(pgcfg->site_name, "Site Name");
2125 }
2126
2127 out:
2128 if (status_fp) {
2129 ad_disc_set_StatusFP(ad_ctx, NULL);
2130 (void) fclose(status_fp);
2131 status_fp = NULL;
2132 }
2133
2134 if (DBG(CONFIG, 1))
2135 idmapdlog(LOG_DEBUG, "Domain discovery done.");
2136
2137 /*
2138 * Log when this took more than 15 sec.
2139 */
2140 t1 = time(NULL);
2141 if (t1 > (t0 + 15)) {
2142 idmapdlog(LOG_NOTICE, "Domain discovery took %d sec.",
2143 (int)(t1 - t0));
2144 idmapdlog(LOG_NOTICE, "Check the DNS configuration.");
2145 }
2146 }
2147
2148 /*
2149 * This is the second part of discovery, which can take a while.
2150 * We don't want to hold up parties who just want to know what
2151 * domain controller we're using (like smbd), so this part runs
2152 * after we've updated that info in the "live" config and told
2153 * such consumers to go ahead.
2154 *
2155 * This is a lot like idmap_cfg_discover(), but used LDAP queries
2156 * get the forest information from the global catalog servers.
2157 *
2158 * Note: the previous update_* calls have usually nuked any
2159 * useful information from pgcfg before we get here, so we
2160 * can only use it store discovery results, not to read.
2161 */
2162 static void
idmap_cfg_discover2(idmap_cfg_handles_t * handles,idmap_pg_config_t * pgcfg)2163 idmap_cfg_discover2(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg)
2164 {
2165 ad_disc_t ad_ctx = handles->ad_ctx;
2166 FILE *status_fp = NULL;
2167 time_t t0, t1;
2168
2169 t0 = time(NULL);
2170 if (DBG(CONFIG, 1))
2171 idmapdlog(LOG_DEBUG, "Running forest discovery.");
2172
2173 status_fp = fopen(IDMAP_CACHEDIR "/discovery.log", "a");
2174 if (status_fp)
2175 ad_disc_set_StatusFP(ad_ctx, status_fp);
2176
2177 if (pgcfg->global_catalog == NULL)
2178 pgcfg->global_catalog =
2179 ad_disc_get_GlobalCatalog(ad_ctx,
2180 AD_DISC_PREFER_SITE,
2181 &pgcfg->global_catalog_auto_disc);
2182
2183 if (pgcfg->global_catalog != NULL) {
2184 pgcfg->domains_in_forest =
2185 ad_disc_get_DomainsInForest(ad_ctx, NULL);
2186
2187 if (!pgcfg->disable_cross_forest_trusts)
2188 discover_trusted_domains(pgcfg, ad_ctx);
2189 }
2190
2191 if (DBG(CONFIG, 1)) {
2192 log_if_unable(pgcfg->global_catalog, "Global Catalog");
2193 log_if_unable(pgcfg->domains_in_forest,
2194 "Domains in the Forest");
2195 /* Empty trusted domains list is OK. */
2196 }
2197
2198 if (status_fp) {
2199 ad_disc_set_StatusFP(ad_ctx, NULL);
2200 (void) fclose(status_fp);
2201 status_fp = NULL;
2202 }
2203
2204 if (DBG(CONFIG, 1))
2205 idmapdlog(LOG_DEBUG, "Forest discovery done.");
2206
2207 /*
2208 * Log when this took more than 30 sec.
2209 */
2210 t1 = time(NULL);
2211 if (t1 > (t0 + 30)) {
2212 idmapdlog(LOG_NOTICE, "Forest discovery took %d sec.",
2213 (int)(t1 - t0));
2214 idmapdlog(LOG_NOTICE, "Check AD join status.");
2215 }
2216 }
2217
2218
2219 /*
2220 * idmap_cfg_load() is called at startup, and periodically via the
2221 * update thread when the auto-discovery TTLs expire, as well as part of
2222 * the refresh method, to update the current configuration. It always
2223 * reads from SMF, but you still have to refresh the service after
2224 * changing the config pg in order for the changes to take effect.
2225 *
2226 * There is one flag:
2227 *
2228 * - CFG_DISCOVER
2229 *
2230 * If CFG_DISCOVER is set then idmap_cfg_load() calls
2231 * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property
2232 * values that weren't set in SMF.
2233 *
2234 * idmap_cfg_load() will log (to LOG_NOTICE) whether the configuration
2235 * changed.
2236 *
2237 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
2238 * reading from SMF.
2239 */
2240 int
idmap_cfg_load(idmap_cfg_t * cfg,int flags)2241 idmap_cfg_load(idmap_cfg_t *cfg, int flags)
2242 {
2243 const ad_disc_t ad_ctx = cfg->handles.ad_ctx;
2244 int rc = 0;
2245 int errors;
2246 int changed = 0;
2247 bool_t dc_changed = FALSE;
2248 bool_t gc_changed = FALSE;
2249 idmap_pg_config_t new_pgcfg, *live_pgcfg;
2250
2251 if (DBG(CONFIG, 1))
2252 idmapdlog(LOG_DEBUG, "Loading configuration.");
2253
2254 live_pgcfg = &cfg->pgcfg;
2255 (void) memset(&new_pgcfg, 0, sizeof (new_pgcfg));
2256
2257 (void) pthread_mutex_lock(&cfg->handles.mutex);
2258
2259 if ((rc = idmap_cfg_load_smf(&cfg->handles, &new_pgcfg, &errors)) < -1)
2260 goto err;
2261
2262 if (flags & CFG_DISCOVER) {
2263
2264 ad_disc_refresh(ad_ctx);
2265
2266 /*
2267 * Convert domain server configuration items to libadutils
2268 * values. This involves DNS, so we want to avoid doing this
2269 * during startup, less we risk slow or unresponsive servers
2270 * causing startup to timeout.
2271 */
2272 rc = resolve_ds_addr(&cfg->handles, "domain_controller", 389,
2273 new_pgcfg.cfg_domain_controller,
2274 &new_pgcfg.domain_controller);
2275 if (rc != 0)
2276 errors++;
2277 else {
2278 (void) ad_disc_set_DomainController(ad_ctx,
2279 new_pgcfg.domain_controller);
2280 new_pgcfg.domain_controller_auto_disc = B_FALSE;
2281 }
2282
2283 rc = resolve_ds_addr(&cfg->handles, "preferred_dc", 389,
2284 new_pgcfg.cfg_preferred_dc,
2285 &new_pgcfg.preferred_dc);
2286 if (rc != 0)
2287 errors++;
2288 else {
2289 (void) ad_disc_set_PreferredDC(ad_ctx,
2290 new_pgcfg.preferred_dc);
2291 new_pgcfg.preferred_dc_auto_disc = B_FALSE;
2292 }
2293
2294 rc = resolve_ds_addr(&cfg->handles, "global_catalog", 3268,
2295 new_pgcfg.cfg_global_catalog,
2296 &new_pgcfg.global_catalog);
2297 if (rc != 0)
2298 errors++;
2299 else {
2300 (void) ad_disc_set_GlobalCatalog(ad_ctx,
2301 new_pgcfg.global_catalog);
2302 new_pgcfg.global_catalog_auto_disc = B_FALSE;
2303 }
2304
2305 /*
2306 * Unless we've been asked to forget the current DC,
2307 * give preference (in order) to the preferred DC if
2308 * configured, or the current DC. These preferences
2309 * reduce undesirable DC changes.
2310 */
2311 if (flags & CFG_FORGET_DC) {
2312 (void) ad_disc_set_PreferredDC(ad_ctx, NULL);
2313 } else if (new_pgcfg.preferred_dc != NULL) {
2314 (void) ad_disc_set_PreferredDC(ad_ctx,
2315 new_pgcfg.preferred_dc);
2316 } else if (live_pgcfg->domain_controller != NULL) {
2317 (void) ad_disc_set_PreferredDC(ad_ctx,
2318 live_pgcfg->domain_controller);
2319 } else {
2320 (void) ad_disc_set_PreferredDC(ad_ctx, NULL);
2321 }
2322
2323 /*
2324 * We want a way to tell adspriv_getdcname_1_svc()
2325 * (and others) that discovery is running and therefore
2326 * they may want to wait a bit or return an error...
2327 */
2328 (void) mutex_lock(&_idmapdstate.addisc_lk);
2329 _idmapdstate.addisc_st |= ADDISC_ST_RUNNING;
2330 (void) mutex_unlock(&_idmapdstate.addisc_lk);
2331
2332 idmap_cfg_discover1(&cfg->handles, &new_pgcfg);
2333
2334 WRLOCK_CONFIG();
2335 (void) mutex_lock(&_idmapdstate.addisc_lk);
2336 _idmapdstate.addisc_st = 0;
2337 (void) cond_broadcast(&_idmapdstate.addisc_cv);
2338 (void) mutex_unlock(&_idmapdstate.addisc_lk);
2339 } else {
2340 WRLOCK_CONFIG();
2341 }
2342
2343 /* Non-discoverable props updated here */
2344
2345 changed += update_uint64(&live_pgcfg->list_size_limit,
2346 &new_pgcfg.list_size_limit, "list_size_limit");
2347
2348 changed += update_uint64(&live_pgcfg->max_threads,
2349 &new_pgcfg.max_threads, "max_threads");
2350
2351 changed += update_uint64(&live_pgcfg->discovery_retry_max_delay,
2352 &new_pgcfg.discovery_retry_max_delay, "discovery_retry_max_delay");
2353
2354 changed += update_uint64(&live_pgcfg->id_cache_timeout,
2355 &new_pgcfg.id_cache_timeout, "id_cache_timeout");
2356
2357 changed += update_uint64(&live_pgcfg->name_cache_timeout,
2358 &new_pgcfg.name_cache_timeout, "name_cache_timeout");
2359
2360 changed += update_uint64(&live_pgcfg->rediscovery_interval,
2361 &new_pgcfg.rediscovery_interval, "rediscovery_interval");
2362
2363 changed += update_string(&live_pgcfg->machine_sid,
2364 &new_pgcfg.machine_sid, "machine_sid");
2365
2366 changed += update_bool(&live_pgcfg->eph_map_unres_sids,
2367 &new_pgcfg.eph_map_unres_sids, "unresolvable_sid_mapping");
2368
2369 changed += update_bool(&live_pgcfg->use_ads,
2370 &new_pgcfg.use_ads, "use_ads");
2371
2372 changed += update_bool(&live_pgcfg->use_lsa,
2373 &new_pgcfg.use_lsa, "use_lsa");
2374
2375 changed += update_bool(&live_pgcfg->disable_cross_forest_trusts,
2376 &new_pgcfg.disable_cross_forest_trusts,
2377 "disable_cross_forest_trusts");
2378
2379 changed += update_enum(&live_pgcfg->directory_based_mapping,
2380 &new_pgcfg.directory_based_mapping, "directory_based_mapping",
2381 directory_mapping_map);
2382
2383 changed += update_string(&live_pgcfg->ad_unixuser_attr,
2384 &new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr");
2385
2386 changed += update_string(&live_pgcfg->ad_unixgroup_attr,
2387 &new_pgcfg.ad_unixgroup_attr, "ad_unixgroup_attr");
2388
2389 changed += update_string(&live_pgcfg->nldap_winname_attr,
2390 &new_pgcfg.nldap_winname_attr, "nldap_winname_attr");
2391
2392 changed += update_string(&live_pgcfg->default_domain,
2393 &new_pgcfg.default_domain, "default_domain");
2394
2395 changed += update_dirs(&live_pgcfg->preferred_dc,
2396 &new_pgcfg.preferred_dc, "preferred_dc");
2397
2398 /* Props that can be discovered or set in SMF updated here */
2399
2400 if (update_string(&live_pgcfg->domain_name,
2401 &new_pgcfg.domain_name, "domain_name")) {
2402 changed++;
2403 dc_changed = TRUE;
2404 gc_changed = TRUE;
2405 idmapd_set_krb5_realm(live_pgcfg->domain_name);
2406 }
2407 live_pgcfg->domain_name_auto_disc = new_pgcfg.domain_name_auto_disc;
2408
2409 changed += update_string(&live_pgcfg->domain_guid,
2410 &new_pgcfg.domain_guid, "domain_guid");
2411 live_pgcfg->domain_guid_auto_disc = new_pgcfg.domain_guid_auto_disc;
2412
2413 if (update_dirs(&live_pgcfg->domain_controller,
2414 &new_pgcfg.domain_controller, "domain_controller")) {
2415 changed++;
2416 dc_changed = TRUE;
2417 }
2418 live_pgcfg->domain_controller_auto_disc =
2419 new_pgcfg.domain_controller_auto_disc;
2420
2421 changed += update_string(&live_pgcfg->forest_name,
2422 &new_pgcfg.forest_name, "forest_name");
2423 live_pgcfg->forest_name_auto_disc = new_pgcfg.forest_name_auto_disc;
2424
2425 changed += update_string(&live_pgcfg->site_name,
2426 &new_pgcfg.site_name, "site_name");
2427 live_pgcfg->site_name_auto_disc = new_pgcfg.site_name_auto_disc;
2428
2429 /* Note: explicitly ignoring the bare string domain server values */
2430
2431 if (DBG(CONFIG, 1)) {
2432 if (changed)
2433 idmapdlog(LOG_NOTICE, "Configuration changed");
2434 else
2435 idmapdlog(LOG_NOTICE, "Configuration unchanged");
2436 }
2437
2438 UNLOCK_CONFIG();
2439
2440 if (dc_changed) {
2441 notify_dc_changed();
2442 }
2443
2444 /*
2445 * Discovery2 can take a while.
2446 */
2447 if (flags & CFG_DISCOVER) {
2448 if (live_pgcfg->domain_name != NULL &&
2449 live_pgcfg->forest_name != NULL)
2450 idmap_cfg_discover2(&cfg->handles, &new_pgcfg);
2451 ad_disc_done(ad_ctx);
2452 }
2453
2454 WRLOCK_CONFIG();
2455
2456 /* More props that can be discovered or set in SMF */
2457
2458 if (update_dirs(&live_pgcfg->global_catalog,
2459 &new_pgcfg.global_catalog, "global_catalog")) {
2460 changed++;
2461 gc_changed = TRUE;
2462 }
2463 live_pgcfg->global_catalog_auto_disc =
2464 new_pgcfg.global_catalog_auto_disc;
2465
2466 /* Props that are only discovered (never in SMF) */
2467
2468 if (update_domains_in_forest(&live_pgcfg->domains_in_forest,
2469 &new_pgcfg.domains_in_forest, "domains_in_forest")) {
2470 changed++;
2471 gc_changed = TRUE;
2472 }
2473
2474 if (update_trusted_domains(&live_pgcfg->trusted_domains,
2475 &new_pgcfg.trusted_domains, "trusted_domains")) {
2476 changed++;
2477 if (live_pgcfg->trusted_domains != NULL &&
2478 live_pgcfg->trusted_domains[0].domain[0] != '\0')
2479 gc_changed = TRUE;
2480 }
2481
2482 if (update_trusted_forest(&live_pgcfg->trusted_forests,
2483 &live_pgcfg->num_trusted_forests, &new_pgcfg.trusted_forests,
2484 &new_pgcfg.num_trusted_forests, "trusted_forest")) {
2485 changed++;
2486 if (live_pgcfg->trusted_forests != NULL)
2487 gc_changed = TRUE;
2488 }
2489
2490 if (DBG(CONFIG, 1)) {
2491 if (changed)
2492 idmapdlog(LOG_NOTICE, "Configuration changed");
2493 else
2494 idmapdlog(LOG_NOTICE, "Configuration unchanged");
2495 }
2496
2497 UNLOCK_CONFIG();
2498
2499 if (dc_changed)
2500 reload_dcs();
2501 if (gc_changed)
2502 reload_gcs();
2503
2504 idmap_cfg_unload(&new_pgcfg);
2505
2506 err:
2507 (void) pthread_mutex_unlock(&cfg->handles.mutex);
2508
2509 if (rc < -1)
2510 return (rc);
2511
2512 return ((errors == 0) ? 0 : -1);
2513 }
2514
2515 /*
2516 * Initialize 'cfg'.
2517 */
2518 idmap_cfg_t *
idmap_cfg_init()2519 idmap_cfg_init()
2520 {
2521 idmap_cfg_handles_t *handles;
2522
2523 /* First the smf repository handles: */
2524 idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t));
2525 if (!cfg) {
2526 idmapdlog(LOG_ERR, "Out of memory");
2527 return (NULL);
2528 }
2529 handles = &cfg->handles;
2530
2531 (void) pthread_mutex_init(&handles->mutex, NULL);
2532
2533 if (!(handles->main = scf_handle_create(SCF_VERSION))) {
2534 idmapdlog(LOG_ERR, "scf_handle_create() failed: %s",
2535 scf_strerror(scf_error()));
2536 goto error;
2537 }
2538
2539 if (scf_handle_bind(handles->main) < 0) {
2540 idmapdlog(LOG_ERR, "scf_handle_bind() failed: %s",
2541 scf_strerror(scf_error()));
2542 goto error;
2543 }
2544
2545 if (!(handles->service = scf_service_create(handles->main)) ||
2546 !(handles->instance = scf_instance_create(handles->main)) ||
2547 !(handles->config_pg = scf_pg_create(handles->main)) ||
2548 !(handles->debug_pg = scf_pg_create(handles->main))) {
2549 idmapdlog(LOG_ERR, "scf handle creation failed: %s",
2550 scf_strerror(scf_error()));
2551 goto error;
2552 }
2553
2554 if (scf_handle_decode_fmri(handles->main,
2555 FMRI_BASE "/:properties/" CONFIG_PG,
2556 NULL, /* scope */
2557 handles->service, /* service */
2558 handles->instance, /* instance */
2559 handles->config_pg, /* pg */
2560 NULL, /* prop */
2561 SCF_DECODE_FMRI_EXACT) < 0) {
2562 idmapdlog(LOG_ERR, "scf_handle_decode_fmri() failed: %s",
2563 scf_strerror(scf_error()));
2564 goto error;
2565 }
2566
2567 if (scf_service_get_pg(handles->service,
2568 DEBUG_PG, handles->debug_pg) < 0) {
2569 idmapdlog(LOG_ERR, "Property group \"%s\": %s",
2570 DEBUG_PG, scf_strerror(scf_error()));
2571 goto error;
2572 }
2573
2574 check_smf_debug_mode(handles);
2575
2576 /* Initialize AD Auto Discovery context */
2577 handles->ad_ctx = ad_disc_init();
2578 if (handles->ad_ctx == NULL)
2579 goto error;
2580
2581 return (cfg);
2582
2583 error:
2584 (void) idmap_cfg_fini(cfg);
2585 return (NULL);
2586 }
2587
2588 void
idmap_cfg_unload(idmap_pg_config_t * pgcfg)2589 idmap_cfg_unload(idmap_pg_config_t *pgcfg)
2590 {
2591
2592 if (pgcfg->default_domain) {
2593 free(pgcfg->default_domain);
2594 pgcfg->default_domain = NULL;
2595 }
2596 if (pgcfg->domain_name) {
2597 free(pgcfg->domain_name);
2598 pgcfg->domain_name = NULL;
2599 }
2600 if (pgcfg->domain_guid) {
2601 free(pgcfg->domain_guid);
2602 pgcfg->domain_guid = NULL;
2603 }
2604 if (pgcfg->machine_sid) {
2605 free(pgcfg->machine_sid);
2606 pgcfg->machine_sid = NULL;
2607 }
2608 if (pgcfg->cfg_domain_controller) {
2609 char **host = &pgcfg->cfg_domain_controller[0];
2610 while (*host != NULL)
2611 free(*host++);
2612 free(pgcfg->cfg_domain_controller);
2613 pgcfg->cfg_domain_controller = NULL;
2614 }
2615 if (pgcfg->domain_controller) {
2616 free(pgcfg->domain_controller);
2617 pgcfg->domain_controller = NULL;
2618 }
2619 if (pgcfg->cfg_preferred_dc) {
2620 char **host = &pgcfg->cfg_preferred_dc[0];
2621 while (*host != NULL)
2622 free(*host++);
2623 free(pgcfg->cfg_preferred_dc);
2624 pgcfg->cfg_preferred_dc = NULL;
2625 }
2626 if (pgcfg->preferred_dc) {
2627 free(pgcfg->preferred_dc);
2628 pgcfg->preferred_dc = NULL;
2629 }
2630 if (pgcfg->forest_name) {
2631 free(pgcfg->forest_name);
2632 pgcfg->forest_name = NULL;
2633 }
2634 if (pgcfg->site_name) {
2635 free(pgcfg->site_name);
2636 pgcfg->site_name = NULL;
2637 }
2638 if (pgcfg->cfg_global_catalog) {
2639 char **host = &pgcfg->cfg_global_catalog[0];
2640 while (*host != NULL)
2641 free(*host++);
2642 free(pgcfg->cfg_global_catalog);
2643 pgcfg->cfg_global_catalog = NULL;
2644 }
2645 if (pgcfg->global_catalog) {
2646 free(pgcfg->global_catalog);
2647 pgcfg->global_catalog = NULL;
2648 }
2649 if (pgcfg->trusted_domains) {
2650 free(pgcfg->trusted_domains);
2651 pgcfg->trusted_domains = NULL;
2652 }
2653 if (pgcfg->trusted_forests)
2654 free_trusted_forests(&pgcfg->trusted_forests,
2655 &pgcfg->num_trusted_forests);
2656
2657 if (pgcfg->ad_unixuser_attr) {
2658 free(pgcfg->ad_unixuser_attr);
2659 pgcfg->ad_unixuser_attr = NULL;
2660 }
2661 if (pgcfg->ad_unixgroup_attr) {
2662 free(pgcfg->ad_unixgroup_attr);
2663 pgcfg->ad_unixgroup_attr = NULL;
2664 }
2665 if (pgcfg->nldap_winname_attr) {
2666 free(pgcfg->nldap_winname_attr);
2667 pgcfg->nldap_winname_attr = NULL;
2668 }
2669 }
2670
2671 int
idmap_cfg_fini(idmap_cfg_t * cfg)2672 idmap_cfg_fini(idmap_cfg_t *cfg)
2673 {
2674 idmap_cfg_handles_t *handles = &cfg->handles;
2675 idmap_cfg_unload(&cfg->pgcfg);
2676
2677 (void) pthread_mutex_destroy(&handles->mutex);
2678 scf_pg_destroy(handles->config_pg);
2679 if (handles->debug_pg != NULL)
2680 scf_pg_destroy(handles->debug_pg);
2681 scf_instance_destroy(handles->instance);
2682 scf_service_destroy(handles->service);
2683 scf_handle_destroy(handles->main);
2684 if (handles->ad_ctx != NULL)
2685 ad_disc_fini(handles->ad_ctx);
2686 free(cfg);
2687
2688 return (0);
2689 }
2690
2691 void
idmap_cfg_poke_updates(void)2692 idmap_cfg_poke_updates(void)
2693 {
2694 int prev_st;
2695
2696 if (DBG(CONFIG, 1)) {
2697 idmapdlog(LOG_INFO, "idmap_cfg_poke_updates");
2698 }
2699
2700 (void) mutex_lock(&_idmapdstate.addisc_lk);
2701 prev_st = _idmapdstate.addisc_st;
2702 _idmapdstate.addisc_st |= ADDISC_ST_REQUESTED;
2703 (void) mutex_unlock(&_idmapdstate.addisc_lk);
2704
2705 if (prev_st & ADDISC_ST_REQUESTED) {
2706 idmapdlog(LOG_DEBUG, "already poked");
2707 } else {
2708 idmapdlog(LOG_DEBUG, "port send poke");
2709 (void) port_send(idmapd_ev_port, POKE_AUTO_DISCOVERY, NULL);
2710 }
2711 }
2712
2713 void
idmap_cfg_force_rediscovery(void)2714 idmap_cfg_force_rediscovery(void)
2715 {
2716 int prev_st;
2717
2718 if (DBG(CONFIG, 1)) {
2719 idmapdlog(LOG_INFO, "idmap_cfg_force_rediscovery");
2720 }
2721
2722 (void) mutex_lock(&_idmapdstate.addisc_lk);
2723 prev_st = _idmapdstate.addisc_st;
2724 _idmapdstate.addisc_st |= ADDISC_ST_REQUESTED;
2725 (void) mutex_unlock(&_idmapdstate.addisc_lk);
2726
2727 if (prev_st & ADDISC_ST_REQUESTED) {
2728 idmapdlog(LOG_DEBUG, "already kicked");
2729 } else {
2730 idmapdlog(LOG_DEBUG, "port send kick");
2731 (void) port_send(idmapd_ev_port, KICK_AUTO_DISCOVERY, NULL);
2732 }
2733 }
2734
2735 /*ARGSUSED*/
2736 void
idmap_cfg_hup_handler(int sig)2737 idmap_cfg_hup_handler(int sig)
2738 {
2739 if (idmapd_ev_port >= 0)
2740 (void) port_send(idmapd_ev_port, RECONFIGURE, NULL);
2741 }
2742
2743 /*
2744 * Upgrade the debug flags.
2745 *
2746 * We're replacing a single debug flag with a fine-grained mechanism that
2747 * is also capable of considerably more verbosity. We'll take a stab at
2748 * producing roughly the same level of output.
2749 */
2750 static
2751 int
upgrade_debug(idmap_cfg_handles_t * handles)2752 upgrade_debug(idmap_cfg_handles_t *handles)
2753 {
2754 boolean_t debug_present;
2755 const char DEBUG_PROP[] = "debug";
2756 int rc;
2757
2758 rc = prop_exists(handles, DEBUG_PROP, &debug_present);
2759
2760 if (rc != 0)
2761 return (rc);
2762
2763 if (!debug_present)
2764 return (0);
2765
2766 idmapdlog(LOG_INFO,
2767 "Upgrading old %s/%s setting to %s/* settings.",
2768 CONFIG_PG, DEBUG_PROP, DEBUG_PG);
2769
2770 rc = set_val_integer(handles, handles->debug_pg, "config", 1);
2771 if (rc != 0)
2772 return (rc);
2773 rc = set_val_integer(handles, handles->debug_pg, "discovery", 1);
2774 if (rc != 0)
2775 return (rc);
2776
2777 rc = del_val(handles, handles->config_pg, DEBUG_PROP);
2778 if (rc != 0)
2779 return (rc);
2780
2781 return (0);
2782 }
2783
2784 /*
2785 * Upgrade the DS mapping flags.
2786 *
2787 * If the old ds_name_mapping_enabled flag is present, then
2788 * if the new directory_based_mapping value is present, then
2789 * if the two are compatible, delete the old and note it
2790 * else delete the old and warn
2791 * else
2792 * set the new based on the old, and note it
2793 * delete the old
2794 */
2795 static
2796 int
upgrade_directory_mapping(idmap_cfg_handles_t * handles)2797 upgrade_directory_mapping(idmap_cfg_handles_t *handles)
2798 {
2799 boolean_t legacy_ds_name_mapping_present;
2800 const char DS_NAME_MAPPING_ENABLED[] = "ds_name_mapping_enabled";
2801 const char DIRECTORY_BASED_MAPPING[] = "directory_based_mapping";
2802 int rc;
2803
2804 rc = prop_exists(handles, DS_NAME_MAPPING_ENABLED,
2805 &legacy_ds_name_mapping_present);
2806
2807 if (rc != 0)
2808 return (rc);
2809
2810 if (!legacy_ds_name_mapping_present)
2811 return (0);
2812
2813 boolean_t legacy_ds_name_mapping_enabled;
2814 rc = get_val_bool(handles, DS_NAME_MAPPING_ENABLED,
2815 &legacy_ds_name_mapping_enabled, B_FALSE);
2816 if (rc != 0)
2817 return (rc);
2818
2819 char *legacy_mode;
2820 char *legacy_bool_string;
2821 if (legacy_ds_name_mapping_enabled) {
2822 legacy_mode = "name";
2823 legacy_bool_string = "true";
2824 } else {
2825 legacy_mode = "none";
2826 legacy_bool_string = "false";
2827 }
2828
2829 char *directory_based_mapping;
2830 rc = get_val_astring(handles, DIRECTORY_BASED_MAPPING,
2831 &directory_based_mapping);
2832 if (rc != 0)
2833 return (rc);
2834
2835 if (directory_based_mapping == NULL) {
2836 idmapdlog(LOG_INFO,
2837 "Upgrading old %s=%s setting\n"
2838 "to %s=%s.",
2839 DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2840 DIRECTORY_BASED_MAPPING, legacy_mode);
2841 rc = set_val_astring(handles, handles->config_pg,
2842 DIRECTORY_BASED_MAPPING, legacy_mode);
2843 if (rc != 0)
2844 return (rc);
2845 } else {
2846 boolean_t new_name_mapping;
2847 if (strcasecmp(directory_based_mapping, "name") == 0)
2848 new_name_mapping = B_TRUE;
2849 else
2850 new_name_mapping = B_FALSE;
2851
2852 if (legacy_ds_name_mapping_enabled == new_name_mapping) {
2853 idmapdlog(LOG_INFO,
2854 "Automatically removing old %s=%s setting\n"
2855 "in favor of %s=%s.",
2856 DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2857 DIRECTORY_BASED_MAPPING, directory_based_mapping);
2858 } else {
2859 idmapdlog(LOG_WARNING,
2860 "Removing conflicting %s=%s setting\n"
2861 "in favor of %s=%s.",
2862 DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2863 DIRECTORY_BASED_MAPPING, directory_based_mapping);
2864 }
2865 free(directory_based_mapping);
2866 }
2867
2868 rc = del_val(handles, handles->config_pg, DS_NAME_MAPPING_ENABLED);
2869 if (rc != 0)
2870 return (rc);
2871
2872 return (0);
2873 }
2874
2875 /*
2876 * Do whatever is necessary to upgrade idmap's configuration before
2877 * we load it.
2878 */
2879 int
idmap_cfg_upgrade(idmap_cfg_t * cfg)2880 idmap_cfg_upgrade(idmap_cfg_t *cfg)
2881 {
2882 int rc;
2883
2884 rc = upgrade_directory_mapping(&cfg->handles);
2885 if (rc != 0)
2886 return (rc);
2887
2888 rc = upgrade_debug(&cfg->handles);
2889 if (rc != 0)
2890 return (rc);
2891
2892 return (0);
2893 }
2894
2895 /*
2896 * The LDAP code passes principal names lacking any
2897 * realm information, which causes mech_krb5 to do
2898 * awful things trying to figure out the realm.
2899 * Avoid that by making sure it has a default,
2900 * even when krb5.conf is not configured.
2901 */
2902 static void
idmapd_set_krb5_realm(char * domain)2903 idmapd_set_krb5_realm(char *domain)
2904 {
2905 static char realm[MAXHOSTNAMELEN];
2906 size_t ilen, olen;
2907 int err;
2908
2909 (void) unlink(IDMAP_CACHEDIR "/ccache");
2910
2911 if (domain == NULL) {
2912 (void) unsetenv("KRB5_DEFAULT_REALM");
2913 return;
2914 }
2915
2916 /* Convert to upper case, in place. */
2917 (void) strlcpy(realm, domain, sizeof (realm));
2918 olen = ilen = strlen(realm);
2919 (void) u8_textprep_str(realm, &ilen, realm, &olen,
2920 U8_TEXTPREP_TOUPPER, U8_UNICODE_LATEST, &err);
2921
2922 (void) setenv("KRB5_DEFAULT_REALM", realm, 1);
2923 }
2924