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 }