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 2013 Nexenta Systems, Inc. All rights reserved.
24 */
25
26
27 /*
28 * Config routines common to idmap(1M) and idmapd(1M)
29 */
30
31 #include <stdlib.h>
32 #include <strings.h>
33 #include <libintl.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include "idmapd.h"
37 #include <stdio.h>
38 #include <stdarg.h>
39 #include <uuid/uuid.h>
40 #include <pthread.h>
41 #include <port.h>
42 #include <net/route.h>
43 #include <sys/u8_textprep.h>
44 #include <note.h>
45 #include "addisc.h"
46
47 #define MACHINE_SID_LEN (9 + 3 * 11)
48 #define FMRI_BASE "svc:/system/idmap"
49 #define CONFIG_PG "config"
50 #define DEBUG_PG "debug"
51 #define RECONFIGURE 1
52 #define POKE_AUTO_DISCOVERY 2
53
54 /*
55 * Default cache timeouts. Can override via svccfg
56 * config/id_cache_timeout = count: seconds
57 * config/name_cache_timeout = count: seconds
58 */
59 #define ID_CACHE_TMO_DEFAULT 86400
60 #define NAME_CACHE_TMO_DEFAULT 604800
61
62 enum event_type {
63 EVENT_NOTHING, /* Woke up for no good reason */
64 EVENT_TIMEOUT, /* Timeout expired */
65 EVENT_ROUTING, /* An interesting routing event happened */
66 EVENT_DEGRADE, /* An error occurred in the mainline */
67 EVENT_REFRESH, /* SMF refresh */
68 };
69
70
71
72 static pthread_t update_thread_handle = 0;
73
74 static int idmapd_ev_port = -1;
75 static int rt_sock = -1;
76
77 struct enum_lookup_map directory_mapping_map[] = {
78 { DIRECTORY_MAPPING_NONE, "none" },
79 { DIRECTORY_MAPPING_NAME, "name" },
80 { DIRECTORY_MAPPING_IDMU, "idmu" },
81 { 0, NULL },
82 };
83
84 struct enum_lookup_map trust_dir_map[] = {
85 { 1, "they trust us" },
86 { 2, "we trust them" },
87 { 3, "we trust each other" },
88 { 0, NULL },
89 };
90
91 static int
generate_machine_sid(char ** machine_sid)92 generate_machine_sid(char **machine_sid)
93 {
94 char *p;
95 uuid_t uu;
96 int i, j, len, rlen;
97 uint32_t rid;
98
99 /*
100 * Generate and split 128-bit UUID into three 32-bit RIDs The
101 * machine_sid will be of the form S-1-5-21-N1-N2-N3 (that's
102 * four RIDs altogether).
103 *
104 * Technically we could use up to 14 random RIDs here, but it
105 * turns out that with some versions of Windows using SIDs with
106 * more than five RIDs in security descriptors causes problems.
107 */
108
109 *machine_sid = calloc(1, MACHINE_SID_LEN);
110 if (*machine_sid == NULL) {
111 idmapdlog(LOG_ERR, "Out of memory");
112 return (-1);
113 }
114 (void) strcpy(*machine_sid, "S-1-5-21");
115 p = *machine_sid + strlen("S-1-5-21");
116 len = MACHINE_SID_LEN - strlen("S-1-5-21");
117
118 uuid_clear(uu);
119 uuid_generate_random(uu);
120
121 #if UUID_LEN != 16
122 #error UUID size is not 16!
123 #endif
124
125 for (i = 0; i < 3; i++) {
126 j = i * 4;
127 rid = (uu[j] << 24) | (uu[j + 1] << 16) |
128 (uu[j + 2] << 8) | (uu[j + 3]);
129 rlen = snprintf(p, len, "-%u", rid);
130 p += rlen;
131 len -= rlen;
132 }
133
134 return (0);
135 }
136
137
138 /* In the case of error, exists is set to FALSE anyway */
139 static int
prop_exists(idmap_cfg_handles_t * handles,const char * name,boolean_t * exists)140 prop_exists(idmap_cfg_handles_t *handles, const char *name, boolean_t *exists)
141 {
142
143 scf_property_t *scf_prop;
144
145 *exists = B_FALSE;
146
147 scf_prop = scf_property_create(handles->main);
148 if (scf_prop == NULL) {
149 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
150 scf_strerror(scf_error()));
151 return (-1);
152 }
153
154 if (scf_pg_get_property(handles->config_pg, name, scf_prop) == 0)
155 *exists = B_TRUE;
156
157 scf_property_destroy(scf_prop);
158
159 return (0);
160 }
161
162 static int
get_debug(idmap_cfg_handles_t * handles,const char * name)163 get_debug(idmap_cfg_handles_t *handles, const char *name)
164 {
165 int64_t i64 = 0;
166
167 scf_property_t *scf_prop;
168 scf_value_t *value;
169
170 scf_prop = scf_property_create(handles->main);
171 if (scf_prop == NULL) {
172 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
173 scf_strerror(scf_error()));
174 abort();
175 }
176 value = scf_value_create(handles->main);
177 if (value == NULL) {
178 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
179 scf_strerror(scf_error()));
180 abort();
181 }
182
183 if (scf_pg_get_property(handles->debug_pg, name, scf_prop) < 0) {
184 /* this is OK: the property is just undefined */
185 goto destruction;
186 }
187
188
189 if (scf_property_get_value(scf_prop, value) < 0) {
190 /* It is still OK when a property doesn't have any value */
191 goto destruction;
192 }
193
194 if (scf_value_get_integer(value, &i64) != 0) {
195 idmapdlog(LOG_ERR, "Can not retrieve %s/%s: %s",
196 DEBUG_PG, name, scf_strerror(scf_error()));
197 abort();
198 }
199
200 destruction:
201 scf_value_destroy(value);
202 scf_property_destroy(scf_prop);
203
204 return ((int)i64);
205 }
206
207 static int
get_val_bool(idmap_cfg_handles_t * handles,const char * name,boolean_t * val,boolean_t default_val)208 get_val_bool(idmap_cfg_handles_t *handles, const char *name,
209 boolean_t *val, boolean_t default_val)
210 {
211 int rc = 0;
212
213 scf_property_t *scf_prop;
214 scf_value_t *value;
215
216 *val = default_val;
217
218 scf_prop = scf_property_create(handles->main);
219 if (scf_prop == NULL) {
220 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
221 scf_strerror(scf_error()));
222 return (-1);
223 }
224 value = scf_value_create(handles->main);
225 if (value == NULL) {
226 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
227 scf_strerror(scf_error()));
228 scf_property_destroy(scf_prop);
229 return (-1);
230 }
231
232 /* It is OK if the property is undefined */
233 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
234 goto destruction;
235
236
237 /* It is still OK when a property doesn't have any value */
238 if (scf_property_get_value(scf_prop, value) < 0)
239 goto destruction;
240
241 uint8_t b;
242 rc = scf_value_get_boolean(value, &b);
243
244 if (rc == 0)
245 *val = (boolean_t)b;
246
247 destruction:
248 scf_value_destroy(value);
249 scf_property_destroy(scf_prop);
250
251 return (rc);
252 }
253
254 static int
get_val_int(idmap_cfg_handles_t * handles,const char * name,void * val,scf_type_t type)255 get_val_int(idmap_cfg_handles_t *handles, const char *name,
256 void *val, scf_type_t type)
257 {
258 int rc = 0;
259
260 scf_property_t *scf_prop;
261 scf_value_t *value;
262
263 switch (type) {
264 case SCF_TYPE_COUNT:
265 *(uint64_t *)val = 0;
266 break;
267 case SCF_TYPE_INTEGER:
268 *(int64_t *)val = 0;
269 break;
270 default:
271 idmapdlog(LOG_ERR, "Invalid scf integer type (%d)",
272 type);
273 abort();
274 }
275
276 scf_prop = scf_property_create(handles->main);
277 if (scf_prop == NULL) {
278 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
279 scf_strerror(scf_error()));
280 return (-1);
281 }
282 value = scf_value_create(handles->main);
283 if (value == NULL) {
284 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
285 scf_strerror(scf_error()));
286 scf_property_destroy(scf_prop);
287 return (-1);
288 }
289
290 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
291 /* this is OK: the property is just undefined */
292 goto destruction;
293
294
295 if (scf_property_get_value(scf_prop, value) < 0)
296 /* It is still OK when a property doesn't have any value */
297 goto destruction;
298
299 switch (type) {
300 case SCF_TYPE_COUNT:
301 rc = scf_value_get_count(value, val);
302 break;
303 case SCF_TYPE_INTEGER:
304 rc = scf_value_get_integer(value, val);
305 break;
306 default:
307 abort(); /* tested above */
308 /* NOTREACHED */
309 }
310
311 if (rc != 0) {
312 idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s",
313 name, scf_strerror(scf_error()));
314 }
315
316 destruction:
317 scf_value_destroy(value);
318 scf_property_destroy(scf_prop);
319
320 return (rc);
321 }
322
323 static char *
scf_value2string(const char * name,scf_value_t * value)324 scf_value2string(const char *name, scf_value_t *value)
325 {
326 static size_t max_val = 0;
327
328 if (max_val == 0)
329 max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
330
331 char buf[max_val + 1];
332 if (scf_value_get_astring(value, buf, max_val + 1) < 0) {
333 idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s",
334 name, scf_strerror(scf_error()));
335 return (NULL);
336 }
337
338 char *s = strdup(buf);
339 if (s == NULL)
340 idmapdlog(LOG_ERR, "Out of memory");
341
342 return (s);
343 }
344
345 static int
get_val_ds(idmap_cfg_handles_t * handles,const char * name,int defport,idmap_ad_disc_ds_t ** val)346 get_val_ds(idmap_cfg_handles_t *handles, const char *name, int defport,
347 idmap_ad_disc_ds_t **val)
348 {
349 idmap_ad_disc_ds_t *servers = NULL;
350 scf_property_t *scf_prop;
351 scf_value_t *value;
352 scf_iter_t *iter;
353 char *host, *portstr;
354 int len, i;
355 int count = 0;
356 int rc = -1;
357
358 *val = NULL;
359
360 restart:
361 scf_prop = scf_property_create(handles->main);
362 if (scf_prop == NULL) {
363 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
364 scf_strerror(scf_error()));
365 return (-1);
366 }
367
368 value = scf_value_create(handles->main);
369 if (value == NULL) {
370 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
371 scf_strerror(scf_error()));
372 scf_property_destroy(scf_prop);
373 return (-1);
374 }
375
376 iter = scf_iter_create(handles->main);
377 if (iter == NULL) {
378 idmapdlog(LOG_ERR, "scf_iter_create() failed: %s",
379 scf_strerror(scf_error()));
380 scf_value_destroy(value);
381 scf_property_destroy(scf_prop);
382 return (-1);
383 }
384
385 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) {
386 /* this is OK: the property is just undefined */
387 rc = 0;
388 goto destruction;
389 }
390
391 if (scf_iter_property_values(iter, scf_prop) < 0) {
392 idmapdlog(LOG_ERR,
393 "scf_iter_property_values(%s) failed: %s",
394 name, scf_strerror(scf_error()));
395 goto destruction;
396 }
397
398 /* Workaround scf bugs -- can't reset an iteration */
399 if (count == 0) {
400 while (scf_iter_next_value(iter, value) > 0)
401 count++;
402
403 if (count == 0) {
404 /* no values */
405 rc = 0;
406 goto destruction;
407 }
408
409 scf_value_destroy(value);
410 scf_iter_destroy(iter);
411 scf_property_destroy(scf_prop);
412 goto restart;
413 }
414
415 if ((servers = calloc(count + 1, sizeof (*servers))) == NULL) {
416 idmapdlog(LOG_ERR, "Out of memory");
417 goto destruction;
418 }
419
420 i = 0;
421 while (i < count && scf_iter_next_value(iter, value) > 0) {
422 servers[i].priority = 0;
423 servers[i].weight = 100;
424 servers[i].port = defport;
425 if ((host = scf_value2string(name, value)) == NULL) {
426 goto destruction;
427 }
428 if ((portstr = strchr(host, ':')) != NULL) {
429 *portstr++ = '\0';
430 servers[i].port = strtol(portstr,
431 (char **)NULL, 10);
432 if (servers[i].port == 0)
433 servers[i].port = defport;
434 }
435 len = strlcpy(servers[i].host, host,
436 sizeof (servers->host));
437
438 free(host);
439
440 /* Ignore this server if the hostname is too long */
441 if (len < sizeof (servers->host))
442 i++;
443 }
444
445 *val = servers;
446
447 rc = 0;
448
449 destruction:
450 scf_value_destroy(value);
451 scf_iter_destroy(iter);
452 scf_property_destroy(scf_prop);
453
454 if (rc < 0) {
455 if (servers)
456 free(servers);
457 *val = NULL;
458 }
459
460 return (rc);
461 }
462
463
464 static int
get_val_astring(idmap_cfg_handles_t * handles,const char * name,char ** val)465 get_val_astring(idmap_cfg_handles_t *handles, const char *name, char **val)
466 {
467 int rc = 0;
468
469 scf_property_t *scf_prop;
470 scf_value_t *value;
471
472 scf_prop = scf_property_create(handles->main);
473 if (scf_prop == NULL) {
474 idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
475 scf_strerror(scf_error()));
476 return (-1);
477 }
478 value = scf_value_create(handles->main);
479 if (value == NULL) {
480 idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
481 scf_strerror(scf_error()));
482 scf_property_destroy(scf_prop);
483 return (-1);
484 }
485
486 *val = NULL;
487
488 if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
489 /* this is OK: the property is just undefined */
490 goto destruction;
491
492 if (scf_property_get_value(scf_prop, value) < 0) {
493 idmapdlog(LOG_ERR,
494 "scf_property_get_value(%s) failed: %s",
495 name, scf_strerror(scf_error()));
496 rc = -1;
497 goto destruction;
498 }
499
500 *val = scf_value2string(name, value);
501 if (*val == NULL)
502 rc = -1;
503
504 destruction:
505 scf_value_destroy(value);
506 scf_property_destroy(scf_prop);
507
508 if (rc < 0) {
509 if (*val)
510 free(*val);
511 *val = NULL;
512 }
513
514 return (rc);
515 }
516
517
518 static int
del_val(idmap_cfg_handles_t * handles,scf_propertygroup_t * pg,const char * name)519 del_val(
520 idmap_cfg_handles_t *handles,
521 scf_propertygroup_t *pg,
522 const char *name)
523 {
524 int rc = -1;
525 int ret;
526 scf_transaction_t *tx = NULL;
527 scf_transaction_entry_t *ent = NULL;
528
529 if ((tx = scf_transaction_create(handles->main)) == NULL) {
530 idmapdlog(LOG_ERR,
531 "scf_transaction_create() failed: %s",
532 scf_strerror(scf_error()));
533 goto destruction;
534 }
535 if ((ent = scf_entry_create(handles->main)) == NULL) {
536 idmapdlog(LOG_ERR,
537 "scf_entry_create() failed: %s",
538 scf_strerror(scf_error()));
539 goto destruction;
540 }
541
542 do {
543 if (scf_pg_update(pg) == -1) {
544 idmapdlog(LOG_ERR,
545 "scf_pg_update(%s) failed: %s",
546 name, scf_strerror(scf_error()));
547 goto destruction;
548 }
549 if (scf_transaction_start(tx, pg) != 0) {
550 idmapdlog(LOG_ERR,
551 "scf_transaction_start(%s) failed: %s",
552 name, scf_strerror(scf_error()));
553 goto destruction;
554 }
555
556 if (scf_transaction_property_delete(tx, ent, name) != 0) {
557 /* Don't complain if it already doesn't exist. */
558 if (scf_error() != SCF_ERROR_NOT_FOUND) {
559 idmapdlog(LOG_ERR,
560 "scf_transaction_property_delete() failed:"
561 " %s",
562 scf_strerror(scf_error()));
563 }
564 goto destruction;
565 }
566
567 ret = scf_transaction_commit(tx);
568
569 if (ret == 0)
570 scf_transaction_reset(tx);
571 } while (ret == 0);
572
573 if (ret == -1) {
574 idmapdlog(LOG_ERR,
575 "scf_transaction_commit(%s) failed: %s",
576 name, scf_strerror(scf_error()));
577 goto destruction;
578 }
579
580 rc = 0;
581
582 destruction:
583 if (ent != NULL)
584 scf_entry_destroy(ent);
585 if (tx != NULL)
586 scf_transaction_destroy(tx);
587 return (rc);
588 }
589
590
591 static int
set_val(idmap_cfg_handles_t * handles,scf_propertygroup_t * pg,const char * name,scf_value_t * value)592 set_val(
593 idmap_cfg_handles_t *handles,
594 scf_propertygroup_t *pg,
595 const char *name,
596 scf_value_t *value)
597 {
598 int rc = -1;
599 int i;
600 scf_property_t *prop = NULL;
601 scf_transaction_t *tx = NULL;
602 scf_transaction_entry_t *ent = NULL;
603
604 if ((prop = scf_property_create(handles->main)) == NULL ||
605 (tx = scf_transaction_create(handles->main)) == NULL ||
606 (ent = scf_entry_create(handles->main)) == NULL) {
607 idmapdlog(LOG_ERR, "Unable to set property %s",
608 name, scf_strerror(scf_error()));
609 goto destruction;
610 }
611
612 for (i = 0; i < MAX_TRIES; i++) {
613 int ret;
614
615 if (scf_pg_update(pg) == -1) {
616 idmapdlog(LOG_ERR,
617 "scf_pg_update() failed: %s",
618 scf_strerror(scf_error()));
619 goto destruction;
620 }
621
622 if (scf_transaction_start(tx, pg) == -1) {
623 idmapdlog(LOG_ERR,
624 "scf_transaction_start(%s) failed: %s",
625 name, scf_strerror(scf_error()));
626 goto destruction;
627 }
628
629 ret = scf_pg_get_property(pg, name, prop);
630 if (ret == SCF_SUCCESS) {
631 if (scf_transaction_property_change_type(tx, ent, name,
632 scf_value_type(value)) < 0) {
633 idmapdlog(LOG_ERR,
634 "scf_transaction_property_change_type(%s)"
635 " failed: %s",
636 name, scf_strerror(scf_error()));
637 goto destruction;
638 }
639 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
640 if (scf_transaction_property_new(tx, ent, name,
641 scf_value_type(value)) < 0) {
642 idmapdlog(LOG_ERR,
643 "scf_transaction_property_new() failed: %s",
644 scf_strerror(scf_error()));
645 goto destruction;
646 }
647 } else {
648 idmapdlog(LOG_ERR,
649 "scf_pg_get_property(%s) failed: %s",
650 name, scf_strerror(scf_error()));
651 goto destruction;
652 }
653
654 if (scf_entry_add_value(ent, value) == -1) {
655 idmapdlog(LOG_ERR,
656 "scf_entry_add_value() failed: %s",
657 scf_strerror(scf_error()));
658 goto destruction;
659 }
660
661 ret = scf_transaction_commit(tx);
662 if (ret == 0) {
663 /*
664 * Property group set in scf_transaction_start()
665 * is not the most recent. Update pg, reset tx and
666 * retry tx.
667 */
668 idmapdlog(LOG_WARNING,
669 "scf_transaction_commit(%s) failed: %s",
670 name, scf_strerror(scf_error()));
671 scf_transaction_reset(tx);
672 continue;
673 }
674 if (ret != 1) {
675 idmapdlog(LOG_ERR,
676 "scf_transaction_commit(%s) failed: %s",
677 name, scf_strerror(scf_error()));
678 goto destruction;
679 }
680 /* Success! */
681 rc = 0;
682 break;
683 }
684
685 destruction:
686 scf_entry_destroy(ent);
687 scf_transaction_destroy(tx);
688 scf_property_destroy(prop);
689 return (rc);
690 }
691
692 static int
set_val_integer(idmap_cfg_handles_t * handles,scf_propertygroup_t * pg,const char * name,int64_t val)693 set_val_integer(
694 idmap_cfg_handles_t *handles,
695 scf_propertygroup_t *pg,
696 const char *name,
697 int64_t val)
698 {
699 scf_value_t *value = NULL;
700 int rc;
701
702 if ((value = scf_value_create(handles->main)) == NULL) {
703 idmapdlog(LOG_ERR, "Unable to set property %s",
704 name, scf_strerror(scf_error()));
705 return (-1);
706 }
707
708 scf_value_set_integer(value, val);
709
710 rc = set_val(handles, pg, name, value);
711
712 scf_value_destroy(value);
713
714 return (rc);
715 }
716
717
718 static int
set_val_astring(idmap_cfg_handles_t * handles,scf_propertygroup_t * pg,const char * name,const char * val)719 set_val_astring(
720 idmap_cfg_handles_t *handles,
721 scf_propertygroup_t *pg,
722 const char *name,
723 const char *val)
724 {
725 scf_value_t *value = NULL;
726 int rc = -1;
727
728 if ((value = scf_value_create(handles->main)) == NULL) {
729 idmapdlog(LOG_ERR, "Unable to set property %s",
730 name, scf_strerror(scf_error()));
731 goto out;
732 }
733
734 if (scf_value_set_astring(value, val) == -1) {
735 idmapdlog(LOG_ERR,
736 "scf_value_set_astring() failed: %s",
737 scf_strerror(scf_error()));
738 goto out;
739 }
740
741 rc = set_val(handles, pg, name, value);
742
743 out:
744 scf_value_destroy(value);
745 return (rc);
746 }
747
748
749
750 /*
751 * This function updates a boolean value.
752 * If nothing has changed it returns 0 else 1
753 */
754 static int
update_bool(boolean_t * value,boolean_t * new,char * name)755 update_bool(boolean_t *value, boolean_t *new, char *name)
756 {
757 if (*value == *new)
758 return (0);
759
760 if (DBG(CONFIG, 1)) {
761 idmapdlog(LOG_INFO, "change %s=%s", name,
762 *new ? "true" : "false");
763 }
764
765 *value = *new;
766 return (1);
767 }
768
769 /*
770 * This function updates a uint64_t value.
771 * If nothing has changed it returns 0 else 1
772 */
773 static int
update_uint64(uint64_t * value,uint64_t * new,char * name)774 update_uint64(uint64_t *value, uint64_t *new, char *name)
775 {
776 if (*value == *new)
777 return (0);
778
779 if (DBG(CONFIG, 1))
780 idmapdlog(LOG_INFO, "change %s=%llu", name, *new);
781
782 *value = *new;
783 return (1);
784 }
785
786 /*
787 * This function updates a string value.
788 * If nothing has changed it returns 0 else 1
789 */
790 static int
update_string(char ** value,char ** new,char * name)791 update_string(char **value, char **new, char *name)
792 {
793 int changed;
794
795 if (*new == NULL && *value != NULL)
796 changed = 1;
797 else if (*new != NULL && *value == NULL)
798 changed = 1;
799 else if (*new != NULL && *value != NULL && strcmp(*new, *value) != 0)
800 changed = 1;
801 else
802 changed = 0;
803
804 /*
805 * Note that even if unchanged we can't just return; we must free one
806 * of the values.
807 */
808
809 if (DBG(CONFIG, 1) && changed)
810 idmapdlog(LOG_INFO, "change %s=%s", name, CHECK_NULL(*new));
811
812 free(*value);
813 *value = *new;
814 *new = NULL;
815 return (changed);
816 }
817
818 static int
update_enum(int * value,int * new,char * name,struct enum_lookup_map * map)819 update_enum(int *value, int *new, char *name, struct enum_lookup_map *map)
820 {
821 if (*value == *new)
822 return (0);
823
824 if (DBG(CONFIG, 1)) {
825 idmapdlog(LOG_INFO, "change %s=%s", name,
826 enum_lookup(*new, map));
827 }
828
829 *value = *new;
830
831 return (1);
832 }
833
834 /*
835 * This function updates a directory service structure.
836 * If nothing has changed it returns 0 else 1
837 */
838 static int
update_dirs(idmap_ad_disc_ds_t ** value,idmap_ad_disc_ds_t ** new,char * name)839 update_dirs(idmap_ad_disc_ds_t **value, idmap_ad_disc_ds_t **new, char *name)
840 {
841 int i;
842
843 if (*value == *new)
844 /* Nothing to do */
845 return (0);
846
847 if (*value != NULL && *new != NULL &&
848 ad_disc_compare_ds(*value, *new) == 0) {
849 free(*new);
850 *new = NULL;
851 return (0);
852 }
853
854 if (*value != NULL)
855 free(*value);
856
857 *value = *new;
858 *new = NULL;
859
860 if (*value == NULL) {
861 /* We're unsetting this DS property */
862 if (DBG(CONFIG, 1))
863 idmapdlog(LOG_INFO, "change %s=<none>", name);
864 return (1);
865 }
866
867 if (DBG(CONFIG, 1)) {
868 /* List all the new DSs */
869 for (i = 0; (*value)[i].host[0] != '\0'; i++) {
870 idmapdlog(LOG_INFO, "change %s=%s port=%d", name,
871 (*value)[i].host, (*value)[i].port);
872 }
873 }
874 return (1);
875 }
876
877 /*
878 * This function updates a trusted domains structure.
879 * If nothing has changed it returns 0 else 1
880 */
881 static int
update_trusted_domains(ad_disc_trusteddomains_t ** value,ad_disc_trusteddomains_t ** new,char * name)882 update_trusted_domains(ad_disc_trusteddomains_t **value,
883 ad_disc_trusteddomains_t **new, char *name)
884 {
885 int i;
886
887 if (*value == *new)
888 /* Nothing to do */
889 return (0);
890
891 if (*value != NULL && *new != NULL &&
892 ad_disc_compare_trusteddomains(*value, *new) == 0) {
893 free(*new);
894 *new = NULL;
895 return (0);
896 }
897
898 if (*value != NULL)
899 free(*value);
900
901 *value = *new;
902 *new = NULL;
903
904 if (*value == NULL) {
905 /* We're unsetting this DS property */
906 if (DBG(CONFIG, 1))
907 idmapdlog(LOG_INFO, "change %s=<none>", name);
908 return (1);
909 }
910
911 if (DBG(CONFIG, 1)) {
912 /* List all the new domains */
913 for (i = 0; (*value)[i].domain[0] != '\0'; i++) {
914 idmapdlog(LOG_INFO, "change %s=%s direction=%s", name,
915 (*value)[i].domain,
916 enum_lookup((*value)[i].direction, trust_dir_map));
917 }
918 }
919 return (1);
920 }
921
922
923 /*
924 * This function updates a domains in a forest structure.
925 * If nothing has changed it returns 0 else 1
926 */
927 static int
update_domains_in_forest(ad_disc_domainsinforest_t ** value,ad_disc_domainsinforest_t ** new,char * name)928 update_domains_in_forest(ad_disc_domainsinforest_t **value,
929 ad_disc_domainsinforest_t **new, char *name)
930 {
931 int i;
932
933 if (*value == *new)
934 /* Nothing to do */
935 return (0);
936
937 if (*value != NULL && *new != NULL &&
938 ad_disc_compare_domainsinforest(*value, *new) == 0) {
939 free(*new);
940 *new = NULL;
941 return (0);
942 }
943
944 if (*value != NULL)
945 free(*value);
946
947 *value = *new;
948 *new = NULL;
949
950 if (*value == NULL) {
951 /* We're unsetting this DS property */
952 if (DBG(CONFIG, 1))
953 idmapdlog(LOG_INFO, "change %s=<none>", name);
954 return (1);
955 }
956
957 if (DBG(CONFIG, 1)) {
958 /* List all the new domains */
959 for (i = 0; (*value)[i].domain[0] != '\0'; i++) {
960 idmapdlog(LOG_INFO, "change %s=%s", name,
961 (*value)[i].domain);
962 }
963 }
964 return (1);
965 }
966
967
968 static void
free_trusted_forests(idmap_trustedforest_t ** value,int * num_values)969 free_trusted_forests(idmap_trustedforest_t **value, int *num_values)
970 {
971 int i;
972
973 for (i = 0; i < *num_values; i++) {
974 free((*value)[i].forest_name);
975 free((*value)[i].global_catalog);
976 free((*value)[i].domains_in_forest);
977 }
978 free(*value);
979 *value = NULL;
980 *num_values = 0;
981 }
982
983
984 static int
compare_trusteddomainsinforest(ad_disc_domainsinforest_t * df1,ad_disc_domainsinforest_t * df2)985 compare_trusteddomainsinforest(ad_disc_domainsinforest_t *df1,
986 ad_disc_domainsinforest_t *df2)
987 {
988 int i, j;
989 int num_df1 = 0;
990 int num_df2 = 0;
991 boolean_t match;
992
993 for (i = 0; df1[i].domain[0] != '\0'; i++)
994 if (df1[i].trusted)
995 num_df1++;
996
997 for (j = 0; df2[j].domain[0] != '\0'; j++)
998 if (df2[j].trusted)
999 num_df2++;
1000
1001 if (num_df1 != num_df2)
1002 return (1);
1003
1004 for (i = 0; df1[i].domain[0] != '\0'; i++) {
1005 if (df1[i].trusted) {
1006 match = B_FALSE;
1007 for (j = 0; df2[j].domain[0] != '\0'; j++) {
1008 if (df2[j].trusted &&
1009 domain_eq(df1[i].domain, df2[j].domain) &&
1010 strcmp(df1[i].sid, df2[j].sid) == 0) {
1011 match = B_TRUE;
1012 break;
1013 }
1014 }
1015 if (!match)
1016 return (1);
1017 }
1018 }
1019 return (0);
1020 }
1021
1022
1023
1024 /*
1025 * This function updates trusted forest structure.
1026 * If nothing has changed it returns 0 else 1
1027 */
1028 static int
update_trusted_forest(idmap_trustedforest_t ** value,int * num_value,idmap_trustedforest_t ** new,int * num_new,char * name)1029 update_trusted_forest(idmap_trustedforest_t **value, int *num_value,
1030 idmap_trustedforest_t **new, int *num_new, char *name)
1031 {
1032 int i, j;
1033 boolean_t match;
1034
1035 if (*value == *new)
1036 /* Nothing to do */
1037 return (0);
1038
1039 if (*value != NULL && *new != NULL) {
1040 if (*num_value != *num_new)
1041 goto not_equal;
1042 for (i = 0; i < *num_value; i++) {
1043 match = B_FALSE;
1044 for (j = 0; j < *num_new; j++) {
1045 if (strcmp((*value)[i].forest_name,
1046 (*new)[j].forest_name) == 0 &&
1047 ad_disc_compare_ds(
1048 (*value)[i].global_catalog,
1049 (*new)[j].global_catalog) == 0 &&
1050 compare_trusteddomainsinforest(
1051 (*value)[i].domains_in_forest,
1052 (*new)[j].domains_in_forest) == 0) {
1053 match = B_TRUE;
1054 break;
1055 }
1056 }
1057 if (!match)
1058 goto not_equal;
1059 }
1060 free_trusted_forests(new, num_new);
1061 return (0);
1062 }
1063 not_equal:
1064 if (*value != NULL)
1065 free_trusted_forests(value, num_value);
1066 *value = *new;
1067 *num_value = *num_new;
1068 *new = NULL;
1069 *num_new = 0;
1070
1071 if (*value == NULL) {
1072 /* We're unsetting this DS property */
1073 if (DBG(CONFIG, 1))
1074 idmapdlog(LOG_INFO, "change %s=<none>", name);
1075 return (1);
1076 }
1077
1078 if (DBG(CONFIG, 1)) {
1079 /* List all the trusted forests */
1080 for (i = 0; i < *num_value; i++) {
1081 idmap_trustedforest_t *f = &(*value)[i];
1082 for (j = 0;
1083 f->domains_in_forest[j].domain[0] != '\0';
1084 j++) {
1085 /* List trusted Domains in the forest. */
1086 if (f->domains_in_forest[j].trusted)
1087 idmapdlog(LOG_INFO,
1088 "change %s=%s domain=%s",
1089 name, f->forest_name,
1090 f->domains_in_forest[j].domain);
1091 }
1092 /* List the hosts */
1093 for (j = 0;
1094 f->global_catalog[j].host[0] != '\0';
1095 j++) {
1096 idmapdlog(LOG_INFO,
1097 "change %s=%s host=%s port=%d",
1098 name, f->forest_name,
1099 f->global_catalog[j].host,
1100 f->global_catalog[j].port);
1101 }
1102 }
1103 }
1104 return (1);
1105 }
1106
1107 const char *
enum_lookup(int value,struct enum_lookup_map * map)1108 enum_lookup(int value, struct enum_lookup_map *map)
1109 {
1110 for (; map->string != NULL; map++) {
1111 if (value == map->value) {
1112 return (map->string);
1113 }
1114 }
1115 return ("(invalid)");
1116 }
1117
1118 /*
1119 * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the
1120 * interfaces.
1121 *
1122 * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON.
1123 */
1124 static
1125 boolean_t
pfroute_event_is_interesting(int rt_sock)1126 pfroute_event_is_interesting(int rt_sock)
1127 {
1128 int nbytes;
1129 int64_t msg[2048 / 8];
1130 struct rt_msghdr *rtm;
1131 boolean_t is_interesting = B_FALSE;
1132
1133 for (;;) {
1134 if ((nbytes = read(rt_sock, msg, sizeof (msg))) <= 0)
1135 break;
1136 rtm = (struct rt_msghdr *)msg;
1137 if (rtm->rtm_version != RTM_VERSION)
1138 continue;
1139 if (nbytes < rtm->rtm_msglen)
1140 continue;
1141 switch (rtm->rtm_type) {
1142 case RTM_NEWADDR:
1143 case RTM_DELADDR:
1144 case RTM_IFINFO:
1145 is_interesting = B_TRUE;
1146 break;
1147 default:
1148 break;
1149 }
1150 }
1151 return (is_interesting);
1152 }
1153
1154 /*
1155 * Wait for an event, and report what kind of event occurred.
1156 *
1157 * Note that there are cases where we are awoken but don't care about
1158 * the lower-level event. We can't just loop here because we can't
1159 * readily calculate how long to sleep the next time. We return
1160 * EVENT_NOTHING and let the caller loop.
1161 */
1162 static
1163 enum event_type
wait_for_event(struct timespec * timeoutp)1164 wait_for_event(struct timespec *timeoutp)
1165 {
1166 port_event_t pe;
1167
1168 (void) memset(&pe, 0, sizeof (pe));
1169 if (port_get(idmapd_ev_port, &pe, timeoutp) != 0) {
1170 switch (errno) {
1171 case EINTR:
1172 return (EVENT_NOTHING);
1173 case ETIME:
1174 /* Timeout */
1175 return (EVENT_TIMEOUT);
1176 default:
1177 /* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */
1178 idmapdlog(LOG_ERR, "Event port failed: %s",
1179 strerror(errno));
1180 exit(1);
1181 /* NOTREACHED */
1182 }
1183 }
1184
1185
1186 switch (pe.portev_source) {
1187 case 0:
1188 /*
1189 * This isn't documented, but seems to be what you get if
1190 * the timeout is zero seconds and there are no events
1191 * pending.
1192 */
1193 return (EVENT_TIMEOUT);
1194
1195 case PORT_SOURCE_USER:
1196 if (pe.portev_events == POKE_AUTO_DISCOVERY)
1197 return (EVENT_DEGRADE);
1198 if (pe.portev_events == RECONFIGURE)
1199 return (EVENT_REFRESH);
1200 break;
1201
1202 case PORT_SOURCE_FD:
1203 if (pe.portev_object == rt_sock) {
1204 /*
1205 * PF_ROUTE socket read event:
1206 * re-associate fd
1207 * handle event
1208 */
1209 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD,
1210 rt_sock, POLLIN, NULL) != 0) {
1211 idmapdlog(LOG_ERR, "Failed to re-associate the "
1212 "routing socket with the event port: %s",
1213 strerror(errno));
1214 abort();
1215 }
1216 /*
1217 * The network configuration may still be in flux.
1218 * No matter, the resolver will re-transmit and
1219 * timeout if need be.
1220 */
1221 if (pfroute_event_is_interesting(rt_sock)) {
1222 if (DBG(CONFIG, 1)) {
1223 idmapdlog(LOG_DEBUG,
1224 "Interesting routing event");
1225 }
1226 return (EVENT_ROUTING);
1227 } else {
1228 if (DBG(CONFIG, 2)) {
1229 idmapdlog(LOG_DEBUG,
1230 "Boring routing event");
1231 }
1232 return (EVENT_NOTHING);
1233 }
1234 }
1235 /* Event on an FD other than the routing FD? Ignore it. */
1236 break;
1237 }
1238
1239 return (EVENT_NOTHING);
1240 }
1241
1242 void *
idmap_cfg_update_thread(void * arg)1243 idmap_cfg_update_thread(void *arg)
1244 {
1245 NOTE(ARGUNUSED(arg))
1246
1247 const ad_disc_t ad_ctx = _idmapdstate.cfg->handles.ad_ctx;
1248
1249 for (;;) {
1250 struct timespec timeout;
1251 struct timespec *timeoutp;
1252 int rc;
1253 int ttl;
1254
1255 (void) ad_disc_SubnetChanged(ad_ctx);
1256
1257 rc = idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER);
1258 if (rc < -1) {
1259 idmapdlog(LOG_ERR, "Fatal errors while reading "
1260 "SMF properties");
1261 exit(1);
1262 } else if (rc == -1) {
1263 idmapdlog(LOG_WARNING,
1264 "Errors re-loading configuration may cause AD "
1265 "lookups to fail");
1266 }
1267
1268 /*
1269 * Wait for an interesting event. Note that we might get
1270 * boring events between interesting events. If so, we loop.
1271 */
1272 for (;;) {
1273 ttl = ad_disc_get_TTL(ad_ctx);
1274
1275 if (ttl < 0) {
1276 timeoutp = NULL;
1277 } else {
1278 timeoutp = &timeout;
1279 timeout.tv_sec = ttl;
1280 timeout.tv_nsec = 0;
1281 }
1282
1283 switch (wait_for_event(timeoutp)) {
1284 case EVENT_NOTHING:
1285 if (DBG(CONFIG, 2))
1286 idmapdlog(LOG_DEBUG, "Boring event.");
1287 continue;
1288 case EVENT_REFRESH:
1289 if (DBG(CONFIG, 1))
1290 idmapdlog(LOG_INFO, "SMF refresh");
1291 /*
1292 * Blow away the ccache, we might have
1293 * re-joined the domain or joined a new one
1294 */
1295 (void) unlink(IDMAP_CACHEDIR "/ccache");
1296 break;
1297 case EVENT_DEGRADE:
1298 if (DBG(CONFIG, 1)) {
1299 idmapdlog(LOG_DEBUG,
1300 "Service degraded");
1301 }
1302 break;
1303 case EVENT_TIMEOUT:
1304 if (DBG(CONFIG, 1))
1305 idmapdlog(LOG_DEBUG, "TTL expired");
1306 break;
1307 case EVENT_ROUTING:
1308 /* Already logged to DEBUG */
1309 break;
1310 }
1311 /* An interesting event! */
1312 break;
1313 }
1314 }
1315 /*
1316 * Lint isn't happy with the concept of a function declared to
1317 * return something, that doesn't return. Of course, merely adding
1318 * the return isn't enough, because it's never reached...
1319 */
1320 /*NOTREACHED*/
1321 return (NULL);
1322 }
1323
1324 int
idmap_cfg_start_updates(void)1325 idmap_cfg_start_updates(void)
1326 {
1327 if ((idmapd_ev_port = port_create()) < 0) {
1328 idmapdlog(LOG_ERR, "Failed to create event port: %s",
1329 strerror(errno));
1330 return (-1);
1331 }
1332
1333 if ((rt_sock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
1334 idmapdlog(LOG_ERR, "Failed to open routing socket: %s",
1335 strerror(errno));
1336 (void) close(idmapd_ev_port);
1337 return (-1);
1338 }
1339
1340 if (fcntl(rt_sock, F_SETFL, O_NDELAY|O_NONBLOCK) < 0) {
1341 idmapdlog(LOG_ERR, "Failed to set routing socket flags: %s",
1342 strerror(errno));
1343 (void) close(rt_sock);
1344 (void) close(idmapd_ev_port);
1345 return (-1);
1346 }
1347
1348 if (port_associate(idmapd_ev_port, PORT_SOURCE_FD,
1349 rt_sock, POLLIN, NULL) != 0) {
1350 idmapdlog(LOG_ERR, "Failed to associate the routing "
1351 "socket with the event port: %s", strerror(errno));
1352 (void) close(rt_sock);
1353 (void) close(idmapd_ev_port);
1354 return (-1);
1355 }
1356
1357 if ((errno = pthread_create(&update_thread_handle, NULL,
1358 idmap_cfg_update_thread, NULL)) != 0) {
1359 idmapdlog(LOG_ERR, "Failed to start update thread: %s",
1360 strerror(errno));
1361 (void) port_dissociate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock);
1362 (void) close(rt_sock);
1363 (void) close(idmapd_ev_port);
1364 return (-1);
1365 }
1366
1367 return (0);
1368 }
1369
1370 /*
1371 * Reject attribute names with invalid characters.
1372 */
1373 static
1374 int
valid_ldap_attr(const char * attr)1375 valid_ldap_attr(const char *attr) {
1376 for (; *attr; attr++) {
1377 if (!isalnum(*attr) && *attr != '-' &&
1378 *attr != '_' && *attr != '.' && *attr != ';')
1379 return (0);
1380 }
1381 return (1);
1382 }
1383
1384 static
1385 void
idmapd_set_debug(idmap_cfg_handles_t * handles,enum idmapd_debug item,const char * name)1386 idmapd_set_debug(
1387 idmap_cfg_handles_t *handles,
1388 enum idmapd_debug item,
1389 const char *name)
1390 {
1391 int val;
1392
1393 if (item < 0 || item > IDMAPD_DEBUG_MAX)
1394 return;
1395
1396 val = get_debug(handles, name);
1397
1398 if (val != _idmapdstate.debug[item])
1399 idmapdlog(LOG_DEBUG, "%s/%s = %d", DEBUG_PG, name, val);
1400
1401 _idmapdstate.debug[item] = val;
1402 }
1403
1404 static
1405 void
check_smf_debug_mode(idmap_cfg_handles_t * handles)1406 check_smf_debug_mode(idmap_cfg_handles_t *handles)
1407 {
1408 idmapd_set_debug(handles, IDMAPD_DEBUG_ALL, "all");
1409 idmapd_set_debug(handles, IDMAPD_DEBUG_CONFIG, "config");
1410 idmapd_set_debug(handles, IDMAPD_DEBUG_MAPPING, "mapping");
1411 idmapd_set_debug(handles, IDMAPD_DEBUG_DISC, "discovery");
1412 idmapd_set_debug(handles, IDMAPD_DEBUG_DNS, "dns");
1413 idmapd_set_debug(handles, IDMAPD_DEBUG_LDAP, "ldap");
1414
1415 adutils_set_debug(AD_DEBUG_ALL, _idmapdstate.debug[IDMAPD_DEBUG_ALL]);
1416 adutils_set_debug(AD_DEBUG_DISC, _idmapdstate.debug[IDMAPD_DEBUG_DISC]);
1417 adutils_set_debug(AD_DEBUG_DNS, _idmapdstate.debug[IDMAPD_DEBUG_DNS]);
1418 adutils_set_debug(AD_DEBUG_LDAP, _idmapdstate.debug[IDMAPD_DEBUG_LDAP]);
1419 }
1420
1421 /*
1422 * This is the half of idmap_cfg_load() that loads property values from
1423 * SMF (using the config/ property group of the idmap FMRI).
1424 *
1425 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
1426 * -3 -> hard smf config failures
1427 * reading from SMF.
1428 */
1429 static
1430 int
idmap_cfg_load_smf(idmap_cfg_handles_t * handles,idmap_pg_config_t * pgcfg,int * const errors)1431 idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
1432 int * const errors)
1433 {
1434 int rc;
1435 char *s;
1436
1437 *errors = 0;
1438
1439 if (scf_pg_update(handles->config_pg) < 0) {
1440 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
1441 scf_strerror(scf_error()));
1442 return (-2);
1443 }
1444
1445 if (scf_pg_update(handles->debug_pg) < 0) {
1446 idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
1447 scf_strerror(scf_error()));
1448 return (-2);
1449 }
1450
1451 check_smf_debug_mode(handles);
1452
1453 rc = get_val_bool(handles, "unresolvable_sid_mapping",
1454 &pgcfg->eph_map_unres_sids, B_TRUE);
1455 if (rc != 0)
1456 (*errors)++;
1457
1458 rc = get_val_bool(handles, "use_ads",
1459 &pgcfg->use_ads, B_TRUE);
1460 if (rc != 0)
1461 (*errors)++;
1462
1463 rc = get_val_bool(handles, "use_lsa",
1464 &pgcfg->use_lsa, B_TRUE);
1465 if (rc != 0)
1466 (*errors)++;
1467
1468 rc = get_val_bool(handles, "disable_cross_forest_trusts",
1469 &pgcfg->disable_cross_forest_trusts, B_TRUE);
1470 if (rc != 0)
1471 (*errors)++;
1472
1473 rc = get_val_astring(handles, "directory_based_mapping", &s);
1474 if (rc != 0)
1475 (*errors)++;
1476 else if (s == NULL || strcasecmp(s, "none") == 0)
1477 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
1478 else if (strcasecmp(s, "name") == 0)
1479 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NAME;
1480 else if (strcasecmp(s, "idmu") == 0)
1481 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_IDMU;
1482 else {
1483 pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
1484 idmapdlog(LOG_ERR,
1485 "config/directory_based_mapping: invalid value \"%s\" ignored",
1486 s);
1487 (*errors)++;
1488 }
1489 free(s);
1490
1491 rc = get_val_int(handles, "list_size_limit",
1492 &pgcfg->list_size_limit, SCF_TYPE_COUNT);
1493 if (rc != 0)
1494 (*errors)++;
1495
1496 rc = get_val_int(handles, "id_cache_timeout",
1497 &pgcfg->id_cache_timeout, SCF_TYPE_COUNT);
1498 if (rc != 0)
1499 (*errors)++;
1500 if (pgcfg->id_cache_timeout == 0)
1501 pgcfg->id_cache_timeout = ID_CACHE_TMO_DEFAULT;
1502
1503 rc = get_val_int(handles, "name_cache_timeout",
1504 &pgcfg->name_cache_timeout, SCF_TYPE_COUNT);
1505 if (rc != 0)
1506 (*errors)++;
1507 if (pgcfg->name_cache_timeout == 0)
1508 pgcfg->name_cache_timeout = NAME_CACHE_TMO_DEFAULT;
1509
1510 rc = get_val_astring(handles, "domain_name",
1511 &pgcfg->domain_name);
1512 if (rc != 0)
1513 (*errors)++;
1514 else {
1515 if (pgcfg->domain_name != NULL &&
1516 pgcfg->domain_name[0] == '\0') {
1517 free(pgcfg->domain_name);
1518 pgcfg->domain_name = NULL;
1519 }
1520 (void) ad_disc_set_DomainName(handles->ad_ctx,
1521 pgcfg->domain_name);
1522 pgcfg->domain_name_auto_disc = B_FALSE;
1523 }
1524
1525 rc = get_val_astring(handles, "default_domain",
1526 &pgcfg->default_domain);
1527 if (rc != 0) {
1528 /*
1529 * SCF failures fetching config/default_domain we treat
1530 * as fatal as they may leave ID mapping rules that
1531 * match unqualified winnames flapping in the wind.
1532 */
1533 return (-2);
1534 }
1535
1536 if (pgcfg->default_domain == NULL && pgcfg->domain_name != NULL) {
1537 pgcfg->default_domain = strdup(pgcfg->domain_name);
1538 }
1539
1540 rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid);
1541 if (rc != 0)
1542 (*errors)++;
1543 if (pgcfg->machine_sid == NULL) {
1544 /* If machine_sid not configured, generate one */
1545 if (generate_machine_sid(&pgcfg->machine_sid) < 0)
1546 return (-2);
1547 rc = set_val_astring(handles, handles->config_pg,
1548 "machine_sid", pgcfg->machine_sid);
1549 if (rc != 0)
1550 (*errors)++;
1551 }
1552
1553 rc = get_val_ds(handles, "domain_controller", 389,
1554 &pgcfg->domain_controller);
1555 if (rc != 0)
1556 (*errors)++;
1557 else {
1558 (void) ad_disc_set_DomainController(handles->ad_ctx,
1559 pgcfg->domain_controller);
1560 pgcfg->domain_controller_auto_disc = B_FALSE;
1561 }
1562
1563 rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name);
1564 if (rc != 0)
1565 (*errors)++;
1566 else {
1567 (void) ad_disc_set_ForestName(handles->ad_ctx,
1568 pgcfg->forest_name);
1569 pgcfg->forest_name_auto_disc = B_FALSE;
1570 }
1571
1572 rc = get_val_astring(handles, "site_name", &pgcfg->site_name);
1573 if (rc != 0)
1574 (*errors)++;
1575 else
1576 (void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name);
1577
1578 rc = get_val_ds(handles, "global_catalog", 3268,
1579 &pgcfg->global_catalog);
1580 if (rc != 0)
1581 (*errors)++;
1582 else {
1583 (void) ad_disc_set_GlobalCatalog(handles->ad_ctx,
1584 pgcfg->global_catalog);
1585 pgcfg->global_catalog_auto_disc = B_FALSE;
1586 }
1587
1588 /* Unless we're doing directory-based name mapping, we're done. */
1589 if (pgcfg->directory_based_mapping != DIRECTORY_MAPPING_NAME)
1590 return (0);
1591
1592 rc = get_val_astring(handles, "ad_unixuser_attr",
1593 &pgcfg->ad_unixuser_attr);
1594 if (rc != 0)
1595 return (-2);
1596 if (pgcfg->ad_unixuser_attr != NULL &&
1597 !valid_ldap_attr(pgcfg->ad_unixuser_attr)) {
1598 idmapdlog(LOG_ERR, "config/ad_unixuser_attr=%s is not a "
1599 "valid LDAP attribute name", pgcfg->ad_unixuser_attr);
1600 return (-3);
1601 }
1602
1603 rc = get_val_astring(handles, "ad_unixgroup_attr",
1604 &pgcfg->ad_unixgroup_attr);
1605 if (rc != 0)
1606 return (-2);
1607 if (pgcfg->ad_unixgroup_attr != NULL &&
1608 !valid_ldap_attr(pgcfg->ad_unixgroup_attr)) {
1609 idmapdlog(LOG_ERR, "config/ad_unixgroup_attr=%s is not a "
1610 "valid LDAP attribute name", pgcfg->ad_unixgroup_attr);
1611 return (-3);
1612 }
1613
1614 rc = get_val_astring(handles, "nldap_winname_attr",
1615 &pgcfg->nldap_winname_attr);
1616 if (rc != 0)
1617 return (-2);
1618 if (pgcfg->nldap_winname_attr != NULL &&
1619 !valid_ldap_attr(pgcfg->nldap_winname_attr)) {
1620 idmapdlog(LOG_ERR, "config/nldap_winname_attr=%s is not a "
1621 "valid LDAP attribute name", pgcfg->nldap_winname_attr);
1622 return (-3);
1623 }
1624 if (pgcfg->ad_unixuser_attr == NULL &&
1625 pgcfg->ad_unixgroup_attr == NULL &&
1626 pgcfg->nldap_winname_attr == NULL) {
1627 idmapdlog(LOG_ERR,
1628 "If config/directory_based_mapping property is set to "
1629 "\"name\" then at least one of the following name mapping "
1630 "attributes must be specified. (config/ad_unixuser_attr OR "
1631 "config/ad_unixgroup_attr OR config/nldap_winname_attr)");
1632 return (-3);
1633 }
1634
1635 return (rc);
1636
1637 }
1638
1639 static
1640 void
log_if_unable(const void * val,const char * what)1641 log_if_unable(const void *val, const char *what)
1642 {
1643 if (val == NULL) {
1644 idmapdlog(LOG_DEBUG, "unable to discover %s", what);
1645 }
1646 }
1647
1648 static
1649 void
discover_trusted_domains(idmap_pg_config_t * pgcfg,ad_disc_t ad_ctx)1650 discover_trusted_domains(idmap_pg_config_t *pgcfg, ad_disc_t ad_ctx)
1651 {
1652 ad_disc_t trusted_ctx;
1653 int i, j, k, l;
1654 char *forestname;
1655 int num_trusteddomains;
1656 boolean_t new_forest;
1657 char *trusteddomain;
1658 idmap_ad_disc_ds_t *globalcatalog;
1659 idmap_trustedforest_t *trustedforests;
1660 ad_disc_domainsinforest_t *domainsinforest;
1661
1662 pgcfg->trusted_domains =
1663 ad_disc_get_TrustedDomains(ad_ctx, NULL);
1664
1665 if (pgcfg->forest_name != NULL && pgcfg->trusted_domains != NULL &&
1666 pgcfg->trusted_domains[0].domain[0] != '\0') {
1667 /*
1668 * We have trusted domains. We need to go through every
1669 * one and find its forest. If it is a new forest we then need
1670 * to find its Global Catalog and the domains in the forest
1671 */
1672 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++)
1673 continue;
1674 num_trusteddomains = i;
1675
1676 trustedforests = calloc(num_trusteddomains,
1677 sizeof (idmap_trustedforest_t));
1678 j = 0;
1679 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++) {
1680 trusteddomain = pgcfg->trusted_domains[i].domain;
1681 trusted_ctx = ad_disc_init();
1682 (void) ad_disc_set_DomainName(trusted_ctx,
1683 trusteddomain);
1684 forestname =
1685 ad_disc_get_ForestName(trusted_ctx, NULL);
1686 if (forestname == NULL) {
1687 if (DBG(CONFIG, 1)) {
1688 idmapdlog(LOG_DEBUG,
1689 "unable to discover Forest Name"
1690 " for the trusted domain %s",
1691 trusteddomain);
1692 }
1693 ad_disc_fini(trusted_ctx);
1694 continue;
1695 }
1696
1697 if (strcasecmp(forestname, pgcfg->forest_name) == 0) {
1698 /*
1699 * Ignore the domain as it is part of
1700 * the primary forest
1701 */
1702 free(forestname);
1703 ad_disc_fini(trusted_ctx);
1704 continue;
1705 }
1706
1707 /* Is this a new forest? */
1708 new_forest = B_TRUE;
1709 for (k = 0; k < j; k++) {
1710 if (strcasecmp(forestname,
1711 trustedforests[k].forest_name) == 0) {
1712 new_forest = B_FALSE;
1713 domainsinforest =
1714 trustedforests[k].domains_in_forest;
1715 break;
1716 }
1717 }
1718 if (!new_forest) {
1719 /* Mark the domain as trusted */
1720 for (l = 0;
1721 domainsinforest[l].domain[0] != '\0'; l++) {
1722 if (domain_eq(trusteddomain,
1723 domainsinforest[l].domain)) {
1724 domainsinforest[l].trusted =
1725 TRUE;
1726 break;
1727 }
1728 }
1729 free(forestname);
1730 ad_disc_fini(trusted_ctx);
1731 continue;
1732 }
1733
1734 /*
1735 * Get the Global Catalog and the domains in
1736 * this new forest.
1737 */
1738 globalcatalog =
1739 ad_disc_get_GlobalCatalog(trusted_ctx,
1740 AD_DISC_PREFER_SITE, NULL);
1741 if (globalcatalog == NULL) {
1742 if (DBG(CONFIG, 1)) {
1743 idmapdlog(LOG_DEBUG,
1744 "unable to discover Global Catalog"
1745 " for the trusted domain %s",
1746 trusteddomain);
1747 }
1748 free(forestname);
1749 ad_disc_fini(trusted_ctx);
1750 continue;
1751 }
1752 domainsinforest =
1753 ad_disc_get_DomainsInForest(trusted_ctx,
1754 NULL);
1755 if (domainsinforest == NULL) {
1756 if (DBG(CONFIG, 1)) {
1757 idmapdlog(LOG_DEBUG,
1758 "unable to discover Domains in the"
1759 " Forest for the trusted domain %s",
1760 trusteddomain);
1761 }
1762 free(globalcatalog);
1763 free(forestname);
1764 ad_disc_fini(trusted_ctx);
1765 continue;
1766 }
1767
1768 trustedforests[j].forest_name = forestname;
1769 trustedforests[j].global_catalog = globalcatalog;
1770 trustedforests[j].domains_in_forest = domainsinforest;
1771 j++;
1772 /* Mark the domain as trusted */
1773 for (l = 0; domainsinforest[l].domain[0] != '\0';
1774 l++) {
1775 if (domain_eq(trusteddomain,
1776 domainsinforest[l].domain)) {
1777 domainsinforest[l].trusted = TRUE;
1778 break;
1779 }
1780 }
1781 ad_disc_fini(trusted_ctx);
1782 }
1783 if (j > 0) {
1784 pgcfg->num_trusted_forests = j;
1785 pgcfg->trusted_forests = trustedforests;
1786 } else {
1787 free(trustedforests);
1788 }
1789 }
1790 }
1791
1792 /*
1793 * This is the half of idmap_cfg_load() that auto-discovers values of
1794 * discoverable properties that weren't already set via SMF properties.
1795 *
1796 * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it
1797 * needs to be careful not to overwrite any properties set in SMF.
1798 */
1799 static
1800 void
idmap_cfg_discover(idmap_cfg_handles_t * handles,idmap_pg_config_t * pgcfg)1801 idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg)
1802 {
1803 ad_disc_t ad_ctx = handles->ad_ctx;
1804
1805 if (pgcfg->use_ads == B_FALSE) {
1806 if (DBG(CONFIG, 1))
1807 idmapdlog(LOG_DEBUG, "ADS disabled.");
1808 return;
1809 }
1810
1811 if (DBG(CONFIG, 1))
1812 idmapdlog(LOG_DEBUG, "Running discovery.");
1813
1814 ad_disc_refresh(ad_ctx);
1815
1816 if (pgcfg->domain_name == NULL) {
1817 idmapdlog(LOG_DEBUG, "No domain name specified.");
1818 } else {
1819 if (pgcfg->domain_controller == NULL)
1820 pgcfg->domain_controller =
1821 ad_disc_get_DomainController(ad_ctx,
1822 AD_DISC_PREFER_SITE,
1823 &pgcfg->domain_controller_auto_disc);
1824
1825 if (pgcfg->forest_name == NULL)
1826 pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx,
1827 &pgcfg->forest_name_auto_disc);
1828
1829 if (pgcfg->site_name == NULL)
1830 pgcfg->site_name = ad_disc_get_SiteName(ad_ctx,
1831 &pgcfg->site_name_auto_disc);
1832
1833 if (pgcfg->global_catalog == NULL)
1834 pgcfg->global_catalog =
1835 ad_disc_get_GlobalCatalog(ad_ctx,
1836 AD_DISC_PREFER_SITE,
1837 &pgcfg->global_catalog_auto_disc);
1838
1839 pgcfg->domains_in_forest =
1840 ad_disc_get_DomainsInForest(ad_ctx, NULL);
1841
1842 if (!pgcfg->disable_cross_forest_trusts)
1843 discover_trusted_domains(pgcfg, ad_ctx);
1844
1845 if (DBG(CONFIG, 1)) {
1846 log_if_unable(pgcfg->domain_name, "Domain Name");
1847 log_if_unable(pgcfg->domain_controller,
1848 "Domain Controller");
1849 log_if_unable(pgcfg->forest_name, "Forest Name");
1850 log_if_unable(pgcfg->site_name, "Site Name");
1851 log_if_unable(pgcfg->global_catalog, "Global Catalog");
1852 log_if_unable(pgcfg->domains_in_forest,
1853 "Domains in the Forest");
1854 if (!pgcfg->disable_cross_forest_trusts) {
1855 log_if_unable(pgcfg->trusted_domains,
1856 "Trusted Domains");
1857 }
1858 }
1859 }
1860
1861 ad_disc_done(ad_ctx);
1862
1863 if (DBG(CONFIG, 1))
1864 idmapdlog(LOG_DEBUG, "Discovery done.");
1865 }
1866
1867
1868 /*
1869 * idmap_cfg_load() is called at startup, and periodically via the
1870 * update thread when the auto-discovery TTLs expire, as well as part of
1871 * the refresh method, to update the current configuration. It always
1872 * reads from SMF, but you still have to refresh the service after
1873 * changing the config pg in order for the changes to take effect.
1874 *
1875 * There is one flag:
1876 *
1877 * - CFG_DISCOVER
1878 *
1879 * If CFG_DISCOVER is set then idmap_cfg_load() calls
1880 * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property
1881 * values that weren't set in SMF.
1882 *
1883 * idmap_cfg_load() will log (to LOG_NOTICE) whether the configuration
1884 * changed.
1885 *
1886 * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
1887 * reading from SMF.
1888 */
1889 int
idmap_cfg_load(idmap_cfg_t * cfg,int flags)1890 idmap_cfg_load(idmap_cfg_t *cfg, int flags)
1891 {
1892 int rc = 0;
1893 int errors;
1894 int changed = 0;
1895 int ad_reload_required = 0;
1896 idmap_pg_config_t new_pgcfg, *live_pgcfg;
1897
1898 if (DBG(CONFIG, 1))
1899 idmapdlog(LOG_DEBUG, "Loading configuration.");
1900
1901 live_pgcfg = &cfg->pgcfg;
1902 (void) memset(&new_pgcfg, 0, sizeof (new_pgcfg));
1903
1904 (void) pthread_mutex_lock(&cfg->handles.mutex);
1905
1906 if ((rc = idmap_cfg_load_smf(&cfg->handles, &new_pgcfg, &errors)) < -1)
1907 goto err;
1908
1909 if (flags & CFG_DISCOVER)
1910 idmap_cfg_discover(&cfg->handles, &new_pgcfg);
1911
1912 WRLOCK_CONFIG();
1913 /* Non-discoverable props updated here */
1914
1915 changed += update_uint64(&live_pgcfg->list_size_limit,
1916 &new_pgcfg.list_size_limit, "list_size_limit");
1917
1918 changed += update_uint64(&live_pgcfg->id_cache_timeout,
1919 &new_pgcfg.id_cache_timeout, "id_cache_timeout");
1920
1921 changed += update_uint64(&live_pgcfg->name_cache_timeout,
1922 &new_pgcfg.name_cache_timeout, "name_cache_timeout");
1923
1924 changed += update_string(&live_pgcfg->machine_sid,
1925 &new_pgcfg.machine_sid, "machine_sid");
1926
1927 changed += update_bool(&live_pgcfg->eph_map_unres_sids,
1928 &new_pgcfg.eph_map_unres_sids, "unresolvable_sid_mapping");
1929
1930 changed += update_bool(&live_pgcfg->use_ads,
1931 &new_pgcfg.use_ads, "use_ads");
1932
1933 changed += update_bool(&live_pgcfg->use_lsa,
1934 &new_pgcfg.use_lsa, "use_lsa");
1935
1936 changed += update_bool(&live_pgcfg->disable_cross_forest_trusts,
1937 &new_pgcfg.disable_cross_forest_trusts,
1938 "disable_cross_forest_trusts");
1939
1940 changed += update_enum(&live_pgcfg->directory_based_mapping,
1941 &new_pgcfg.directory_based_mapping, "directory_based_mapping",
1942 directory_mapping_map);
1943
1944 changed += update_string(&live_pgcfg->ad_unixuser_attr,
1945 &new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr");
1946
1947 changed += update_string(&live_pgcfg->ad_unixgroup_attr,
1948 &new_pgcfg.ad_unixgroup_attr, "ad_unixgroup_attr");
1949
1950 changed += update_string(&live_pgcfg->nldap_winname_attr,
1951 &new_pgcfg.nldap_winname_attr, "nldap_winname_attr");
1952
1953 /* Props that can be discovered and set in SMF updated here */
1954 changed += update_string(&live_pgcfg->default_domain,
1955 &new_pgcfg.default_domain, "default_domain");
1956
1957 changed += update_string(&live_pgcfg->domain_name,
1958 &new_pgcfg.domain_name, "domain_name");
1959 live_pgcfg->domain_name_auto_disc = new_pgcfg.domain_name_auto_disc;
1960
1961 changed += update_dirs(&live_pgcfg->domain_controller,
1962 &new_pgcfg.domain_controller, "domain_controller");
1963 live_pgcfg->domain_controller_auto_disc =
1964 new_pgcfg.domain_controller_auto_disc;
1965
1966 changed += update_string(&live_pgcfg->forest_name,
1967 &new_pgcfg.forest_name, "forest_name");
1968 live_pgcfg->forest_name_auto_disc = new_pgcfg.forest_name_auto_disc;
1969
1970 changed += update_string(&live_pgcfg->site_name,
1971 &new_pgcfg.site_name, "site_name");
1972 live_pgcfg->site_name_auto_disc = new_pgcfg.site_name_auto_disc;
1973
1974 if (update_dirs(&live_pgcfg->global_catalog,
1975 &new_pgcfg.global_catalog, "global_catalog")) {
1976 changed++;
1977 if (live_pgcfg->global_catalog != NULL &&
1978 live_pgcfg->global_catalog[0].host[0] != '\0')
1979 ad_reload_required = TRUE;
1980 }
1981 live_pgcfg->global_catalog_auto_disc =
1982 new_pgcfg.global_catalog_auto_disc;
1983
1984 if (update_domains_in_forest(&live_pgcfg->domains_in_forest,
1985 &new_pgcfg.domains_in_forest, "domains_in_forest")) {
1986 changed++;
1987 ad_reload_required = TRUE;
1988 }
1989
1990 if (update_trusted_domains(&live_pgcfg->trusted_domains,
1991 &new_pgcfg.trusted_domains, "trusted_domains")) {
1992 changed++;
1993 if (live_pgcfg->trusted_domains != NULL &&
1994 live_pgcfg->trusted_domains[0].domain[0] != '\0')
1995 ad_reload_required = TRUE;
1996 }
1997
1998 if (update_trusted_forest(&live_pgcfg->trusted_forests,
1999 &live_pgcfg->num_trusted_forests, &new_pgcfg.trusted_forests,
2000 &new_pgcfg.num_trusted_forests, "trusted_forest")) {
2001 changed++;
2002 if (live_pgcfg->trusted_forests != NULL)
2003 ad_reload_required = TRUE;
2004 }
2005
2006 if (ad_reload_required)
2007 reload_ad();
2008
2009 idmap_cfg_unload(&new_pgcfg);
2010
2011 if (DBG(CONFIG, 1)) {
2012 if (changed)
2013 idmapdlog(LOG_NOTICE, "Configuration changed");
2014 else
2015 idmapdlog(LOG_NOTICE, "Configuration unchanged");
2016 }
2017
2018 UNLOCK_CONFIG();
2019
2020 err:
2021 (void) pthread_mutex_unlock(&cfg->handles.mutex);
2022
2023 if (rc < -1)
2024 return (rc);
2025
2026 return ((errors == 0) ? 0 : -1);
2027 }
2028
2029 /*
2030 * Initialize 'cfg'.
2031 */
2032 idmap_cfg_t *
idmap_cfg_init()2033 idmap_cfg_init()
2034 {
2035 idmap_cfg_handles_t *handles;
2036
2037 /* First the smf repository handles: */
2038 idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t));
2039 if (!cfg) {
2040 idmapdlog(LOG_ERR, "Out of memory");
2041 return (NULL);
2042 }
2043 handles = &cfg->handles;
2044
2045 (void) pthread_mutex_init(&handles->mutex, NULL);
2046
2047 if (!(handles->main = scf_handle_create(SCF_VERSION))) {
2048 idmapdlog(LOG_ERR, "scf_handle_create() failed: %s",
2049 scf_strerror(scf_error()));
2050 goto error;
2051 }
2052
2053 if (scf_handle_bind(handles->main) < 0) {
2054 idmapdlog(LOG_ERR, "scf_handle_bind() failed: %s",
2055 scf_strerror(scf_error()));
2056 goto error;
2057 }
2058
2059 if (!(handles->service = scf_service_create(handles->main)) ||
2060 !(handles->instance = scf_instance_create(handles->main)) ||
2061 !(handles->config_pg = scf_pg_create(handles->main)) ||
2062 !(handles->debug_pg = scf_pg_create(handles->main))) {
2063 idmapdlog(LOG_ERR, "scf handle creation failed: %s",
2064 scf_strerror(scf_error()));
2065 goto error;
2066 }
2067
2068 if (scf_handle_decode_fmri(handles->main,
2069 FMRI_BASE "/:properties/" CONFIG_PG,
2070 NULL, /* scope */
2071 handles->service, /* service */
2072 handles->instance, /* instance */
2073 handles->config_pg, /* pg */
2074 NULL, /* prop */
2075 SCF_DECODE_FMRI_EXACT) < 0) {
2076 idmapdlog(LOG_ERR, "scf_handle_decode_fmri() failed: %s",
2077 scf_strerror(scf_error()));
2078 goto error;
2079 }
2080
2081 if (scf_service_get_pg(handles->service,
2082 DEBUG_PG, handles->debug_pg) < 0) {
2083 idmapdlog(LOG_ERR, "Property group \"%s\": %s",
2084 DEBUG_PG, scf_strerror(scf_error()));
2085 goto error;
2086 }
2087
2088 check_smf_debug_mode(handles);
2089
2090 /* Initialize AD Auto Discovery context */
2091 handles->ad_ctx = ad_disc_init();
2092 if (handles->ad_ctx == NULL)
2093 goto error;
2094
2095 return (cfg);
2096
2097 error:
2098 (void) idmap_cfg_fini(cfg);
2099 return (NULL);
2100 }
2101
2102 void
idmap_cfg_unload(idmap_pg_config_t * pgcfg)2103 idmap_cfg_unload(idmap_pg_config_t *pgcfg)
2104 {
2105
2106 if (pgcfg->default_domain) {
2107 free(pgcfg->default_domain);
2108 pgcfg->default_domain = NULL;
2109 }
2110 if (pgcfg->domain_name) {
2111 free(pgcfg->domain_name);
2112 pgcfg->domain_name = NULL;
2113 }
2114 if (pgcfg->machine_sid) {
2115 free(pgcfg->machine_sid);
2116 pgcfg->machine_sid = NULL;
2117 }
2118 if (pgcfg->domain_controller) {
2119 free(pgcfg->domain_controller);
2120 pgcfg->domain_controller = NULL;
2121 }
2122 if (pgcfg->forest_name) {
2123 free(pgcfg->forest_name);
2124 pgcfg->forest_name = NULL;
2125 }
2126 if (pgcfg->site_name) {
2127 free(pgcfg->site_name);
2128 pgcfg->site_name = NULL;
2129 }
2130 if (pgcfg->global_catalog) {
2131 free(pgcfg->global_catalog);
2132 pgcfg->global_catalog = NULL;
2133 }
2134 if (pgcfg->trusted_domains) {
2135 free(pgcfg->trusted_domains);
2136 pgcfg->trusted_domains = NULL;
2137 }
2138 if (pgcfg->trusted_forests)
2139 free_trusted_forests(&pgcfg->trusted_forests,
2140 &pgcfg->num_trusted_forests);
2141
2142 if (pgcfg->ad_unixuser_attr) {
2143 free(pgcfg->ad_unixuser_attr);
2144 pgcfg->ad_unixuser_attr = NULL;
2145 }
2146 if (pgcfg->ad_unixgroup_attr) {
2147 free(pgcfg->ad_unixgroup_attr);
2148 pgcfg->ad_unixgroup_attr = NULL;
2149 }
2150 if (pgcfg->nldap_winname_attr) {
2151 free(pgcfg->nldap_winname_attr);
2152 pgcfg->nldap_winname_attr = NULL;
2153 }
2154 }
2155
2156 int
idmap_cfg_fini(idmap_cfg_t * cfg)2157 idmap_cfg_fini(idmap_cfg_t *cfg)
2158 {
2159 idmap_cfg_handles_t *handles = &cfg->handles;
2160 idmap_cfg_unload(&cfg->pgcfg);
2161
2162 (void) pthread_mutex_destroy(&handles->mutex);
2163 scf_pg_destroy(handles->config_pg);
2164 if (handles->debug_pg != NULL)
2165 scf_pg_destroy(handles->debug_pg);
2166 scf_instance_destroy(handles->instance);
2167 scf_service_destroy(handles->service);
2168 scf_handle_destroy(handles->main);
2169 if (handles->ad_ctx != NULL)
2170 ad_disc_fini(handles->ad_ctx);
2171 free(cfg);
2172
2173 return (0);
2174 }
2175
2176 void
idmap_cfg_poke_updates(void)2177 idmap_cfg_poke_updates(void)
2178 {
2179 if (idmapd_ev_port != -1)
2180 (void) port_send(idmapd_ev_port, POKE_AUTO_DISCOVERY, NULL);
2181 }
2182
2183 /*ARGSUSED*/
2184 void
idmap_cfg_hup_handler(int sig)2185 idmap_cfg_hup_handler(int sig)
2186 {
2187 if (idmapd_ev_port >= 0)
2188 (void) port_send(idmapd_ev_port, RECONFIGURE, NULL);
2189 }
2190
2191 /*
2192 * Upgrade the debug flags.
2193 *
2194 * We're replacing a single debug flag with a fine-grained mechanism that
2195 * is also capable of considerably more verbosity. We'll take a stab at
2196 * producing roughly the same level of output.
2197 */
2198 static
2199 int
upgrade_debug(idmap_cfg_handles_t * handles)2200 upgrade_debug(idmap_cfg_handles_t *handles)
2201 {
2202 boolean_t debug_present;
2203 const char DEBUG_PROP[] = "debug";
2204 int rc;
2205
2206 rc = prop_exists(handles, DEBUG_PROP, &debug_present);
2207
2208 if (rc != 0)
2209 return (rc);
2210
2211 if (!debug_present)
2212 return (0);
2213
2214 idmapdlog(LOG_INFO,
2215 "Upgrading old %s/%s setting to %s/* settings.",
2216 CONFIG_PG, DEBUG_PROP, DEBUG_PG);
2217
2218 rc = set_val_integer(handles, handles->debug_pg, "config", 1);
2219 if (rc != 0)
2220 return (rc);
2221 rc = set_val_integer(handles, handles->debug_pg, "discovery", 1);
2222 if (rc != 0)
2223 return (rc);
2224
2225 rc = del_val(handles, handles->config_pg, DEBUG_PROP);
2226 if (rc != 0)
2227 return (rc);
2228
2229 return (0);
2230 }
2231
2232 /*
2233 * Upgrade the DS mapping flags.
2234 *
2235 * If the old ds_name_mapping_enabled flag is present, then
2236 * if the new directory_based_mapping value is present, then
2237 * if the two are compatible, delete the old and note it
2238 * else delete the old and warn
2239 * else
2240 * set the new based on the old, and note it
2241 * delete the old
2242 */
2243 static
2244 int
upgrade_directory_mapping(idmap_cfg_handles_t * handles)2245 upgrade_directory_mapping(idmap_cfg_handles_t *handles)
2246 {
2247 boolean_t legacy_ds_name_mapping_present;
2248 const char DS_NAME_MAPPING_ENABLED[] = "ds_name_mapping_enabled";
2249 const char DIRECTORY_BASED_MAPPING[] = "directory_based_mapping";
2250 int rc;
2251
2252 rc = prop_exists(handles, DS_NAME_MAPPING_ENABLED,
2253 &legacy_ds_name_mapping_present);
2254
2255 if (rc != 0)
2256 return (rc);
2257
2258 if (!legacy_ds_name_mapping_present)
2259 return (0);
2260
2261 boolean_t legacy_ds_name_mapping_enabled;
2262 rc = get_val_bool(handles, DS_NAME_MAPPING_ENABLED,
2263 &legacy_ds_name_mapping_enabled, B_FALSE);
2264 if (rc != 0)
2265 return (rc);
2266
2267 char *legacy_mode;
2268 char *legacy_bool_string;
2269 if (legacy_ds_name_mapping_enabled) {
2270 legacy_mode = "name";
2271 legacy_bool_string = "true";
2272 } else {
2273 legacy_mode = "none";
2274 legacy_bool_string = "false";
2275 }
2276
2277 char *directory_based_mapping;
2278 rc = get_val_astring(handles, DIRECTORY_BASED_MAPPING,
2279 &directory_based_mapping);
2280 if (rc != 0)
2281 return (rc);
2282
2283 if (directory_based_mapping == NULL) {
2284 idmapdlog(LOG_INFO,
2285 "Upgrading old %s=%s setting\n"
2286 "to %s=%s.",
2287 DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2288 DIRECTORY_BASED_MAPPING, legacy_mode);
2289 rc = set_val_astring(handles, handles->config_pg,
2290 DIRECTORY_BASED_MAPPING, legacy_mode);
2291 if (rc != 0)
2292 return (rc);
2293 } else {
2294 boolean_t new_name_mapping;
2295 if (strcasecmp(directory_based_mapping, "name") == 0)
2296 new_name_mapping = B_TRUE;
2297 else
2298 new_name_mapping = B_FALSE;
2299
2300 if (legacy_ds_name_mapping_enabled == new_name_mapping) {
2301 idmapdlog(LOG_INFO,
2302 "Automatically removing old %s=%s setting\n"
2303 "in favor of %s=%s.",
2304 DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2305 DIRECTORY_BASED_MAPPING, directory_based_mapping);
2306 } else {
2307 idmapdlog(LOG_WARNING,
2308 "Removing conflicting %s=%s setting\n"
2309 "in favor of %s=%s.",
2310 DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2311 DIRECTORY_BASED_MAPPING, directory_based_mapping);
2312 }
2313 free(directory_based_mapping);
2314 }
2315
2316 rc = del_val(handles, handles->config_pg, DS_NAME_MAPPING_ENABLED);
2317 if (rc != 0)
2318 return (rc);
2319
2320 return (0);
2321 }
2322
2323 /*
2324 * Do whatever is necessary to upgrade idmap's configuration before
2325 * we load it.
2326 */
2327 int
idmap_cfg_upgrade(idmap_cfg_t * cfg)2328 idmap_cfg_upgrade(idmap_cfg_t *cfg)
2329 {
2330 int rc;
2331
2332 rc = upgrade_directory_mapping(&cfg->handles);
2333 if (rc != 0)
2334 return (rc);
2335
2336 rc = upgrade_debug(&cfg->handles);
2337 if (rc != 0)
2338 return (rc);
2339
2340 return (0);
2341 }
2342