root/usr/src/lib/libsmbfs/smb/rc_scf.c
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
 */

/*
 * Support functions for getting things libsmbfs needs
 * from the SMF configuration (using libscf).
 */

#include <sys/types.h>
#include <sys/queue.h>

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <libscf.h>

#include <cflib.h>
#include "rcfile_priv.h"

#define IDMAP_SERVICE_FMRI              "svc:/system/idmap"
#define IDMAP_PG_NAME                   "config"
#define MACHINE_UUID                    "machine_uuid"

#define SMBC_DEFAULT_INSTANCE_FMRI      "svc:/network/smb/client:default"

scf_handle_t *_scf_handle_create_and_bind(scf_version_t ver);

/*
 * Get the "machine_uuid" from idmap, as a string (allocated)
 */
char *
cf_get_client_uuid(void)
{
        char val_buf[64];
        char *ret = NULL;

        scf_handle_t            *h = NULL;
        scf_service_t           *svc = NULL;
        scf_propertygroup_t     *pg = NULL;
        scf_property_t          *prop = NULL;
        scf_value_t             *val = NULL;

        if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
                goto out;

        if ((svc = scf_service_create(h)) == NULL ||
            (pg = scf_pg_create(h)) == NULL ||
            (prop = scf_property_create(h)) == NULL ||
            (val = scf_value_create(h)) == NULL)
                goto out;

        if (scf_handle_decode_fmri(h, IDMAP_SERVICE_FMRI,
            NULL, svc, NULL, NULL, NULL, 0) == -1)
                goto out;


        if (scf_service_get_pg(svc, IDMAP_PG_NAME, pg) != 0)
                goto out;
        if (scf_pg_get_property(pg, MACHINE_UUID, prop) != 0)
                goto out;
        if (scf_property_get_value(prop, val) != 0)
                goto out;
        if (scf_value_get_as_string(val, val_buf, sizeof (val_buf)) < 0)
                goto out;

        ret = strdup(val_buf);

out:
        scf_value_destroy(val);
        scf_property_destroy(prop);
        scf_pg_destroy(pg);
        scf_service_destroy(svc);

        if (h != NULL)
                scf_handle_destroy(h);

        return (ret);
}

/*
 * Get the output of "sharectl get smbfs" into a file, without an
 * actual fork/exec of sharectl.
 *
 * Each section of the smbfs settings are represented as an SMF
 * property group with an "S-" prefix and a UUID, and the section
 * name itself a property which can have a more flexible name than
 * a property group name can have.
 */
int
rc_scf_get_sharectl(FILE *fp)
{
        char sect_name[256];
        char prop_name[256];
        char val_buf[1024];

        scf_handle_t            *h = NULL;
        scf_service_t           *svc = NULL;
        scf_instance_t          *inst = NULL;
        scf_propertygroup_t     *pg = NULL;
        scf_property_t          *prop = NULL;
        scf_value_t             *val = NULL;
        scf_iter_t              *pgiter = NULL;
        scf_iter_t              *propiter = NULL;
        scf_iter_t              *valiter = NULL;
        int ret = -1;

        if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
                goto out;

        if ((svc = scf_service_create(h)) == NULL ||
            (inst = scf_instance_create(h)) == NULL ||
            (pgiter = scf_iter_create(h)) == NULL ||
            (propiter = scf_iter_create(h)) == NULL ||
            (valiter = scf_iter_create(h)) == NULL ||
            (pg = scf_pg_create(h)) == NULL ||
            (prop = scf_property_create(h)) == NULL ||
            (val = scf_value_create(h)) == NULL)
                goto out;

        if (scf_handle_decode_fmri(h, SMBC_DEFAULT_INSTANCE_FMRI,
            NULL, svc, inst, NULL, NULL, 0) == -1)
                goto out;

        if (scf_iter_instance_pgs_composed(pgiter, inst, NULL) == -1)
                goto out;
        while ((ret = scf_iter_next_pg(pgiter, pg)) == 1) {
                /*
                 * Using prop_name array for pg name temporarily.
                 * Skip any property groups names other than "S-*".
                 */
                if (scf_pg_get_name(pg, prop_name, sizeof (prop_name)) < 0)
                        continue;
                if (strncmp(prop_name, "S-", 2) != 0)
                        continue;

                /*
                 * Get the "section" name, which is a property of
                 * this property group.
                 */
                if (scf_pg_get_property(pg, "section", prop) != 0)
                        continue;
                if (scf_property_get_value(prop, val) != 0)
                        continue;
                if (scf_value_get_as_string(val, sect_name,
                    sizeof (sect_name)) < 0)
                        continue;

                /*
                 * Have an S-* property group with a "section" name.
                 * Print the section start.
                 */
                fprintf(fp, "[%s]\n", sect_name);

                /*
                 * Now print the remaining properties in this PG,
                 * but skip the special "section" (name) prop.
                 */
                if (scf_iter_pg_properties(propiter, pg) == -1)
                        goto out;
                while ((ret = scf_iter_next_property(propiter, prop)) == 1) {

                        if (scf_property_get_name(prop, prop_name,
                            sizeof (prop_name)) < 0)
                                continue;

                        /* Skip the "section" prop. now */
                        if (strcmp(prop_name, "section") == 0)
                                continue;

                        if (scf_property_get_value(prop, val) != 0)
                                continue;

                        if (scf_value_get_as_string(val, val_buf,
                            sizeof (val_buf)) < 0)
                                continue;

                        fprintf(fp, "%s=%s\n", prop_name, val_buf);
                }
        }
        ret = 0;

out:
        fflush(fp);

        scf_value_destroy(val);
        scf_property_destroy(prop);
        scf_pg_destroy(pg);
        scf_iter_destroy(valiter);
        scf_iter_destroy(propiter);
        scf_iter_destroy(pgiter);
        scf_instance_destroy(inst);
        scf_service_destroy(svc);

        if (h != NULL)
                scf_handle_destroy(h);

        return (ret);
}

/*
 * Simple test wrapper.  Compile with:
 * cc -o rc_scf_test -I.. -DTEST_MAIN rc_scf.c -lscf
 */
#ifdef  TEST_MAIN
int
main(int argc, char **arv)
{
        char *s;
        int rc;

        rc = rc_scf_get_sharectl(stdout);
        printf("# rc=%d\n", rc);
        return (0);
}
#endif  /* TEST_MAIN */