1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22dc20a302Sas  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24b819cea2SGordon Ross  *
25a90cf9f2SGordon Ross  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
26327e8b4bSAndy Fiddaman  * Copyright 2023 Oxide Computer Company
27da6c28aaSamw  */
28da6c28aaSamw 
29da6c28aaSamw /* helper functions for using libscf with CIFS */
30da6c28aaSamw 
31da6c28aaSamw #include <libscf.h>
32da6c28aaSamw #include <string.h>
33da6c28aaSamw #include <stdio.h>
34da6c28aaSamw #include <stdlib.h>
35da6c28aaSamw #include <syslog.h>
36da6c28aaSamw #include <errno.h>
37da6c28aaSamw #include <libintl.h>
38da6c28aaSamw #include <assert.h>
39da6c28aaSamw #include <strings.h>
40da6c28aaSamw 
41da6c28aaSamw #include <uuid/uuid.h>
42da6c28aaSamw #include <sys/param.h>
43da6c28aaSamw 
44da6c28aaSamw #include <smbsrv/libsmb.h>
45da6c28aaSamw 
46da6c28aaSamw /*
47da6c28aaSamw  * smb_smf_scf_log_error(msg)
48da6c28aaSamw  * Logs error messages from scf API's
49da6c28aaSamw  */
50da6c28aaSamw static void
smb_smf_scf_log_error(char * msg)51da6c28aaSamw smb_smf_scf_log_error(char *msg)
52da6c28aaSamw {
53b819cea2SGordon Ross 	if (msg == NULL)
54c79c9de5SAndy Fiddaman 		msg = "SMBD SMF problems";
55b819cea2SGordon Ross 
56c79c9de5SAndy Fiddaman 	syslog(LOG_ERR, "%s: %s", msg, scf_strerror(scf_error()));
57da6c28aaSamw }
58da6c28aaSamw 
59da6c28aaSamw /*
60da6c28aaSamw  * smb_smf_create_service_pgroup(handle, pgroup)
61da6c28aaSamw  *
62da6c28aaSamw  * create a new property group at service level.
63da6c28aaSamw  */
64da6c28aaSamw int
smb_smf_create_service_pgroup(smb_scfhandle_t * handle,char * pgroup)65da6c28aaSamw smb_smf_create_service_pgroup(smb_scfhandle_t *handle, char *pgroup)
66da6c28aaSamw {
67da6c28aaSamw 	int ret = SMBD_SMF_OK;
68da6c28aaSamw 	int err;
69da6c28aaSamw 
707b59d02dSjb 	if (handle == NULL)
71da6c28aaSamw 		return (SMBD_SMF_SYSTEM_ERR);
72da6c28aaSamw 
73da6c28aaSamw 	/*
74da6c28aaSamw 	 * only create a handle if it doesn't exist. It is ok to exist
75da6c28aaSamw 	 * since the pg handle will be set as a side effect.
76da6c28aaSamw 	 */
77da6c28aaSamw 	if (handle->scf_pg == NULL)
787b59d02dSjb 		if ((handle->scf_pg =
797b59d02dSjb 		    scf_pg_create(handle->scf_handle)) == NULL)
807b59d02dSjb 			return (SMBD_SMF_SYSTEM_ERR);
81da6c28aaSamw 
82da6c28aaSamw 	/*
83da6c28aaSamw 	 * if the pgroup exists, we are done. If it doesn't, then we
84da6c28aaSamw 	 * need to actually add one to the service instance.
85da6c28aaSamw 	 */
86da6c28aaSamw 	if (scf_service_get_pg(handle->scf_service,
87da6c28aaSamw 	    pgroup, handle->scf_pg) != 0) {
88da6c28aaSamw 		/* doesn't exist so create one */
89da6c28aaSamw 		if (scf_service_add_pg(handle->scf_service, pgroup,
90da6c28aaSamw 		    SCF_GROUP_APPLICATION, 0, handle->scf_pg) != 0) {
91da6c28aaSamw 			err = scf_error();
92da6c28aaSamw 			if (err != SCF_ERROR_NONE)
93da6c28aaSamw 				smb_smf_scf_log_error(NULL);
94da6c28aaSamw 			switch (err) {
95da6c28aaSamw 			case SCF_ERROR_PERMISSION_DENIED:
96da6c28aaSamw 				ret = SMBD_SMF_NO_PERMISSION;
97da6c28aaSamw 				break;
98da6c28aaSamw 			default:
99da6c28aaSamw 				ret = SMBD_SMF_SYSTEM_ERR;
100da6c28aaSamw 				break;
101da6c28aaSamw 			}
102da6c28aaSamw 		}
103da6c28aaSamw 	}
104da6c28aaSamw 	return (ret);
105da6c28aaSamw }
106da6c28aaSamw 
107da6c28aaSamw /*
108da6c28aaSamw  * Start transaction on current pg in handle.
109da6c28aaSamw  * The pg could be service or instance level.
110da6c28aaSamw  * Must be called after pg handle is obtained
111da6c28aaSamw  * from create or get.
112da6c28aaSamw  */
113da6c28aaSamw int
smb_smf_start_transaction(smb_scfhandle_t * handle)114da6c28aaSamw smb_smf_start_transaction(smb_scfhandle_t *handle)
115da6c28aaSamw {
116da6c28aaSamw 	int ret = SMBD_SMF_OK;
117da6c28aaSamw 
118da6c28aaSamw 	if (!handle || (!handle->scf_pg))
119da6c28aaSamw 		return (SMBD_SMF_SYSTEM_ERR);
120da6c28aaSamw 
121da6c28aaSamw 	/*
122da6c28aaSamw 	 * lookup the property group and create it if it doesn't already
123da6c28aaSamw 	 * exist.
124da6c28aaSamw 	 */
125da6c28aaSamw 	if (handle->scf_state == SCH_STATE_INIT) {
126da6c28aaSamw 		if (ret == SMBD_SMF_OK) {
127da6c28aaSamw 			handle->scf_trans =
128da6c28aaSamw 			    scf_transaction_create(handle->scf_handle);
129da6c28aaSamw 			if (handle->scf_trans != NULL) {
130da6c28aaSamw 				if (scf_transaction_start(handle->scf_trans,
131da6c28aaSamw 				    handle->scf_pg) != 0) {
132da6c28aaSamw 					ret = SMBD_SMF_SYSTEM_ERR;
133da6c28aaSamw 					scf_transaction_destroy(
134da6c28aaSamw 					    handle->scf_trans);
135da6c28aaSamw 					handle->scf_trans = NULL;
136da6c28aaSamw 				}
137da6c28aaSamw 			} else {
138da6c28aaSamw 				ret = SMBD_SMF_SYSTEM_ERR;
139da6c28aaSamw 			}
140da6c28aaSamw 		}
141da6c28aaSamw 	}
142da6c28aaSamw 	if (ret == SMBD_SMF_SYSTEM_ERR &&
143da6c28aaSamw 	    scf_error() == SCF_ERROR_PERMISSION_DENIED)
144da6c28aaSamw 		ret = SMBD_SMF_NO_PERMISSION;
145da6c28aaSamw 
146da6c28aaSamw 	return (ret);
147da6c28aaSamw }
148da6c28aaSamw 
149da6c28aaSamw /*
150da6c28aaSamw  * smb_smf_end_transaction(handle)
151da6c28aaSamw  *
152da6c28aaSamw  * Commit the changes that were added to the transaction in the
153da6c28aaSamw  * handle. Do all necessary cleanup.
154da6c28aaSamw  */
155da6c28aaSamw int
smb_smf_end_transaction(smb_scfhandle_t * handle)156da6c28aaSamw smb_smf_end_transaction(smb_scfhandle_t *handle)
157da6c28aaSamw {
158da6c28aaSamw 	int ret = SMBD_SMF_OK;
159a90cf9f2SGordon Ross 	int rc;
160da6c28aaSamw 
161da6c28aaSamw 	if (handle == NULL)
162da6c28aaSamw 		return (SMBD_SMF_SYSTEM_ERR);
163da6c28aaSamw 
164da6c28aaSamw 	if (handle->scf_trans == NULL) {
165da6c28aaSamw 		ret = SMBD_SMF_SYSTEM_ERR;
166da6c28aaSamw 	} else {
167a90cf9f2SGordon Ross 		rc = scf_transaction_commit(handle->scf_trans);
168a90cf9f2SGordon Ross 		if (rc == 1) {
169a90cf9f2SGordon Ross 			ret = SMBD_SMF_OK;
170a90cf9f2SGordon Ross 		} else if (rc == 0) {
171a90cf9f2SGordon Ross 			ret = SMBD_SMF_INVALID_ARG;
172c79c9de5SAndy Fiddaman 			smb_smf_scf_log_error(
173c79c9de5SAndy Fiddaman 			    "Failed to commit, old pg: transaction");
174a90cf9f2SGordon Ross 		} else {
175da6c28aaSamw 			ret = SMBD_SMF_SYSTEM_ERR;
176c79c9de5SAndy Fiddaman 			smb_smf_scf_log_error(
177c79c9de5SAndy Fiddaman 			    "Failed to commit, error: transaction");
178da6c28aaSamw 		}
179da6c28aaSamw 		scf_transaction_destroy_children(handle->scf_trans);
180da6c28aaSamw 		scf_transaction_destroy(handle->scf_trans);
181da6c28aaSamw 		handle->scf_trans = NULL;
182da6c28aaSamw 	}
183da6c28aaSamw 	return (ret);
184da6c28aaSamw }
185da6c28aaSamw 
186da6c28aaSamw /*
187da6c28aaSamw  * Sets string property in current pg
188da6c28aaSamw  */
189da6c28aaSamw int
smb_smf_set_string_property(smb_scfhandle_t * handle,char * propname,char * valstr)190da6c28aaSamw smb_smf_set_string_property(smb_scfhandle_t *handle,
191da6c28aaSamw     char *propname, char *valstr)
192da6c28aaSamw {
193da6c28aaSamw 	int ret = SMBD_SMF_OK;
194da6c28aaSamw 	scf_value_t *value = NULL;
195da6c28aaSamw 	scf_transaction_entry_t *entry = NULL;
196da6c28aaSamw 
197da6c28aaSamw 	if (handle == NULL)
198da6c28aaSamw 		return (SMBD_SMF_SYSTEM_ERR);
199da6c28aaSamw 
200da6c28aaSamw 	/*
201da6c28aaSamw 	 * properties must be set in transactions and don't take
202da6c28aaSamw 	 * effect until the transaction has been ended/committed.
203da6c28aaSamw 	 */
204da6c28aaSamw 	value = scf_value_create(handle->scf_handle);
205da6c28aaSamw 	entry = scf_entry_create(handle->scf_handle);
206da6c28aaSamw 	if (value != NULL && entry != NULL) {
207da6c28aaSamw 		if (scf_transaction_property_change(handle->scf_trans, entry,
208da6c28aaSamw 		    propname, SCF_TYPE_ASTRING) == 0 ||
209da6c28aaSamw 		    scf_transaction_property_new(handle->scf_trans, entry,
210da6c28aaSamw 		    propname, SCF_TYPE_ASTRING) == 0) {
211da6c28aaSamw 			if (scf_value_set_astring(value, valstr) == 0) {
212da6c28aaSamw 				if (scf_entry_add_value(entry, value) != 0) {
213da6c28aaSamw 					ret = SMBD_SMF_SYSTEM_ERR;
214da6c28aaSamw 					scf_value_destroy(value);
215da6c28aaSamw 				}
216da6c28aaSamw 				/* the value is in the transaction */
217da6c28aaSamw 				value = NULL;
218da6c28aaSamw 			} else {
219da6c28aaSamw 				/* value couldn't be constructed */
220da6c28aaSamw 				ret = SMBD_SMF_SYSTEM_ERR;
221da6c28aaSamw 			}
222da6c28aaSamw 			/* the entry is in the transaction */
223da6c28aaSamw 			entry = NULL;
224da6c28aaSamw 		} else {
225da6c28aaSamw 			ret = SMBD_SMF_SYSTEM_ERR;
226da6c28aaSamw 		}
227da6c28aaSamw 	} else {
228da6c28aaSamw 		ret = SMBD_SMF_SYSTEM_ERR;
229da6c28aaSamw 	}
230da6c28aaSamw 	if (ret == SMBD_SMF_SYSTEM_ERR) {
231*2bc647a2SToomas Soome 		if (scf_error() == SCF_ERROR_PERMISSION_DENIED) {
232da6c28aaSamw 			ret = SMBD_SMF_NO_PERMISSION;
233da6c28aaSamw 		}
234da6c28aaSamw 	}
235da6c28aaSamw 
236da6c28aaSamw 	/*
237da6c28aaSamw 	 * cleanup if there were any errors that didn't leave these
238da6c28aaSamw 	 * values where they would be cleaned up later.
239da6c28aaSamw 	 */
240da6c28aaSamw 	if (value != NULL)
241da6c28aaSamw 		scf_value_destroy(value);
242da6c28aaSamw 	if (entry != NULL)
243da6c28aaSamw 		scf_entry_destroy(entry);
244da6c28aaSamw 	return (ret);
245da6c28aaSamw }
246da6c28aaSamw 
247da6c28aaSamw /*
248da6c28aaSamw  * Gets string property value.upto sz size.
249da6c28aaSamw  * Caller is responsible to have enough memory allocated.
250da6c28aaSamw  */
251da6c28aaSamw int
smb_smf_get_string_property(smb_scfhandle_t * handle,char * propname,char * valstr,size_t sz)252da6c28aaSamw smb_smf_get_string_property(smb_scfhandle_t *handle, char *propname,
253da6c28aaSamw     char *valstr, size_t sz)
254da6c28aaSamw {
255da6c28aaSamw 	int ret = SMBD_SMF_OK;
256da6c28aaSamw 	scf_value_t *value;
257da6c28aaSamw 	scf_property_t *prop;
258da6c28aaSamw 
259da6c28aaSamw 	if (handle == NULL)
260da6c28aaSamw 		return (SMBD_SMF_SYSTEM_ERR);
261da6c28aaSamw 
262da6c28aaSamw 	value = scf_value_create(handle->scf_handle);
263da6c28aaSamw 	prop = scf_property_create(handle->scf_handle);
264da6c28aaSamw 	if (value && prop &&
265da6c28aaSamw 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
266da6c28aaSamw 		if (scf_property_get_value(prop, value) == 0) {
267da6c28aaSamw 			if (scf_value_get_astring(value, valstr, sz) < 0) {
268da6c28aaSamw 				ret = SMBD_SMF_SYSTEM_ERR;
269da6c28aaSamw 			}
270da6c28aaSamw 		} else {
271da6c28aaSamw 			ret = SMBD_SMF_SYSTEM_ERR;
272da6c28aaSamw 		}
273da6c28aaSamw 	} else {
274da6c28aaSamw 		ret = SMBD_SMF_SYSTEM_ERR;
275da6c28aaSamw 	}
276da6c28aaSamw 	if (value != NULL)
277da6c28aaSamw 		scf_value_destroy(value);
278da6c28aaSamw 	if (prop != NULL)
279da6c28aaSamw 		scf_property_destroy(prop);
280da6c28aaSamw 	return (ret);
281da6c28aaSamw }
282da6c28aaSamw 
283da6c28aaSamw /*
284da6c28aaSamw  * Set integer value of property.
285da6c28aaSamw  * The value is returned as int64_t value
286da6c28aaSamw  * Caller ensures appropriate translation.
287da6c28aaSamw  */
288da6c28aaSamw int
smb_smf_set_integer_property(smb_scfhandle_t * handle,char * propname,int64_t valint)289da6c28aaSamw smb_smf_set_integer_property(smb_scfhandle_t *handle, char *propname,
290da6c28aaSamw     int64_t valint)
291da6c28aaSamw {
292da6c28aaSamw 	int ret = SMBD_SMF_OK;
293da6c28aaSamw 	scf_value_t *value = NULL;
294da6c28aaSamw 	scf_transaction_entry_t *entry = NULL;
295da6c28aaSamw 
296da6c28aaSamw 	if (handle == NULL)
297da6c28aaSamw 		return (SMBD_SMF_SYSTEM_ERR);
298da6c28aaSamw 
299da6c28aaSamw 	/*
300da6c28aaSamw 	 * properties must be set in transactions and don't take
301da6c28aaSamw 	 * effect until the transaction has been ended/committed.
302da6c28aaSamw 	 */
303da6c28aaSamw 	value = scf_value_create(handle->scf_handle);
304da6c28aaSamw 	entry = scf_entry_create(handle->scf_handle);
305da6c28aaSamw 	if (value != NULL && entry != NULL) {
306da6c28aaSamw 		if (scf_transaction_property_change(handle->scf_trans, entry,
307da6c28aaSamw 		    propname, SCF_TYPE_INTEGER) == 0 ||
308da6c28aaSamw 		    scf_transaction_property_new(handle->scf_trans, entry,
309da6c28aaSamw 		    propname, SCF_TYPE_INTEGER) == 0) {
310da6c28aaSamw 			scf_value_set_integer(value, valint);
311da6c28aaSamw 			if (scf_entry_add_value(entry, value) != 0) {
312da6c28aaSamw 				ret = SMBD_SMF_SYSTEM_ERR;
313da6c28aaSamw 				scf_value_destroy(value);
314da6c28aaSamw 			}
315da6c28aaSamw 			/* the value is in the transaction */
316da6c28aaSamw 			value = NULL;
317da6c28aaSamw 		}
318da6c28aaSamw 		/* the entry is in the transaction */
319da6c28aaSamw 		entry = NULL;
320da6c28aaSamw 	} else {
321da6c28aaSamw 		ret = SMBD_SMF_SYSTEM_ERR;
322da6c28aaSamw 	}
323da6c28aaSamw 	if (ret == SMBD_SMF_SYSTEM_ERR) {
324*2bc647a2SToomas Soome 		if (scf_error() == SCF_ERROR_PERMISSION_DENIED) {
325da6c28aaSamw 			ret = SMBD_SMF_NO_PERMISSION;
326da6c28aaSamw 		}
327da6c28aaSamw 	}
328da6c28aaSamw 	/*
329da6c28aaSamw 	 * cleanup if there were any errors that didn't leave these
330da6c28aaSamw 	 * values where they would be cleaned up later.
331da6c28aaSamw 	 */
332da6c28aaSamw 	if (value != NULL)
333da6c28aaSamw 		scf_value_destroy(value);
334da6c28aaSamw 	if (entry != NULL)
335da6c28aaSamw 		scf_entry_destroy(entry);
336da6c28aaSamw 	return (ret);
337da6c28aaSamw }
338da6c28aaSamw 
339da6c28aaSamw /*
340da6c28aaSamw  * Gets integer property value.
341da6c28aaSamw  * Caller is responsible to have enough memory allocated.
342da6c28aaSamw  */
343da6c28aaSamw int
smb_smf_get_integer_property(smb_scfhandle_t * handle,char * propname,int64_t * valint)344da6c28aaSamw smb_smf_get_integer_property(smb_scfhandle_t *handle, char *propname,
345da6c28aaSamw     int64_t *valint)
346da6c28aaSamw {
347da6c28aaSamw 	int ret = SMBD_SMF_OK;
348da6c28aaSamw 	scf_value_t *value = NULL;
349da6c28aaSamw 	scf_property_t *prop = NULL;
350da6c28aaSamw 
351da6c28aaSamw 	if (handle == NULL)
352da6c28aaSamw 		return (SMBD_SMF_SYSTEM_ERR);
353da6c28aaSamw 
354da6c28aaSamw 	value = scf_value_create(handle->scf_handle);
355da6c28aaSamw 	prop = scf_property_create(handle->scf_handle);
356da6c28aaSamw 	if ((prop) && (value) &&
357da6c28aaSamw 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
358da6c28aaSamw 		if (scf_property_get_value(prop, value) == 0) {
359da6c28aaSamw 			if (scf_value_get_integer(value,
360da6c28aaSamw 			    valint) != 0) {
361da6c28aaSamw 				ret = SMBD_SMF_SYSTEM_ERR;
362da6c28aaSamw 			}
363da6c28aaSamw 		} else {
364da6c28aaSamw 			ret = SMBD_SMF_SYSTEM_ERR;
365da6c28aaSamw 		}
366da6c28aaSamw 	} else {
367da6c28aaSamw 		ret = SMBD_SMF_SYSTEM_ERR;
368da6c28aaSamw 	}
369da6c28aaSamw 	if (value != NULL)
370da6c28aaSamw 		scf_value_destroy(value);
371da6c28aaSamw 	if (prop != NULL)
372da6c28aaSamw 		scf_property_destroy(prop);
373da6c28aaSamw 	return (ret);
374da6c28aaSamw }
375da6c28aaSamw 
376da6c28aaSamw /*
377da6c28aaSamw  * Set boolean value of property.
378da6c28aaSamw  * The value is returned as int64_t value
379da6c28aaSamw  * Caller ensures appropriate translation.
380da6c28aaSamw  */
381da6c28aaSamw int
smb_smf_set_boolean_property(smb_scfhandle_t * handle,char * propname,uint8_t valbool)382da6c28aaSamw smb_smf_set_boolean_property(smb_scfhandle_t *handle, char *propname,
383da6c28aaSamw     uint8_t valbool)
384da6c28aaSamw {
385da6c28aaSamw 	int ret = SMBD_SMF_OK;
386da6c28aaSamw 	scf_value_t *value = NULL;
387da6c28aaSamw 	scf_transaction_entry_t *entry = NULL;
388da6c28aaSamw 
389da6c28aaSamw 	if (handle == NULL)
390da6c28aaSamw 		return (SMBD_SMF_SYSTEM_ERR);
391da6c28aaSamw 
392da6c28aaSamw 	/*
393da6c28aaSamw 	 * properties must be set in transactions and don't take
394da6c28aaSamw 	 * effect until the transaction has been ended/committed.
395da6c28aaSamw 	 */
396da6c28aaSamw 	value = scf_value_create(handle->scf_handle);
397da6c28aaSamw 	entry = scf_entry_create(handle->scf_handle);
398da6c28aaSamw 	if (value != NULL && entry != NULL) {
399da6c28aaSamw 		if (scf_transaction_property_change(handle->scf_trans, entry,
400da6c28aaSamw 		    propname, SCF_TYPE_BOOLEAN) == 0 ||
401da6c28aaSamw 		    scf_transaction_property_new(handle->scf_trans, entry,
402da6c28aaSamw 		    propname, SCF_TYPE_BOOLEAN) == 0) {
403da6c28aaSamw 			scf_value_set_boolean(value, valbool);
404da6c28aaSamw 			if (scf_entry_add_value(entry, value) != 0) {
405da6c28aaSamw 				ret = SMBD_SMF_SYSTEM_ERR;
406da6c28aaSamw 				scf_value_destroy(value);
407da6c28aaSamw 			}
408da6c28aaSamw 			/* the value is in the transaction */
409da6c28aaSamw 			value = NULL;
410da6c28aaSamw 		}
411da6c28aaSamw 		/* the entry is in the transaction */
412da6c28aaSamw 		entry = NULL;
413da6c28aaSamw 	} else {
414da6c28aaSamw 		ret = SMBD_SMF_SYSTEM_ERR;
415da6c28aaSamw 	}
416da6c28aaSamw 	if (ret == SMBD_SMF_SYSTEM_ERR) {
417*2bc647a2SToomas Soome 		if (scf_error() == SCF_ERROR_PERMISSION_DENIED) {
418da6c28aaSamw 			ret = SMBD_SMF_NO_PERMISSION;
419da6c28aaSamw 		}
420da6c28aaSamw 	}
421da6c28aaSamw 	/*
422da6c28aaSamw 	 * cleanup if there were any errors that didn't leave these
423da6c28aaSamw 	 * values where they would be cleaned up later.
424da6c28aaSamw 	 */
425da6c28aaSamw 	if (value != NULL)
426da6c28aaSamw 		scf_value_destroy(value);
427da6c28aaSamw 	if (entry != NULL)
428da6c28aaSamw 		scf_entry_destroy(entry);
429da6c28aaSamw 	return (ret);
430da6c28aaSamw }
431da6c28aaSamw 
432da6c28aaSamw /*
433da6c28aaSamw  * Gets boolean property value.
434da6c28aaSamw  * Caller is responsible to have enough memory allocated.
435da6c28aaSamw  */
436da6c28aaSamw int
smb_smf_get_boolean_property(smb_scfhandle_t * handle,char * propname,uint8_t * valbool)437da6c28aaSamw smb_smf_get_boolean_property(smb_scfhandle_t *handle, char *propname,
438da6c28aaSamw     uint8_t *valbool)
439da6c28aaSamw {
440da6c28aaSamw 	int ret = SMBD_SMF_OK;
441da6c28aaSamw 	scf_value_t *value = NULL;
442da6c28aaSamw 	scf_property_t *prop = NULL;
443da6c28aaSamw 
444da6c28aaSamw 	if (handle == NULL)
445da6c28aaSamw 		return (SMBD_SMF_SYSTEM_ERR);
446da6c28aaSamw 
447da6c28aaSamw 	value = scf_value_create(handle->scf_handle);
448da6c28aaSamw 	prop = scf_property_create(handle->scf_handle);
449da6c28aaSamw 	if ((prop) && (value) &&
450da6c28aaSamw 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
451da6c28aaSamw 		if (scf_property_get_value(prop, value) == 0) {
452da6c28aaSamw 			if (scf_value_get_boolean(value,
453da6c28aaSamw 			    valbool) != 0) {
454da6c28aaSamw 				ret = SMBD_SMF_SYSTEM_ERR;
455da6c28aaSamw 			}
456da6c28aaSamw 		} else {
457da6c28aaSamw 			ret = SMBD_SMF_SYSTEM_ERR;
458da6c28aaSamw 		}
459da6c28aaSamw 	} else {
460da6c28aaSamw 		ret = SMBD_SMF_SYSTEM_ERR;
461da6c28aaSamw 	}
462da6c28aaSamw 	if (value != NULL)
463da6c28aaSamw 		scf_value_destroy(value);
464da6c28aaSamw 	if (prop != NULL)
465da6c28aaSamw 		scf_property_destroy(prop);
466da6c28aaSamw 	return (ret);
467da6c28aaSamw }
468da6c28aaSamw 
469da6c28aaSamw /*
470da6c28aaSamw  * Sets a blob property value.
471da6c28aaSamw  */
472da6c28aaSamw int
smb_smf_set_opaque_property(smb_scfhandle_t * handle,char * propname,void * voidval,size_t sz)473da6c28aaSamw smb_smf_set_opaque_property(smb_scfhandle_t *handle, char *propname,
474da6c28aaSamw     void *voidval, size_t sz)
475da6c28aaSamw {
476da6c28aaSamw 	int ret = SMBD_SMF_OK;
477da6c28aaSamw 	scf_value_t *value;
478da6c28aaSamw 	scf_transaction_entry_t *entry;
479da6c28aaSamw 
480da6c28aaSamw 	if (handle == NULL)
481da6c28aaSamw 		return (SMBD_SMF_SYSTEM_ERR);
482da6c28aaSamw 
483da6c28aaSamw 	/*
484da6c28aaSamw 	 * properties must be set in transactions and don't take
485da6c28aaSamw 	 * effect until the transaction has been ended/committed.
486da6c28aaSamw 	 */
487da6c28aaSamw 	value = scf_value_create(handle->scf_handle);
488da6c28aaSamw 	entry = scf_entry_create(handle->scf_handle);
489da6c28aaSamw 	if (value != NULL && entry != NULL) {
490da6c28aaSamw 		if (scf_transaction_property_change(handle->scf_trans, entry,
491da6c28aaSamw 		    propname, SCF_TYPE_OPAQUE) == 0 ||
492da6c28aaSamw 		    scf_transaction_property_new(handle->scf_trans, entry,
493da6c28aaSamw 		    propname, SCF_TYPE_OPAQUE) == 0) {
494da6c28aaSamw 			if (scf_value_set_opaque(value, voidval, sz) == 0) {
495da6c28aaSamw 				if (scf_entry_add_value(entry, value) != 0) {
496da6c28aaSamw 					ret = SMBD_SMF_SYSTEM_ERR;
497da6c28aaSamw 					scf_value_destroy(value);
498da6c28aaSamw 				}
499da6c28aaSamw 				/* the value is in the transaction */
500da6c28aaSamw 				value = NULL;
501da6c28aaSamw 			} else {
502da6c28aaSamw 				/* value couldn't be constructed */
503da6c28aaSamw 				ret = SMBD_SMF_SYSTEM_ERR;
504da6c28aaSamw 			}
505da6c28aaSamw 			/* the entry is in the transaction */
506da6c28aaSamw 			entry = NULL;
507da6c28aaSamw 		} else {
508da6c28aaSamw 			ret = SMBD_SMF_SYSTEM_ERR;
509da6c28aaSamw 		}
510da6c28aaSamw 	} else {
511da6c28aaSamw 		ret = SMBD_SMF_SYSTEM_ERR;
512da6c28aaSamw 	}
513da6c28aaSamw 	if (ret == SMBD_SMF_SYSTEM_ERR) {
514*2bc647a2SToomas Soome 		if (scf_error() == SCF_ERROR_PERMISSION_DENIED) {
515da6c28aaSamw 			ret = SMBD_SMF_NO_PERMISSION;
516da6c28aaSamw 		}
517da6c28aaSamw 	}
518da6c28aaSamw 	/*
519da6c28aaSamw 	 * cleanup if there were any errors that didn't leave these
520da6c28aaSamw 	 * values where they would be cleaned up later.
521da6c28aaSamw 	 */
522da6c28aaSamw 	if (value != NULL)
523da6c28aaSamw 		scf_value_destroy(value);
524da6c28aaSamw 	if (entry != NULL)
525da6c28aaSamw 		scf_entry_destroy(entry);
526da6c28aaSamw 	return (ret);
527da6c28aaSamw }
528da6c28aaSamw 
529da6c28aaSamw /*
530da6c28aaSamw  * Gets a blob property value.
531da6c28aaSamw  * Caller is responsible to have enough memory allocated.
532da6c28aaSamw  */
533da6c28aaSamw int
smb_smf_get_opaque_property(smb_scfhandle_t * handle,char * propname,void * v,size_t sz)534da6c28aaSamw smb_smf_get_opaque_property(smb_scfhandle_t *handle, char *propname,
535da6c28aaSamw     void *v, size_t sz)
536da6c28aaSamw {
537da6c28aaSamw 	int ret = SMBD_SMF_OK;
538da6c28aaSamw 	scf_value_t *value = NULL;
539da6c28aaSamw 	scf_property_t *prop = NULL;
540da6c28aaSamw 
541da6c28aaSamw 	if (handle == NULL)
542da6c28aaSamw 		return (SMBD_SMF_SYSTEM_ERR);
543da6c28aaSamw 
544da6c28aaSamw 	value = scf_value_create(handle->scf_handle);
545da6c28aaSamw 	prop = scf_property_create(handle->scf_handle);
546da6c28aaSamw 	if ((prop) && (value) &&
547da6c28aaSamw 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
548da6c28aaSamw 		if (scf_property_get_value(prop, value) == 0) {
549da6c28aaSamw 			if (scf_value_get_opaque(value, (char *)v, sz) != sz) {
550da6c28aaSamw 				ret = SMBD_SMF_SYSTEM_ERR;
551da6c28aaSamw 			}
552da6c28aaSamw 		} else {
553da6c28aaSamw 			ret = SMBD_SMF_SYSTEM_ERR;
554da6c28aaSamw 		}
555da6c28aaSamw 	} else {
556da6c28aaSamw 		ret = SMBD_SMF_SYSTEM_ERR;
557da6c28aaSamw 	}
558da6c28aaSamw 	if (value != NULL)
559da6c28aaSamw 		scf_value_destroy(value);
560da6c28aaSamw 	if (prop != NULL)
561da6c28aaSamw 		scf_property_destroy(prop);
562da6c28aaSamw 	return (ret);
563da6c28aaSamw }
564da6c28aaSamw 
565a90cf9f2SGordon Ross /*
566a90cf9f2SGordon Ross  * Delete a property (for properties obsoleted during an upgrade).
567a90cf9f2SGordon Ross  */
568a90cf9f2SGordon Ross int
smb_smf_delete_property(smb_scfhandle_t * handle,char * propname)569a90cf9f2SGordon Ross smb_smf_delete_property(smb_scfhandle_t *handle, char *propname)
570a90cf9f2SGordon Ross {
571a90cf9f2SGordon Ross 	scf_transaction_entry_t *entry;
572a90cf9f2SGordon Ross 	int ret = SMBD_SMF_OK;
573a90cf9f2SGordon Ross 
574a90cf9f2SGordon Ross 	if (handle == NULL)
575a90cf9f2SGordon Ross 		return (SMBD_SMF_SYSTEM_ERR);
576a90cf9f2SGordon Ross 	if (handle->scf_trans == NULL)
577a90cf9f2SGordon Ross 		return (SMBD_SMF_SYSTEM_ERR);
578a90cf9f2SGordon Ross 
579a90cf9f2SGordon Ross 	/*
580a90cf9f2SGordon Ross 	 * properties must be set in transactions and don't take
581a90cf9f2SGordon Ross 	 * effect until the transaction has been ended/committed.
582a90cf9f2SGordon Ross 	 */
583a90cf9f2SGordon Ross 	entry = scf_entry_create(handle->scf_handle);
584a90cf9f2SGordon Ross 	if (entry == NULL) {
585a90cf9f2SGordon Ross 		ret = SMBD_SMF_SYSTEM_ERR;
586a90cf9f2SGordon Ross 		goto out;
587a90cf9f2SGordon Ross 	}
588a90cf9f2SGordon Ross 
589a90cf9f2SGordon Ross 	if (scf_transaction_property_delete(handle->scf_trans,
590a90cf9f2SGordon Ross 	    entry, propname) == 0) {
591a90cf9f2SGordon Ross 		/* the entry is in the transaction */
592a90cf9f2SGordon Ross 		entry = NULL;
593a90cf9f2SGordon Ross 	} else {
594a90cf9f2SGordon Ross 		switch (scf_error()) {
595a90cf9f2SGordon Ross 		case SCF_ERROR_NOT_FOUND:
596a90cf9f2SGordon Ross 			/* Did not exist.  We're done. */
597a90cf9f2SGordon Ross 			ret = SMBD_SMF_OK;
598a90cf9f2SGordon Ross 			goto out;
599a90cf9f2SGordon Ross 		case SCF_ERROR_PERMISSION_DENIED:
600a90cf9f2SGordon Ross 			ret = SMBD_SMF_NO_PERMISSION;
601a90cf9f2SGordon Ross 			goto out;
602a90cf9f2SGordon Ross 		default:
603a90cf9f2SGordon Ross 			ret = SMBD_SMF_SYSTEM_ERR;
604a90cf9f2SGordon Ross 			goto out;
605a90cf9f2SGordon Ross 		}
606a90cf9f2SGordon Ross 	}
607a90cf9f2SGordon Ross 
608a90cf9f2SGordon Ross out:
609a90cf9f2SGordon Ross 	scf_entry_destroy(entry);
610a90cf9f2SGordon Ross 	return (ret);
611a90cf9f2SGordon Ross }
612a90cf9f2SGordon Ross 
613c8ec8eeaSjose borrego /*
6148d7e4166Sjose borrego  * Put the smb service into maintenance mode.
6158d7e4166Sjose borrego  */
6168d7e4166Sjose borrego int
smb_smf_maintenance_mode(void)6178d7e4166Sjose borrego smb_smf_maintenance_mode(void)
6188d7e4166Sjose borrego {
6198d7e4166Sjose borrego 	return (smf_maintain_instance(SMBD_DEFAULT_INSTANCE_FMRI, 0));
6208d7e4166Sjose borrego }
6218d7e4166Sjose borrego 
6228d7e4166Sjose borrego /*
6238d7e4166Sjose borrego  * Restart the smb service.
624c8ec8eeaSjose borrego  */
625c8ec8eeaSjose borrego int
smb_smf_restart_service(void)626c8ec8eeaSjose borrego smb_smf_restart_service(void)
627c8ec8eeaSjose borrego {
628c8ec8eeaSjose borrego 	return (smf_restart_instance(SMBD_DEFAULT_INSTANCE_FMRI));
629c8ec8eeaSjose borrego }
630c8ec8eeaSjose borrego 
631da6c28aaSamw /*
632da6c28aaSamw  * smb_smf_scf_init()
633da6c28aaSamw  *
634da6c28aaSamw  * must be called before using any of the SCF functions.
635da6c28aaSamw  * Returns smb_scfhandle_t pointer if success.
636da6c28aaSamw  */
637da6c28aaSamw smb_scfhandle_t *
smb_smf_scf_init(char * svc_name)638da6c28aaSamw smb_smf_scf_init(char *svc_name)
639da6c28aaSamw {
640da6c28aaSamw 	smb_scfhandle_t *handle;
641da6c28aaSamw 
642da6c28aaSamw 	handle = malloc(sizeof (smb_scfhandle_t));
643da6c28aaSamw 	if (handle != NULL) {
644da6c28aaSamw 		bzero((char *)handle, sizeof (smb_scfhandle_t));
645da6c28aaSamw 		handle->scf_state = SCH_STATE_INITIALIZING;
646da6c28aaSamw 		handle->scf_handle = scf_handle_create(SCF_VERSION);
647da6c28aaSamw 		if (handle->scf_handle != NULL) {
648da6c28aaSamw 			if (scf_handle_bind(handle->scf_handle) == 0) {
649da6c28aaSamw 				handle->scf_scope =
650da6c28aaSamw 				    scf_scope_create(handle->scf_handle);
6517b59d02dSjb 
6527b59d02dSjb 				if (handle->scf_scope == NULL)
6537b59d02dSjb 					goto err;
6547b59d02dSjb 
655da6c28aaSamw 				if (scf_handle_get_local_scope(
656da6c28aaSamw 				    handle->scf_handle, handle->scf_scope) != 0)
657da6c28aaSamw 					goto err;
658da6c28aaSamw 
659da6c28aaSamw 				handle->scf_service =
660da6c28aaSamw 				    scf_service_create(handle->scf_handle);
661da6c28aaSamw 
6627b59d02dSjb 				if (handle->scf_service == NULL)
6637b59d02dSjb 					goto err;
6647b59d02dSjb 
665da6c28aaSamw 				if (scf_scope_get_service(handle->scf_scope,
666da6c28aaSamw 				    svc_name, handle->scf_service)
667da6c28aaSamw 				    != SCF_SUCCESS) {
668da6c28aaSamw 					goto err;
669da6c28aaSamw 				}
670da6c28aaSamw 				handle->scf_pg =
671da6c28aaSamw 				    scf_pg_create(handle->scf_handle);
6727b59d02dSjb 
6737b59d02dSjb 				if (handle->scf_pg == NULL)
6747b59d02dSjb 					goto err;
6757b59d02dSjb 
676da6c28aaSamw 				handle->scf_state = SCH_STATE_INIT;
677da6c28aaSamw 			} else {
678da6c28aaSamw 				goto err;
679da6c28aaSamw 			}
680da6c28aaSamw 		} else {
681da6c28aaSamw 			free(handle);
682da6c28aaSamw 			handle = NULL;
683c79c9de5SAndy Fiddaman 			smb_smf_scf_log_error(
684c79c9de5SAndy Fiddaman 			    "Could not access SMF repository");
685da6c28aaSamw 		}
686da6c28aaSamw 	}
687da6c28aaSamw 	return (handle);
688da6c28aaSamw 
689da6c28aaSamw 	/* error handling/unwinding */
690da6c28aaSamw err:
691da6c28aaSamw 	(void) smb_smf_scf_fini(handle);
692327e8b4bSAndy Fiddaman 	if (scf_error() != SCF_ERROR_NOT_FOUND)
693327e8b4bSAndy Fiddaman 		(void) smb_smf_scf_log_error("SMF initialization problem");
694da6c28aaSamw 	return (NULL);
695da6c28aaSamw }
696da6c28aaSamw 
697da6c28aaSamw /*
698da6c28aaSamw  * smb_smf_scf_fini(handle)
699da6c28aaSamw  *
700da6c28aaSamw  * must be called when done. Called with the handle allocated in
701da6c28aaSamw  * smb_smf_scf_init(), it cleans up the state and frees any SCF resources
702da6c28aaSamw  * still in use.
703da6c28aaSamw  */
704da6c28aaSamw void
smb_smf_scf_fini(smb_scfhandle_t * handle)705da6c28aaSamw smb_smf_scf_fini(smb_scfhandle_t *handle)
706da6c28aaSamw {
707da6c28aaSamw 	if (handle != NULL) {
708da6c28aaSamw 		int unbind = 0;
709da6c28aaSamw 		scf_iter_destroy(handle->scf_pg_iter);
710da6c28aaSamw 		handle->scf_pg_iter = NULL;
711da6c28aaSamw 
712da6c28aaSamw 		scf_iter_destroy(handle->scf_inst_iter);
713da6c28aaSamw 		handle->scf_inst_iter = NULL;
714da6c28aaSamw 
715da6c28aaSamw 		unbind = 1;
716da6c28aaSamw 		scf_scope_destroy(handle->scf_scope);
717da6c28aaSamw 		handle->scf_scope = NULL;
718da6c28aaSamw 
719da6c28aaSamw 		scf_instance_destroy(handle->scf_instance);
720da6c28aaSamw 		handle->scf_instance = NULL;
721da6c28aaSamw 
722da6c28aaSamw 		scf_service_destroy(handle->scf_service);
723da6c28aaSamw 		handle->scf_service = NULL;
724da6c28aaSamw 
725da6c28aaSamw 		scf_pg_destroy(handle->scf_pg);
726da6c28aaSamw 		handle->scf_pg = NULL;
727da6c28aaSamw 
728da6c28aaSamw 		handle->scf_state = SCH_STATE_UNINIT;
729da6c28aaSamw 		if (unbind)
730da6c28aaSamw 			(void) scf_handle_unbind(handle->scf_handle);
731da6c28aaSamw 		scf_handle_destroy(handle->scf_handle);
732da6c28aaSamw 		handle->scf_handle = NULL;
733da6c28aaSamw 
734da6c28aaSamw 		free(handle);
735da6c28aaSamw 	}
736da6c28aaSamw }
737