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, NULL) != 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