1*c5c4113dSnw /*
2*c5c4113dSnw  * CDDL HEADER START
3*c5c4113dSnw  *
4*c5c4113dSnw  * The contents of this file are subject to the terms of the
5*c5c4113dSnw  * Common Development and Distribution License (the "License").
6*c5c4113dSnw  * You may not use this file except in compliance with the License.
7*c5c4113dSnw  *
8*c5c4113dSnw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*c5c4113dSnw  * or http://www.opensolaris.org/os/licensing.
10*c5c4113dSnw  * See the License for the specific language governing permissions
11*c5c4113dSnw  * and limitations under the License.
12*c5c4113dSnw  *
13*c5c4113dSnw  * When distributing Covered Code, include this CDDL HEADER in each
14*c5c4113dSnw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*c5c4113dSnw  * If applicable, add the following below this CDDL HEADER, with the
16*c5c4113dSnw  * fields enclosed by brackets "[]" replaced with your own identifying
17*c5c4113dSnw  * information: Portions Copyright [yyyy] [name of copyright owner]
18*c5c4113dSnw  *
19*c5c4113dSnw  * CDDL HEADER END
20*c5c4113dSnw  */
21*c5c4113dSnw /*
22*c5c4113dSnw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*c5c4113dSnw  * Use is subject to license terms.
24*c5c4113dSnw  */
25*c5c4113dSnw 
26*c5c4113dSnw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*c5c4113dSnw 
28*c5c4113dSnw /*
29*c5c4113dSnw  * Config routines common to idmap(1M) and idmapd(1M)
30*c5c4113dSnw  */
31*c5c4113dSnw 
32*c5c4113dSnw #include <stdlib.h>
33*c5c4113dSnw #include <synch.h>
34*c5c4113dSnw #include <assert.h>
35*c5c4113dSnw #include <sys/varargs.h>
36*c5c4113dSnw #include <sys/systeminfo.h>
37*c5c4113dSnw #include <strings.h>
38*c5c4113dSnw #include <libintl.h>
39*c5c4113dSnw #include <ctype.h>
40*c5c4113dSnw #include <errno.h>
41*c5c4113dSnw #include "idmap_config.h"
42*c5c4113dSnw #include <stdio.h>
43*c5c4113dSnw #include <stdarg.h>
44*c5c4113dSnw 
45*c5c4113dSnw #define	FMRI_BASE "svc:/system/idmap"
46*c5c4113dSnw 
47*c5c4113dSnw #define	CONFIG_PG "config"
48*c5c4113dSnw #define	GENERAL_PG "general"
49*c5c4113dSnw 
50*c5c4113dSnw #define	IDMAP_CFG_DEBUG 0
51*c5c4113dSnw 
52*c5c4113dSnw /* initial length of the array for policy options/attributes: */
53*c5c4113dSnw #define	DEF_ARRAY_LENGTH 16
54*c5c4113dSnw 
55*c5c4113dSnw static char errmess_buf [1000] =
56*c5c4113dSnw 	"Internal error: idmap configuration has not been initialized";
57*c5c4113dSnw 
58*c5c4113dSnw static void
59*c5c4113dSnw errmess(char *format, va_list ap)
60*c5c4113dSnw {
61*c5c4113dSnw /*LINTED: E_SEC_PRINTF_VAR_FMT*/
62*c5c4113dSnw 	(void) vsnprintf(errmess_buf, sizeof (errmess_buf), format, ap);
63*c5c4113dSnw 	(void) strlcat(errmess_buf, gettext(".\n"), sizeof (errmess_buf));
64*c5c4113dSnw 
65*c5c4113dSnw #if IDMAP_CFG_DEBUG
66*c5c4113dSnw 	(void) fprintf(stderr, errmess_buf);
67*c5c4113dSnw 	fflush(stderr);
68*c5c4113dSnw #endif
69*c5c4113dSnw }
70*c5c4113dSnw 
71*c5c4113dSnw 
72*c5c4113dSnw static void
73*c5c4113dSnw idmap_error(char *format, ...)
74*c5c4113dSnw {
75*c5c4113dSnw 	va_list ap;
76*c5c4113dSnw 	va_start(ap, format);
77*c5c4113dSnw 	errmess(format, ap);
78*c5c4113dSnw 	va_end(ap);
79*c5c4113dSnw }
80*c5c4113dSnw 
81*c5c4113dSnw static void
82*c5c4113dSnw idmap_scf_error(char *format, ...)
83*c5c4113dSnw {
84*c5c4113dSnw 	const char *scf_message;
85*c5c4113dSnw 	char *new_format;
86*c5c4113dSnw 	char *sep;
87*c5c4113dSnw 	va_list ap;
88*c5c4113dSnw 
89*c5c4113dSnw 	sep = gettext(": ");
90*c5c4113dSnw 	va_start(ap, format);
91*c5c4113dSnw 
92*c5c4113dSnw 	scf_message = scf_strerror(scf_error());
93*c5c4113dSnw 	new_format = (char *) malloc(sizeof (char) *
94*c5c4113dSnw 	    (strlen(format) + strlen(scf_message) + strlen(sep) + 1));
95*c5c4113dSnw 
96*c5c4113dSnw 	(void) strcpy(new_format, format);
97*c5c4113dSnw 	(void) strcat(new_format, sep);
98*c5c4113dSnw 	(void) strcat(new_format, scf_message);
99*c5c4113dSnw 
100*c5c4113dSnw 	errmess(new_format, ap);
101*c5c4113dSnw 
102*c5c4113dSnw 	va_end(ap);
103*c5c4113dSnw 	free(new_format);
104*c5c4113dSnw }
105*c5c4113dSnw 
106*c5c4113dSnw char *
107*c5c4113dSnw idmap_cfg_error() {
108*c5c4113dSnw 	return (errmess_buf);
109*c5c4113dSnw }
110*c5c4113dSnw 
111*c5c4113dSnw /* Check if in the case of failure the original value of *val is preserved */
112*c5c4113dSnw static int
113*c5c4113dSnw get_val_int(idmap_cfg_t *cfg, char *name, void *val, scf_type_t type)
114*c5c4113dSnw {
115*c5c4113dSnw 	int rc = 0;
116*c5c4113dSnw 
117*c5c4113dSnw 	scf_property_t *scf_prop = scf_property_create(cfg->handles.main);
118*c5c4113dSnw 	scf_value_t *value = scf_value_create(cfg->handles.main);
119*c5c4113dSnw 
120*c5c4113dSnw 
121*c5c4113dSnw 	if (0 > scf_pg_get_property(cfg->handles.config_pg, name, scf_prop))
122*c5c4113dSnw 	/* this is OK: the property is just undefined */
123*c5c4113dSnw 		goto destruction;
124*c5c4113dSnw 
125*c5c4113dSnw 
126*c5c4113dSnw 	if (0 > scf_property_get_value(scf_prop, value))
127*c5c4113dSnw 	/* It is still OK when a property doesn't have any value */
128*c5c4113dSnw 		goto destruction;
129*c5c4113dSnw 
130*c5c4113dSnw 	switch (type) {
131*c5c4113dSnw 	case SCF_TYPE_BOOLEAN:
132*c5c4113dSnw 		rc = scf_value_get_boolean(value, val);
133*c5c4113dSnw 		break;
134*c5c4113dSnw 	case SCF_TYPE_COUNT:
135*c5c4113dSnw 		rc = scf_value_get_count(value, val);
136*c5c4113dSnw 		break;
137*c5c4113dSnw 	case SCF_TYPE_INTEGER:
138*c5c4113dSnw 		rc = scf_value_get_integer(value, val);
139*c5c4113dSnw 		break;
140*c5c4113dSnw 	default:
141*c5c4113dSnw 		idmap_scf_error(gettext("Internal error: invalid int type %d"),
142*c5c4113dSnw 		    type);
143*c5c4113dSnw 		rc = -1;
144*c5c4113dSnw 		break;
145*c5c4113dSnw 	}
146*c5c4113dSnw 
147*c5c4113dSnw 
148*c5c4113dSnw destruction:
149*c5c4113dSnw 	scf_value_destroy(value);
150*c5c4113dSnw 	scf_property_destroy(scf_prop);
151*c5c4113dSnw 
152*c5c4113dSnw 	return (rc);
153*c5c4113dSnw }
154*c5c4113dSnw 
155*c5c4113dSnw static char *
156*c5c4113dSnw scf_value2string(scf_value_t *value) {
157*c5c4113dSnw 	int rc = -1;
158*c5c4113dSnw 	char buf_size = 127;
159*c5c4113dSnw 	int length;
160*c5c4113dSnw 	char *buf = NULL;
161*c5c4113dSnw 	buf = (char *) malloc(sizeof (char) * buf_size);
162*c5c4113dSnw 
163*c5c4113dSnw 	for (;;) {
164*c5c4113dSnw 		length = scf_value_get_astring(value, buf, buf_size);
165*c5c4113dSnw 		if (length < 0) {
166*c5c4113dSnw 			rc = -1;
167*c5c4113dSnw 			goto destruction;
168*c5c4113dSnw 		}
169*c5c4113dSnw 
170*c5c4113dSnw 		if (length == buf_size - 1) {
171*c5c4113dSnw 			buf_size *= 2;
172*c5c4113dSnw 			buf = (char *)realloc(buf, buf_size * sizeof (char));
173*c5c4113dSnw 			if (!buf) {
174*c5c4113dSnw 				idmap_scf_error(
175*c5c4113dSnw 					gettext("Not enough memory"));
176*c5c4113dSnw 				rc = -1;
177*c5c4113dSnw 				goto destruction;
178*c5c4113dSnw 			}
179*c5c4113dSnw 		} else {
180*c5c4113dSnw 			rc = 0;
181*c5c4113dSnw 			break;
182*c5c4113dSnw 		}
183*c5c4113dSnw 	}
184*c5c4113dSnw 
185*c5c4113dSnw destruction:
186*c5c4113dSnw 	if (rc < 0) {
187*c5c4113dSnw 		if (buf)
188*c5c4113dSnw 			free(buf);
189*c5c4113dSnw 		buf = NULL;
190*c5c4113dSnw 	}
191*c5c4113dSnw 
192*c5c4113dSnw 	return (buf);
193*c5c4113dSnw }
194*c5c4113dSnw 
195*c5c4113dSnw 
196*c5c4113dSnw static int
197*c5c4113dSnw get_val_astring(idmap_cfg_t *cfg, char *name, char **val)
198*c5c4113dSnw {
199*c5c4113dSnw 	int rc = 0;
200*c5c4113dSnw 
201*c5c4113dSnw 	scf_property_t *scf_prop = scf_property_create(cfg->handles.main);
202*c5c4113dSnw 	scf_value_t *value = scf_value_create(cfg->handles.main);
203*c5c4113dSnw 
204*c5c4113dSnw 
205*c5c4113dSnw 	if (0 > scf_pg_get_property(cfg->handles.config_pg, name, scf_prop))
206*c5c4113dSnw 	/* this is OK: the property is just undefined */
207*c5c4113dSnw 		goto destruction;
208*c5c4113dSnw 
209*c5c4113dSnw 	if (0 > scf_property_get_value(scf_prop, value)) {
210*c5c4113dSnw 		idmap_scf_error(gettext("Cannot get the astring %s"), name);
211*c5c4113dSnw 		rc = -1;
212*c5c4113dSnw 		goto destruction;
213*c5c4113dSnw 	}
214*c5c4113dSnw 
215*c5c4113dSnw 	if (!(*val = scf_value2string(value))) {
216*c5c4113dSnw 		rc = -1;
217*c5c4113dSnw 		idmap_scf_error(gettext("Cannot retrieve the astring %s"),
218*c5c4113dSnw 		    name);
219*c5c4113dSnw 	}
220*c5c4113dSnw 
221*c5c4113dSnw destruction:
222*c5c4113dSnw 	scf_value_destroy(value);
223*c5c4113dSnw 	scf_property_destroy(scf_prop);
224*c5c4113dSnw 
225*c5c4113dSnw 	if (rc < 0) {
226*c5c4113dSnw 		if (*val)
227*c5c4113dSnw 			free(*val);
228*c5c4113dSnw 		*val = NULL;
229*c5c4113dSnw 	}
230*c5c4113dSnw 
231*c5c4113dSnw 	return (rc);
232*c5c4113dSnw }
233*c5c4113dSnw 
234*c5c4113dSnw int
235*c5c4113dSnw idmap_cfg_load(idmap_cfg_t *cfg)
236*c5c4113dSnw {
237*c5c4113dSnw 	int rc = 0;
238*c5c4113dSnw 
239*c5c4113dSnw 	cfg->pgcfg.list_size_limit = 0;
240*c5c4113dSnw 	cfg->pgcfg.mapping_domain = NULL;
241*c5c4113dSnw 	cfg->pgcfg.machine_sid = NULL;
242*c5c4113dSnw 	cfg->pgcfg.domain_controller = NULL;
243*c5c4113dSnw 	cfg->pgcfg.global_catalog = NULL;
244*c5c4113dSnw 
245*c5c4113dSnw 	if (0 > scf_pg_update(cfg->handles.config_pg)) {
246*c5c4113dSnw 		idmap_scf_error(gettext("Error updating config pg"));
247*c5c4113dSnw 		return (-1);
248*c5c4113dSnw 	}
249*c5c4113dSnw 
250*c5c4113dSnw 	if (0 > scf_pg_update(cfg->handles.general_pg)) {
251*c5c4113dSnw 		idmap_scf_error(gettext("Error updating general pg"));
252*c5c4113dSnw 		return (-1);
253*c5c4113dSnw 	}
254*c5c4113dSnw 
255*c5c4113dSnw 	rc = get_val_int(cfg, "list_size_limit",
256*c5c4113dSnw 	    &cfg->pgcfg.list_size_limit, SCF_TYPE_COUNT);
257*c5c4113dSnw 	if (rc != 0)
258*c5c4113dSnw 		return (-1);
259*c5c4113dSnw 
260*c5c4113dSnw 	rc = get_val_astring(cfg, "mapping_domain",
261*c5c4113dSnw 	    &cfg->pgcfg.mapping_domain);
262*c5c4113dSnw 	if (rc != 0)
263*c5c4113dSnw 		return (-1);
264*c5c4113dSnw 
265*c5c4113dSnw 	/*
266*c5c4113dSnw 	 * TBD:
267*c5c4113dSnw 	 * If there is no mapping_domain in idmap's smf config then
268*c5c4113dSnw 	 * set it to the joined domain.
269*c5c4113dSnw 	 * Till domain join is implemented, temporarily set it to
270*c5c4113dSnw 	 * the system domain for testing purposes.
271*c5c4113dSnw 	 */
272*c5c4113dSnw 	if (!cfg->pgcfg.mapping_domain) 	{
273*c5c4113dSnw 		char test[1];
274*c5c4113dSnw 		long dname_size = sysinfo(SI_SRPC_DOMAIN, test, 1);
275*c5c4113dSnw 		if (dname_size > 0) {
276*c5c4113dSnw 			cfg->pgcfg.mapping_domain =
277*c5c4113dSnw 			    (char *)malloc(dname_size * sizeof (char));
278*c5c4113dSnw 			dname_size = sysinfo(SI_SRPC_DOMAIN,
279*c5c4113dSnw 			    cfg->pgcfg.mapping_domain, dname_size);
280*c5c4113dSnw 		}
281*c5c4113dSnw 		if (dname_size <= 0) {
282*c5c4113dSnw 			idmap_scf_error(
283*c5c4113dSnw 			    gettext("Error obtaining the default domain"));
284*c5c4113dSnw 			if (cfg->pgcfg.mapping_domain)
285*c5c4113dSnw 				free(cfg->pgcfg.mapping_domain);
286*c5c4113dSnw 			cfg->pgcfg.mapping_domain = NULL;
287*c5c4113dSnw 		}
288*c5c4113dSnw 	}
289*c5c4113dSnw 
290*c5c4113dSnw 	rc = get_val_astring(cfg, "machine_sid", &cfg->pgcfg.machine_sid);
291*c5c4113dSnw 	if (rc != 0)
292*c5c4113dSnw 		return (-1);
293*c5c4113dSnw 
294*c5c4113dSnw 	rc = get_val_astring(cfg, "global_catalog", &cfg->pgcfg.global_catalog);
295*c5c4113dSnw 	if (rc != 0)
296*c5c4113dSnw 		return (-1);
297*c5c4113dSnw 
298*c5c4113dSnw 	rc = get_val_astring(cfg, "domain_controller",
299*c5c4113dSnw 	    &cfg->pgcfg.domain_controller);
300*c5c4113dSnw 	if (rc != 0)
301*c5c4113dSnw 		return (-1);
302*c5c4113dSnw 
303*c5c4113dSnw 	return (rc);
304*c5c4113dSnw }
305*c5c4113dSnw 
306*c5c4113dSnw idmap_cfg_t *
307*c5c4113dSnw idmap_cfg_init() {
308*c5c4113dSnw 	/*
309*c5c4113dSnw 	 * The following initializes 'cfg'.
310*c5c4113dSnw 	 */
311*c5c4113dSnw 
312*c5c4113dSnw 	/* First the smf repository handles: */
313*c5c4113dSnw 	idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t));
314*c5c4113dSnw 	if (!cfg) {
315*c5c4113dSnw 		idmap_error(gettext("Not enough memory"));
316*c5c4113dSnw 		return (NULL);
317*c5c4113dSnw 	}
318*c5c4113dSnw 
319*c5c4113dSnw 	if (!(cfg->handles.main = scf_handle_create(SCF_VERSION))) {
320*c5c4113dSnw 		idmap_scf_error(gettext("SCF handle not created"));
321*c5c4113dSnw 		goto error;
322*c5c4113dSnw 	}
323*c5c4113dSnw 
324*c5c4113dSnw 	if (0 > scf_handle_bind(cfg->handles.main)) {
325*c5c4113dSnw 		idmap_scf_error(gettext("SCF connection failed"));
326*c5c4113dSnw 		goto error;
327*c5c4113dSnw 	}
328*c5c4113dSnw 
329*c5c4113dSnw 	if (!(cfg->handles.service = scf_service_create(cfg->handles.main)) ||
330*c5c4113dSnw 	    !(cfg->handles.instance = scf_instance_create(cfg->handles.main)) ||
331*c5c4113dSnw 	    !(cfg->handles.config_pg = scf_pg_create(cfg->handles.main)) ||
332*c5c4113dSnw 	    !(cfg->handles.general_pg = scf_pg_create(cfg->handles.main))) {
333*c5c4113dSnw 		idmap_scf_error(gettext("SCF handle creation failed"));
334*c5c4113dSnw 		goto error;
335*c5c4113dSnw 	}
336*c5c4113dSnw 
337*c5c4113dSnw 	if (0 > scf_handle_decode_fmri(cfg->handles.main,
338*c5c4113dSnw 		FMRI_BASE "/:properties/" CONFIG_PG,
339*c5c4113dSnw 		NULL,				/* scope */
340*c5c4113dSnw 		cfg->handles.service,		/* service */
341*c5c4113dSnw 		cfg->handles.instance,		/* instance */
342*c5c4113dSnw 		cfg->handles.config_pg,		/* pg */
343*c5c4113dSnw 		NULL,				/* prop */
344*c5c4113dSnw 		SCF_DECODE_FMRI_EXACT)) {
345*c5c4113dSnw 		idmap_scf_error(gettext("SCF fmri decoding failed"));
346*c5c4113dSnw 		goto error;
347*c5c4113dSnw 
348*c5c4113dSnw 	}
349*c5c4113dSnw 
350*c5c4113dSnw 	if (0 > scf_service_get_pg(cfg->handles.service,
351*c5c4113dSnw 		GENERAL_PG, cfg->handles.general_pg)) {
352*c5c4113dSnw 		idmap_scf_error(gettext("SCF general pg not obtained"));
353*c5c4113dSnw 		goto error;
354*c5c4113dSnw 	}
355*c5c4113dSnw 
356*c5c4113dSnw 	return (cfg);
357*c5c4113dSnw 
358*c5c4113dSnw error:
359*c5c4113dSnw 	(void) idmap_cfg_fini(cfg);
360*c5c4113dSnw 	return (NULL);
361*c5c4113dSnw }
362*c5c4113dSnw 
363*c5c4113dSnw /* ARGSUSED */
364*c5c4113dSnw static void
365*c5c4113dSnw idmap_pgcfg_fini(idmap_pg_config_t *pgcfg) {
366*c5c4113dSnw 	if (pgcfg->mapping_domain)
367*c5c4113dSnw 		free(pgcfg->mapping_domain);
368*c5c4113dSnw 	if (pgcfg->machine_sid)
369*c5c4113dSnw 		free(pgcfg->mapping_domain);
370*c5c4113dSnw 	if (pgcfg->global_catalog)
371*c5c4113dSnw 		free(pgcfg->global_catalog);
372*c5c4113dSnw 	if (pgcfg->domain_controller)
373*c5c4113dSnw 		free(pgcfg->domain_controller);
374*c5c4113dSnw }
375*c5c4113dSnw 
376*c5c4113dSnw int
377*c5c4113dSnw idmap_cfg_fini(idmap_cfg_t *cfg)
378*c5c4113dSnw {
379*c5c4113dSnw 	idmap_pgcfg_fini(&cfg->pgcfg);
380*c5c4113dSnw 
381*c5c4113dSnw 	scf_pg_destroy(cfg->handles.config_pg);
382*c5c4113dSnw 	scf_pg_destroy(cfg->handles.general_pg);
383*c5c4113dSnw 	scf_instance_destroy(cfg->handles.instance);
384*c5c4113dSnw 	scf_service_destroy(cfg->handles.service);
385*c5c4113dSnw 	scf_handle_destroy(cfg->handles.main);
386*c5c4113dSnw 	free(cfg);
387*c5c4113dSnw 
388*c5c4113dSnw 	return (0);
389*c5c4113dSnw }
390