xref: /illumos-gate/usr/src/lib/libscf/common/highlevel.c (revision ff8e166f73f3bfaeac25d65662c6469130892500)
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 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * This file contains high level functions used by multiple utilities.
29  */
30 
31 #include "libscf_impl.h"
32 
33 #include <assert.h>
34 #include <libuutil.h>
35 #include <string.h>
36 #include <strings.h>
37 #include <stdlib.h>
38 #include <sys/systeminfo.h>
39 #include <sys/uadmin.h>
40 #include <sys/utsname.h>
41 #include <sys/secflags.h>
42 
43 #ifdef	__x86
44 #include <smbios.h>
45 
46 /*
47  * Check whether the platform is on the fastreboot_blacklist.
48  * Return 1 if the platform has been blacklisted, 0 otherwise.
49  */
50 static int
51 scf_is_fb_blacklisted(void)
52 {
53 	smbios_hdl_t *shp;
54 	smbios_system_t sys;
55 	smbios_info_t info;
56 
57 	id_t id;
58 	int err;
59 	int i;
60 
61 	scf_simple_prop_t *prop = NULL;
62 	ssize_t numvals;
63 	char *platform_name;
64 
65 	int blacklisted = 0;
66 
67 	/*
68 	 * If there's no SMBIOS, assume it's blacklisted.
69 	 */
70 	if ((shp = smbios_open(NULL, SMB_VERSION, 0, &err)) == NULL)
71 		return (1);
72 
73 	/*
74 	 * If we can't read system info, assume it's blacklisted.
75 	 */
76 	if ((id = smbios_info_system(shp, &sys)) == SMB_ERR ||
77 	    smbios_info_common(shp, id, &info) == SMB_ERR) {
78 		blacklisted = 1;
79 		goto fb_out;
80 	}
81 
82 	/*
83 	 * If we can't read the "platforms" property from property group
84 	 * BOOT_CONFIG_PG_FBBLACKLIST, assume no platforms have
85 	 * been blacklisted.
86 	 */
87 	if ((prop = scf_simple_prop_get(NULL, FMRI_BOOT_CONFIG,
88 	    BOOT_CONFIG_PG_FBBLACKLIST, "platforms")) == NULL)
89 		goto fb_out;
90 
91 	numvals = scf_simple_prop_numvalues(prop);
92 
93 	for (i = 0; i < numvals; i++) {
94 		platform_name = scf_simple_prop_next_astring(prop);
95 		if (platform_name == NULL)
96 			break;
97 		if (strcmp(platform_name, info.smbi_product) == 0) {
98 			blacklisted = 1;
99 			break;
100 		}
101 	}
102 
103 fb_out:
104 	smbios_close(shp);
105 	scf_simple_prop_free(prop);
106 
107 	return (blacklisted);
108 }
109 
110 /*
111  * Add or get a property group given an FMRI.
112  * Return SCF_SUCCESS on success, SCF_FAILED on failure.
113  */
114 static int
115 scf_fmri_pg_get_or_add(const char *fmri, const char *pgname,
116     const char *pgtype, uint32_t pgflags, int add)
117 {
118 	scf_handle_t	*handle = NULL;
119 	scf_instance_t	*inst = NULL;
120 	int		rc = SCF_FAILED;
121 	int		error;
122 
123 	if ((handle = scf_handle_create(SCF_VERSION)) == NULL ||
124 	    scf_handle_bind(handle) != 0 ||
125 	    (inst = scf_instance_create(handle)) == NULL ||
126 	    scf_handle_decode_fmri(handle, fmri, NULL, NULL,
127 	    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
128 		goto scferror;
129 
130 	if (add) {
131 		rc = scf_instance_add_pg(inst, pgname, pgtype, pgflags, NULL);
132 		/*
133 		 * If the property group already exists, return SCF_SUCCESS.
134 		 */
135 		if (rc != SCF_SUCCESS && scf_error() == SCF_ERROR_EXISTS)
136 			rc = SCF_SUCCESS;
137 	} else {
138 		rc = scf_instance_get_pg(inst, pgname, NULL);
139 	}
140 
141 scferror:
142 	if (rc != SCF_SUCCESS)
143 		error = scf_error();
144 
145 	scf_instance_destroy(inst);
146 	if (handle)
147 		(void) scf_handle_unbind(handle);
148 	scf_handle_destroy(handle);
149 
150 	if (rc != SCF_SUCCESS)
151 		(void) scf_set_error(error);
152 
153 	return (rc);
154 }
155 #endif	/* __x86 */
156 
157 /*
158  * Get config properties from svc:/system/boot-config:default.
159  * It prints errors with uu_warn().
160  */
161 void
162 scf_get_boot_config(uint8_t *boot_config)
163 {
164 	uint64_t ret = 0;
165 
166 	assert(boot_config);
167 	*boot_config = 0;
168 
169 	{
170 		/*
171 		 * Property vector for BOOT_CONFIG_PG_PARAMS property group.
172 		 */
173 		scf_propvec_t ua_boot_config[] = {
174 			{ FASTREBOOT_DEFAULT, NULL, SCF_TYPE_BOOLEAN, NULL,
175 			    UA_FASTREBOOT_DEFAULT },
176 			{ FASTREBOOT_ONPANIC, NULL, SCF_TYPE_BOOLEAN, NULL,
177 			    UA_FASTREBOOT_ONPANIC },
178 			{ NULL }
179 		};
180 		scf_propvec_t	*prop;
181 
182 		for (prop = ua_boot_config; prop->pv_prop != NULL; prop++)
183 			prop->pv_ptr = &ret;
184 		prop = NULL;
185 		if (scf_read_propvec(FMRI_BOOT_CONFIG, BOOT_CONFIG_PG_PARAMS,
186 		    B_TRUE, ua_boot_config, &prop) != SCF_FAILED) {
187 
188 #ifdef	__x86
189 			/*
190 			 * Unset both flags if the platform has been
191 			 * blacklisted.
192 			 */
193 			if (scf_is_fb_blacklisted())
194 				return;
195 #endif	/* __x86 */
196 			*boot_config = (uint8_t)ret;
197 			return;
198 		}
199 #if defined(FASTREBOOT_DEBUG)
200 		if (prop != NULL) {
201 			(void) uu_warn("Service %s property '%s/%s' "
202 			    "not found.\n", FMRI_BOOT_CONFIG,
203 			    BOOT_CONFIG_PG_PARAMS, prop->pv_prop);
204 		} else {
205 			(void) uu_warn("Unable to read service %s "
206 			    "property '%s': %s\n", FMRI_BOOT_CONFIG,
207 			    BOOT_CONFIG_PG_PARAMS, scf_strerror(scf_error()));
208 		}
209 #endif	/* FASTREBOOT_DEBUG */
210 	}
211 }
212 
213 /*
214  * Get or set properties in non-persistent "config_ovr" property group
215  * in svc:/system/boot-config:default.
216  * It prints errors with uu_warn().
217  */
218 /*ARGSUSED*/
219 static int
220 scf_getset_boot_config_ovr(int set, uint8_t *boot_config_ovr)
221 {
222 	int rc = SCF_SUCCESS;
223 
224 	assert(boot_config_ovr);
225 
226 #ifndef	__x86
227 	return (rc);
228 #else
229 	{
230 		/*
231 		 * Property vector for BOOT_CONFIG_PG_OVR property group.
232 		 */
233 		scf_propvec_t ua_boot_config_ovr[] = {
234 			{ FASTREBOOT_DEFAULT, NULL, SCF_TYPE_BOOLEAN, NULL,
235 			    UA_FASTREBOOT_DEFAULT },
236 			{ FASTREBOOT_ONPANIC, NULL, SCF_TYPE_BOOLEAN, NULL,
237 			    UA_FASTREBOOT_ONPANIC },
238 			{ NULL }
239 		};
240 		scf_propvec_t	*prop;
241 
242 		rc = scf_fmri_pg_get_or_add(FMRI_BOOT_CONFIG,
243 		    BOOT_CONFIG_PG_OVR, SCF_GROUP_APPLICATION,
244 		    SCF_PG_FLAG_NONPERSISTENT, set);
245 
246 		if (rc != SCF_SUCCESS) {
247 #if defined(FASTREBOOT_DEBUG)
248 			if (set)
249 				(void) uu_warn("Unable to add service %s "
250 				    "property group '%s'\n",
251 				    FMRI_BOOT_CONFIG, BOOT_CONFIG_PG_OVR);
252 #endif	/* FASTREBOOT_DEBUG */
253 			return (rc);
254 		}
255 
256 		for (prop = ua_boot_config_ovr; prop->pv_prop != NULL; prop++)
257 			prop->pv_ptr = boot_config_ovr;
258 		prop = NULL;
259 
260 		if (set)
261 			rc = scf_write_propvec(FMRI_BOOT_CONFIG,
262 			    BOOT_CONFIG_PG_OVR, ua_boot_config_ovr, &prop);
263 		else
264 			rc = scf_read_propvec(FMRI_BOOT_CONFIG,
265 			    BOOT_CONFIG_PG_OVR, B_FALSE, ua_boot_config_ovr,
266 			    &prop);
267 
268 #if defined(FASTREBOOT_DEBUG)
269 		if (rc != SCF_SUCCESS) {
270 			if (prop != NULL) {
271 				(void) uu_warn("Service %s property '%s/%s' "
272 				    "not found.\n", FMRI_BOOT_CONFIG,
273 				    BOOT_CONFIG_PG_OVR, prop->pv_prop);
274 			} else {
275 				(void) uu_warn("Unable to %s service %s "
276 				    "property '%s': %s\n", set ? "set" : "get",
277 				    FMRI_BOOT_CONFIG, BOOT_CONFIG_PG_OVR,
278 				    scf_strerror(scf_error()));
279 			}
280 		}
281 #endif	/* FASTREBOOT_DEBUG */
282 
283 		if (set)
284 			(void) smf_refresh_instance(FMRI_BOOT_CONFIG);
285 
286 		return (rc);
287 
288 	}
289 #endif	/* __x86 */
290 }
291 
292 /*
293  * Get values of properties in non-persistent "config_ovr" property group.
294  */
295 void
296 scf_get_boot_config_ovr(uint8_t *boot_config_ovr)
297 {
298 	(void) scf_getset_boot_config_ovr(B_FALSE, boot_config_ovr);
299 }
300 
301 /*
302  * Set value of "config_ovr/fastreboot_default".
303  */
304 int
305 scf_fastreboot_default_set_transient(boolean_t value)
306 {
307 	uint8_t	boot_config_ovr = 0;
308 
309 	if (value == B_TRUE)
310 		boot_config_ovr = UA_FASTREBOOT_DEFAULT | UA_FASTREBOOT_ONPANIC;
311 
312 	return (scf_getset_boot_config_ovr(B_TRUE, &boot_config_ovr));
313 }
314 
315 /*
316  * Check whether Fast Reboot is the default operating mode.
317  * Return 0 if
318  *   1. the platform is xVM
319  * or
320  *   2. svc:/system/boot-config:default service doesn't exist,
321  * or
322  *   3. property "config/fastreboot_default" doesn't exist,
323  * or
324  *   4. value of property "config/fastreboot_default" is set to "false"
325  *      and "config_ovr/fastreboot_default" is not set to "true",
326  * or
327  *   5. the platform has been blacklisted.
328  * or
329  *   6. value of property "config_ovr/fastreboot_default" is set to "false".
330  * Return non-zero otherwise.
331  */
332 int
333 scf_is_fastboot_default(void)
334 {
335 	uint8_t	boot_config = 0, boot_config_ovr;
336 	char procbuf[SYS_NMLN];
337 
338 	/*
339 	 * If we are on xVM, do not fast reboot by default.
340 	 */
341 	if (sysinfo(SI_PLATFORM, procbuf, sizeof (procbuf)) == -1 ||
342 	    strcmp(procbuf, "i86xpv") == 0)
343 		return (0);
344 
345 	/*
346 	 * Get property values from "config" property group
347 	 */
348 	scf_get_boot_config(&boot_config);
349 
350 	/*
351 	 * Get property values from non-persistent "config_ovr" property group
352 	 */
353 	boot_config_ovr = boot_config;
354 	scf_get_boot_config_ovr(&boot_config_ovr);
355 
356 	return (boot_config & boot_config_ovr & UA_FASTREBOOT_DEFAULT);
357 }
358 
359 /*
360  * Read the default security-flags from system/process-security and return a
361  * secflagset_t suitable for psecflags(2)
362  *
363  * Unfortunately, this symbol must _exist_ in the native build, for the sake
364  * of the mapfile, even though we don't ever use it, and it will never work.
365  */
366 struct group_desc {
367 	secflagdelta_t *delta;
368 	char *fmri;
369 };
370 
371 int
372 scf_default_secflags(scf_handle_t *hndl, scf_secflags_t *flags)
373 {
374 #if !defined(NATIVE_BUILD)
375 	scf_property_t *prop;
376 	scf_value_t *val;
377 	const char *flagname;
378 	int flag;
379 	struct group_desc *g;
380 	struct group_desc groups[] = {
381 		{NULL, "svc:/system/process-security/"
382 		    ":properties/default"},
383 		{NULL, "svc:/system/process-security/"
384 		    ":properties/lower"},
385 		{NULL, "svc:/system/process-security/"
386 		    ":properties/upper"},
387 		{NULL, NULL}
388 	};
389 
390 	bzero(flags, sizeof (*flags));
391 
392 	groups[0].delta = &flags->ss_default;
393 	groups[1].delta = &flags->ss_lower;
394 	groups[2].delta = &flags->ss_upper;
395 
396 	for (g = groups; g->delta != NULL; g++) {
397 		for (flag = 0; (flagname = secflag_to_str(flag)) != NULL;
398 		    flag++) {
399 			char *pfmri;
400 			uint8_t flagval = 0;
401 
402 			if ((val = scf_value_create(hndl)) == NULL)
403 				return (-1);
404 
405 			if ((prop = scf_property_create(hndl)) == NULL) {
406 				scf_value_destroy(val);
407 				return (-1);
408 			}
409 
410 			if ((pfmri = uu_msprintf("%s/%s", g->fmri,
411 			    flagname)) == NULL)
412 				uu_die("Allocation failure\n");
413 
414 			if (scf_handle_decode_fmri(hndl, pfmri,
415 			    NULL, NULL, NULL, NULL, prop, 0) != 0)
416 				goto next;
417 
418 			if (scf_property_get_value(prop, val) != 0)
419 				goto next;
420 
421 			(void) scf_value_get_boolean(val, &flagval);
422 
423 			if (flagval != 0)
424 				secflag_set(&g->delta->psd_add, flag);
425 			else
426 				secflag_set(&g->delta->psd_rem, flag);
427 
428 next:
429 			uu_free(pfmri);
430 			scf_value_destroy(val);
431 			scf_property_destroy(prop);
432 		}
433 	}
434 
435 	return (0);
436 #else
437 	assert(0);
438 	abort();
439 #endif /* !NATIVE_BUILD */
440 }
441