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         return (0);
 439 #else
 440         assert(0);
 441         abort();
 442 #endif /* !NATIVE_BUILD */
 443 }