1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Support functions for getting things libsmbfs needs
  18  * from the SMF configuration (using libscf).
  19  */
  20 
  21 #include <sys/types.h>
  22 #include <sys/queue.h>
  23 
  24 #include <ctype.h>
  25 #include <errno.h>
  26 #include <stdio.h>
  27 #include <string.h>
  28 #include <strings.h>
  29 #include <stdlib.h>
  30 #include <unistd.h>
  31 #include <libscf.h>
  32 
  33 #include <cflib.h>
  34 #include "rcfile_priv.h"
  35 
  36 #define IDMAP_SERVICE_FMRI              "svc:/system/idmap"
  37 #define IDMAP_PG_NAME                   "config"
  38 #define MACHINE_UUID                    "machine_uuid"
  39 
  40 #define SMBC_DEFAULT_INSTANCE_FMRI      "svc:/network/smb/client:default"
  41 
  42 scf_handle_t *_scf_handle_create_and_bind(scf_version_t ver);
  43 
  44 /*
  45  * Get the "machine_uuid" from idmap, as a string (allocated)
  46  */
  47 char *
  48 cf_get_client_uuid(void)
  49 {
  50         char val_buf[64];
  51         char *ret = NULL;
  52 
  53         scf_handle_t            *h = NULL;
  54         scf_service_t           *svc = NULL;
  55         scf_propertygroup_t     *pg = NULL;
  56         scf_property_t          *prop = NULL;
  57         scf_value_t             *val = NULL;
  58 
  59         if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
  60                 goto out;
  61 
  62         if ((svc = scf_service_create(h)) == NULL ||
  63             (pg = scf_pg_create(h)) == NULL ||
  64             (prop = scf_property_create(h)) == NULL ||
  65             (val = scf_value_create(h)) == NULL)
  66                 goto out;
  67 
  68         if (scf_handle_decode_fmri(h, IDMAP_SERVICE_FMRI,
  69             NULL, svc, NULL, NULL, NULL, 0) == -1)
  70                 goto out;
  71 
  72 
  73         if (scf_service_get_pg(svc, IDMAP_PG_NAME, pg) != 0)
  74                 goto out;
  75         if (scf_pg_get_property(pg, MACHINE_UUID, prop) != 0)
  76                 goto out;
  77         if (scf_property_get_value(prop, val) != 0)
  78                 goto out;
  79         if (scf_value_get_as_string(val, val_buf, sizeof (val_buf)) < 0)
  80                 goto out;
  81 
  82         ret = strdup(val_buf);
  83 
  84 out:
  85         scf_value_destroy(val);
  86         scf_property_destroy(prop);
  87         scf_pg_destroy(pg);
  88         scf_service_destroy(svc);
  89 
  90         if (h != NULL)
  91                 scf_handle_destroy(h);
  92 
  93         return (ret);
  94 }
  95 
  96 /*
  97  * Get the output of "sharectl get smbfs" into a file, without an
  98  * actual fork/exec of sharectl.
  99  *
 100  * Each section of the smbfs settings are represented as an SMF
 101  * property group with an "S-" prefix and a UUID, and the section
 102  * name itself a property which can have a more flexible name than
 103  * a property group name can have.
 104  */
 105 int
 106 rc_scf_get_sharectl(FILE *fp)
 107 {
 108         char sect_name[256];
 109         char prop_name[256];
 110         char val_buf[1024];
 111 
 112         scf_handle_t            *h = NULL;
 113         scf_service_t           *svc = NULL;
 114         scf_instance_t          *inst = NULL;
 115         scf_propertygroup_t     *pg = NULL;
 116         scf_property_t          *prop = NULL;
 117         scf_value_t             *val = NULL;
 118         scf_iter_t              *pgiter = NULL;
 119         scf_iter_t              *propiter = NULL;
 120         scf_iter_t              *valiter = NULL;
 121         int ret = -1;
 122 
 123         if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
 124                 goto out;
 125 
 126         if ((svc = scf_service_create(h)) == NULL ||
 127             (inst = scf_instance_create(h)) == NULL ||
 128             (pgiter = scf_iter_create(h)) == NULL ||
 129             (propiter = scf_iter_create(h)) == NULL ||
 130             (valiter = scf_iter_create(h)) == NULL ||
 131             (pg = scf_pg_create(h)) == NULL ||
 132             (prop = scf_property_create(h)) == NULL ||
 133             (val = scf_value_create(h)) == NULL)
 134                 goto out;
 135 
 136         if (scf_handle_decode_fmri(h, SMBC_DEFAULT_INSTANCE_FMRI,
 137             NULL, svc, inst, NULL, NULL, 0) == -1)
 138                 goto out;
 139 
 140         if (scf_iter_instance_pgs_composed(pgiter, inst, NULL) == -1)
 141                 goto out;
 142         while ((ret = scf_iter_next_pg(pgiter, pg)) == 1) {
 143                 /*
 144                  * Using prop_name array for pg name temporarily.
 145                  * Skip any property groups names other than "S-*".
 146                  */
 147                 if (scf_pg_get_name(pg, prop_name, sizeof (prop_name)) < 0)
 148                         continue;
 149                 if (strncmp(prop_name, "S-", 2) != 0)
 150                         continue;
 151 
 152                 /*
 153                  * Get the "section" name, which is a property of
 154                  * this property group.
 155                  */
 156                 if (scf_pg_get_property(pg, "section", prop) != 0)
 157                         continue;
 158                 if (scf_property_get_value(prop, val) != 0)
 159                         continue;
 160                 if (scf_value_get_as_string(val, sect_name,
 161                     sizeof (sect_name)) < 0)
 162                         continue;
 163 
 164                 /*
 165                  * Have an S-* property group with a "section" name.
 166                  * Print the section start.
 167                  */
 168                 fprintf(fp, "[%s]\n", sect_name);
 169 
 170                 /*
 171                  * Now print the remaining properties in this PG,
 172                  * but skip the special "section" (name) prop.
 173                  */
 174                 if (scf_iter_pg_properties(propiter, pg) == -1)
 175                         goto out;
 176                 while ((ret = scf_iter_next_property(propiter, prop)) == 1) {
 177 
 178                         if (scf_property_get_name(prop, prop_name,
 179                             sizeof (prop_name)) < 0)
 180                                 continue;
 181 
 182                         /* Skip the "section" prop. now */
 183                         if (strcmp(prop_name, "section") == 0)
 184                                 continue;
 185 
 186                         if (scf_property_get_value(prop, val) != 0)
 187                                 continue;
 188 
 189                         if (scf_value_get_as_string(val, val_buf,
 190                             sizeof (val_buf)) < 0)
 191                                 continue;
 192 
 193                         fprintf(fp, "%s=%s\n", prop_name, val_buf);
 194                 }
 195         }
 196         ret = 0;
 197 
 198 out:
 199         fflush(fp);
 200 
 201         scf_value_destroy(val);
 202         scf_property_destroy(prop);
 203         scf_pg_destroy(pg);
 204         scf_iter_destroy(valiter);
 205         scf_iter_destroy(propiter);
 206         scf_iter_destroy(pgiter);
 207         scf_instance_destroy(inst);
 208         scf_service_destroy(svc);
 209 
 210         if (h != NULL)
 211                 scf_handle_destroy(h);
 212 
 213         return (ret);
 214 }
 215 
 216 /*
 217  * Simple test wrapper.  Compile with:
 218  * cc -o rc_scf_test -I.. -DTEST_MAIN rc_scf.c -lscf
 219  */
 220 #ifdef  TEST_MAIN
 221 int
 222 main(int argc, char **arv)
 223 {
 224         char *s;
 225         int rc;
 226 
 227         rc = rc_scf_get_sharectl(stdout);
 228         printf("# rc=%d\n", rc);
 229         return (0);
 230 }
 231 #endif  /* TEST_MAIN */