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