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
42scf_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 */
47char *
48cf_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
84out:
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 */
105int
106rc_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
198out:
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
221int
222main(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 */
232