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