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