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 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29/* helper functions for using libscf with CIFS */
30
31#include <libscf.h>
32#include <string.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <syslog.h>
36#include <errno.h>
37#include <uuid/uuid.h>
38#include <sys/param.h>
39#include <libintl.h>
40#include <assert.h>
41#include <strings.h>
42
43#include "libshare.h"
44#include "libshare_smbfs.h"
45
46/*
47 * smb_smf_scf_log_error(msg)
48 * Logs error messages from scf API's
49 */
50static void
51smb_smf_scf_log_error(char *msg)
52{
53	if (!msg) {
54		syslog(LOG_ERR, " SMBC SMF problem: %s\n",
55		    scf_strerror(scf_error()));
56	} else { /*LINTED E_SEC_PRINTF_E_VAR_FMT*/
57		syslog(LOG_ERR, msg, scf_strerror(scf_error()));
58	}
59}
60
61/*
62 * smb_smf_scf_fini(handle)
63 *
64 * must be called when done. Called with the handle allocated in
65 * smb_smf_scf_init(), it cleans up the state and frees any SCF resources
66 * still in use.
67 */
68void
69smb_smf_scf_fini(smb_scfhandle_t *handle)
70{
71	if (handle != NULL) {
72		int unbind = 0;
73		if (handle->scf_pg_iter != NULL) {
74			scf_iter_destroy(handle->scf_pg_iter);
75			handle->scf_pg_iter = NULL;
76		}
77		if (handle->scf_inst_iter != NULL) {
78			scf_iter_destroy(handle->scf_inst_iter);
79			handle->scf_inst_iter = NULL;
80		}
81		if (handle->scf_scope != NULL) {
82			unbind = 1;
83			scf_scope_destroy(handle->scf_scope);
84			handle->scf_scope = NULL;
85		}
86		if (handle->scf_instance != NULL) {
87			scf_instance_destroy(handle->scf_instance);
88			handle->scf_instance = NULL;
89		}
90		if (handle->scf_service != NULL) {
91			scf_service_destroy(handle->scf_service);
92			handle->scf_service = NULL;
93		}
94		if (handle->scf_pg != NULL) {
95			scf_pg_destroy(handle->scf_pg);
96			handle->scf_pg = NULL;
97		}
98		if (handle->scf_handle != NULL) {
99			handle->scf_state = SCH_STATE_UNINIT;
100			if (unbind)
101				(void) scf_handle_unbind(handle->scf_handle);
102			scf_handle_destroy(handle->scf_handle);
103			handle->scf_handle = NULL;
104		}
105		free(handle);
106	}
107}
108
109
110/*
111 * Check if instance with given name exists for a service.
112 * Returns 0 is instance exist
113 */
114int
115smb_smf_instance_exists(smb_scfhandle_t *handle, char *inst_name)
116{
117	int ret = SMBC_SMF_OK;
118	if (handle == NULL) {
119		return (SMBC_SMF_SYSTEM_ERR);
120	}
121
122	handle->scf_instance = scf_instance_create(handle->scf_handle);
123	if (scf_service_get_instance(handle->scf_service, inst_name,
124	    handle->scf_instance) != SCF_SUCCESS) {
125		ret = SMBC_SMF_SYSTEM_ERR;
126	}
127	scf_instance_destroy(handle->scf_instance);
128	handle->scf_instance = NULL;
129	return (ret);
130}
131
132/*
133 * Create a service instance. returns 0 if successful.
134 * If instance already exists enable it.
135 */
136int
137smb_smf_instance_create(smb_scfhandle_t *handle, char *serv_prefix,
138	char *inst_name)
139{
140	char *instance;
141	int ret = SMBC_SMF_OK;
142	int sz;
143
144	if (handle == NULL) {
145		return (SMBC_SMF_SYSTEM_ERR);
146	}
147
148	if (!serv_prefix || !inst_name) {
149		return (SMBC_SMF_SYSTEM_ERR);
150	}
151	sz = strlen(serv_prefix) + strlen(inst_name) + 2;
152	instance = malloc(sz);
153	if (!instance) {
154		return (SMBC_SMF_SYSTEM_ERR);
155	}
156	(void) snprintf(instance, sz, "%s:%s", serv_prefix, inst_name);
157	handle->scf_instance = scf_instance_create(handle->scf_handle);
158	if (scf_service_get_instance(handle->scf_service, inst_name,
159	    handle->scf_instance) != SCF_SUCCESS) {
160		if (scf_service_add_instance(handle->scf_service,
161		    inst_name, handle->scf_instance) == SCF_SUCCESS) {
162			if (smf_enable_instance(instance, 0))
163				ret = SMBC_SMF_SYSTEM_ERR;
164		} else {
165			ret = SMBC_SMF_SYSTEM_ERR;
166		}
167	} else {
168		if (smf_enable_instance(instance, 0))
169			ret = SMBC_SMF_SYSTEM_ERR;
170	}
171	free(instance);
172	return (ret);
173}
174
175/*
176 * Delete a specified instance. Return SMBC_SMF_OK for success.
177 */
178int
179smb_smf_instance_delete(smb_scfhandle_t *handle, char *inst_name)
180{
181	int ret = SMBC_SMF_OK;
182
183	if (handle == NULL) {
184		return (SMBC_SMF_SYSTEM_ERR);
185	}
186
187	handle->scf_instance = scf_instance_create(handle->scf_handle);
188	if (scf_service_get_instance(handle->scf_service, inst_name,
189	    handle->scf_instance) == SCF_SUCCESS) {
190		if (scf_instance_delete(handle->scf_instance) == SCF_SUCCESS) {
191			return (ret);
192		} else {
193			ret = SMBC_SMF_SYSTEM_ERR;
194		}
195	} else {
196		smb_smf_scf_log_error(NULL);
197		ret = SMBC_SMF_SYSTEM_ERR;
198	}
199	return (ret);
200}
201
202/*
203 * smb_smf_scf_init()
204 *
205 * must be called before using any of the SCF functions.
206 * Returns smb_scfhandle_t pointer if success.
207 */
208smb_scfhandle_t *
209smb_smf_scf_init(char *svc_name)
210{
211	smb_scfhandle_t *handle;
212
213	handle = malloc(sizeof (smb_scfhandle_t));
214	if (handle != NULL) {
215		bzero((char *)handle, sizeof (smb_scfhandle_t));
216		handle->scf_state = SCH_STATE_INITIALIZING;
217		handle->scf_handle = scf_handle_create(SCF_VERSION);
218		if (handle->scf_handle != NULL) {
219			if (scf_handle_bind(handle->scf_handle) == 0) {
220				handle->scf_scope =
221				    scf_scope_create(handle->scf_handle);
222				if (scf_handle_get_local_scope(
223				    handle->scf_handle, handle->scf_scope) != 0)
224					goto err;
225
226				handle->scf_service =
227				    scf_service_create(handle->scf_handle);
228
229				if (scf_scope_get_service(handle->scf_scope,
230				    svc_name, handle->scf_service)
231				    != SCF_SUCCESS) {
232					goto err;
233				}
234				handle->scf_pg =
235				    scf_pg_create(handle->scf_handle);
236				handle->scf_state = SCH_STATE_INIT;
237			} else {
238				goto err;
239			}
240		} else {
241			free(handle);
242			handle = NULL;
243			smb_smf_scf_log_error("Could not access SMF "
244			    "repository: %s\n");
245		}
246	}
247	return (handle);
248
249	/* error handling/unwinding */
250err:
251	(void) smb_smf_scf_fini(handle);
252	(void) smb_smf_scf_log_error("SMF initialization problem: %s\n");
253	return (NULL);
254}
255
256/*
257 * smb_smf_create_service_pgroup(handle, pgroup)
258 *
259 * create a new property group at service level.
260 */
261int
262smb_smf_create_service_pgroup(smb_scfhandle_t *handle, char *pgroup)
263{
264	int ret = SMBC_SMF_OK;
265	int err;
266
267	if (handle == NULL) {
268		return (SMBC_SMF_SYSTEM_ERR);
269	}
270
271	/*
272	 * only create a handle if it doesn't exist. It is ok to exist
273	 * since the pg handle will be set as a side effect.
274	 */
275	if (handle->scf_pg == NULL) {
276		handle->scf_pg = scf_pg_create(handle->scf_handle);
277	}
278	/*
279	 * if the pgroup exists, we are done. If it doesn't, then we
280	 * need to actually add one to the service instance.
281	 */
282	if (scf_service_get_pg(handle->scf_service,
283	    pgroup, handle->scf_pg) != 0) {
284		/* doesn't exist so create one */
285		if (scf_service_add_pg(handle->scf_service, pgroup,
286		    SCF_GROUP_FRAMEWORK, 0, handle->scf_pg) != 0) {
287			err = scf_error();
288			if (err != SCF_ERROR_NONE)
289				smb_smf_scf_log_error(NULL);
290			switch (err) {
291			case SCF_ERROR_PERMISSION_DENIED:
292				ret = SMBC_SMF_NO_PERMISSION;
293				break;
294			default:
295				ret = SMBC_SMF_SYSTEM_ERR;
296				break;
297			}
298		}
299	}
300	return (ret);
301}
302
303/*
304 * smb_smf_create_instance_pgroup(handle, pgroup)
305 *
306 * create a new property group at instance level.
307 */
308int
309smb_smf_create_instance_pgroup(smb_scfhandle_t *handle, char *pgroup)
310{
311	int ret = SMBC_SMF_OK;
312	int err;
313
314	if (handle == NULL) {
315		return (SMBC_SMF_SYSTEM_ERR);
316	}
317
318	/*
319	 * only create a handle if it doesn't exist. It is ok to exist
320	 * since the pg handle will be set as a side effect.
321	 */
322	if (handle->scf_pg == NULL) {
323		handle->scf_pg = scf_pg_create(handle->scf_handle);
324	}
325
326	/*
327	 * if the pgroup exists, we are done. If it doesn't, then we
328	 * need to actually add one to the service instance.
329	 */
330	if (scf_instance_get_pg(handle->scf_instance,
331	    pgroup, handle->scf_pg) != 0) {
332		/* doesn't exist so create one */
333		if (scf_instance_add_pg(handle->scf_instance, pgroup,
334		    SCF_GROUP_APPLICATION, 0, handle->scf_pg) != 0) {
335			err = scf_error();
336			if (err != SCF_ERROR_NONE)
337				smb_smf_scf_log_error(NULL);
338			switch (err) {
339			case SCF_ERROR_PERMISSION_DENIED:
340				ret = SMBC_SMF_NO_PERMISSION;
341				break;
342			default:
343				ret = SMBC_SMF_SYSTEM_ERR;
344				break;
345			}
346		}
347	}
348	return (ret);
349}
350
351/*
352 * smb_smf_delete_service_pgroup(handle, pgroup)
353 *
354 * remove the property group from the current service.
355 * but only if it actually exists.
356 */
357int
358smb_smf_delete_service_pgroup(smb_scfhandle_t *handle, char *pgroup)
359{
360	int ret = SMBC_SMF_OK;
361	int err;
362
363	if (handle == NULL) {
364		return (SMBC_SMF_SYSTEM_ERR);
365	}
366
367	/*
368	 * only create a handle if it doesn't exist. It is ok to exist
369	 * since the pg handle will be set as a side effect.
370	 */
371	if (handle->scf_pg == NULL) {
372		handle->scf_pg = scf_pg_create(handle->scf_handle);
373	}
374
375	/*
376	 * only delete if it does exist.
377	 */
378	if (scf_service_get_pg(handle->scf_service,
379	    pgroup, handle->scf_pg) == 0) {
380		/* does exist so delete it */
381		if (scf_pg_delete(handle->scf_pg) != 0) {
382			ret = SMBC_SMF_SYSTEM_ERR;
383			err = scf_error();
384			if (err != SCF_ERROR_NONE) {
385				smb_smf_scf_log_error("SMF delpg "
386				    "problem: %s\n");
387			}
388		}
389	} else {
390		err = scf_error();
391		if (err != SCF_ERROR_NONE)
392			smb_smf_scf_log_error("SMF getpg problem: %s\n");
393		ret = SMBC_SMF_SYSTEM_ERR;
394	}
395	if (ret == SMBC_SMF_SYSTEM_ERR &&
396	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
397		ret = SMBC_SMF_NO_PERMISSION;
398	}
399	return (ret);
400}
401
402/*
403 * smb_smf_delete_instance_pgroup(handle, pgroup)
404 *
405 * remove the property group from the current instance.
406 * but only if it actually exists.
407 */
408int
409smb_smf_delete_instance_pgroup(smb_scfhandle_t *handle, char *pgroup)
410{
411	int ret = SMBC_SMF_OK;
412	int err;
413
414	if (handle == NULL) {
415		return (SMBC_SMF_SYSTEM_ERR);
416	}
417
418	/*
419	 * only create a handle if it doesn't exist. It is ok to exist
420	 * since the pg handle will be set as a side effect.
421	 */
422	if (handle->scf_pg == NULL) {
423		handle->scf_pg = scf_pg_create(handle->scf_handle);
424	}
425
426	/*
427	 * only delete if it does exist.
428	 */
429	if (scf_instance_get_pg(handle->scf_instance,
430	    pgroup, handle->scf_pg) == 0) {
431		/* does exist so delete it */
432		if (scf_pg_delete(handle->scf_pg) != 0) {
433			ret = SMBC_SMF_SYSTEM_ERR;
434			err = scf_error();
435			if (err != SCF_ERROR_NONE) {
436				smb_smf_scf_log_error("SMF delpg "
437				    "problem: %s\n");
438			}
439		}
440	} else {
441		err = scf_error();
442		if (err != SCF_ERROR_NONE)
443			smb_smf_scf_log_error("SMF getpg problem: %s\n");
444		ret = SMBC_SMF_SYSTEM_ERR;
445	}
446	if (ret == SMBC_SMF_SYSTEM_ERR &&
447	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
448		ret = SMBC_SMF_NO_PERMISSION;
449	}
450	return (ret);
451}
452
453/*
454 * Start transaction on current pg in handle.
455 * The pg could be service or instance level.
456 * Must be called after pg handle is obtained
457 * from create or get.
458 */
459int
460smb_smf_start_transaction(smb_scfhandle_t *handle)
461{
462	int ret = SMBC_SMF_OK;
463
464	if (!handle || (!handle->scf_pg)) {
465		return (SMBC_SMF_SYSTEM_ERR);
466	}
467	/*
468	 * lookup the property group and create it if it doesn't already
469	 * exist.
470	 */
471	if (handle->scf_state == SCH_STATE_INIT) {
472		if (ret == SMBC_SMF_OK) {
473			handle->scf_trans =
474			    scf_transaction_create(handle->scf_handle);
475			if (handle->scf_trans != NULL) {
476				if (scf_transaction_start(handle->scf_trans,
477				    handle->scf_pg) != 0) {
478					ret = SMBC_SMF_SYSTEM_ERR;
479					scf_transaction_destroy(
480					    handle->scf_trans);
481					handle->scf_trans = NULL;
482				}
483			} else {
484				ret = SMBC_SMF_SYSTEM_ERR;
485			}
486		}
487	}
488	if (ret == SMBC_SMF_SYSTEM_ERR &&
489	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
490		ret = SMBC_SMF_NO_PERMISSION;
491	}
492	return (ret);
493}
494
495/*
496 * smb_smf_end_transaction(handle)
497 *
498 * Commit the changes that were added to the transaction in the
499 * handle. Do all necessary cleanup.
500 */
501int
502smb_smf_end_transaction(smb_scfhandle_t *handle)
503{
504	int ret = SMBC_SMF_OK;
505
506	if (handle == NULL) {
507		return (SMBC_SMF_SYSTEM_ERR);
508	}
509
510	if (handle->scf_trans == NULL) {
511		ret = SMBC_SMF_SYSTEM_ERR;
512	} else {
513		if (scf_transaction_commit(handle->scf_trans) < 0) {
514			ret = SMBC_SMF_SYSTEM_ERR;
515			smb_smf_scf_log_error("Failed to commit "
516			    "transaction: %s");
517		}
518		scf_transaction_destroy_children(handle->scf_trans);
519		scf_transaction_destroy(handle->scf_trans);
520		handle->scf_trans = NULL;
521	}
522	return (ret);
523}
524
525/*
526 * Deletes property in current pg
527 */
528int
529smb_smf_delete_property(smb_scfhandle_t *handle, char *propname)
530{
531	int ret = SMBC_SMF_OK;
532	scf_transaction_entry_t *entry = NULL;
533
534	if (handle == NULL) {
535		return (SMBC_SMF_SYSTEM_ERR);
536	}
537
538	/*
539	 * properties must be set in transactions and don't take
540	 * effect until the transaction has been ended/committed.
541	 */
542	entry = scf_entry_create(handle->scf_handle);
543	if (entry != NULL) {
544		if (scf_transaction_property_delete(handle->scf_trans, entry,
545		    propname) != 0) {
546			ret = SMBC_SMF_SYSTEM_ERR;
547		}
548	} else {
549		ret = SMBC_SMF_SYSTEM_ERR;
550	}
551	if (ret == SMBC_SMF_SYSTEM_ERR) {
552		switch (scf_error()) {
553		case SCF_ERROR_PERMISSION_DENIED:
554			ret = SMBC_SMF_NO_PERMISSION;
555			break;
556		}
557	}
558
559	/*
560	 * cleanup if there were any errors that didn't leave these
561	 * values where they would be cleaned up later.
562	 */
563	if ((ret != SMBC_SMF_OK) && (entry != NULL)) {
564		scf_entry_destroy(entry);
565	}
566	return (ret);
567}
568
569/*
570 * Sets string property in current pg
571 */
572int
573smb_smf_set_string_property(smb_scfhandle_t *handle,
574    char *propname, char *valstr)
575{
576	int ret = SMBC_SMF_OK;
577	scf_value_t *value = NULL;
578	scf_transaction_entry_t *entry = NULL;
579
580	if (handle == NULL) {
581		return (SMBC_SMF_SYSTEM_ERR);
582	}
583
584	/*
585	 * properties must be set in transactions and don't take
586	 * effect until the transaction has been ended/committed.
587	 */
588	value = scf_value_create(handle->scf_handle);
589	entry = scf_entry_create(handle->scf_handle);
590	if (value != NULL && entry != NULL) {
591		if (scf_transaction_property_change(handle->scf_trans, entry,
592		    propname, SCF_TYPE_ASTRING) == 0 ||
593		    scf_transaction_property_new(handle->scf_trans, entry,
594		    propname, SCF_TYPE_ASTRING) == 0) {
595			if (scf_value_set_astring(value, valstr) == 0) {
596				if (scf_entry_add_value(entry, value) != 0) {
597					ret = SMBC_SMF_SYSTEM_ERR;
598					scf_value_destroy(value);
599				}
600				/* the value is in the transaction */
601				value = NULL;
602			} else {
603				/* value couldn't be constructed */
604				ret = SMBC_SMF_SYSTEM_ERR;
605			}
606			/* the entry is in the transaction */
607			entry = NULL;
608		} else {
609			ret = SMBC_SMF_SYSTEM_ERR;
610		}
611	} else {
612		ret = SMBC_SMF_SYSTEM_ERR;
613	}
614	if (ret == SMBC_SMF_SYSTEM_ERR) {
615		switch (scf_error()) {
616		case SCF_ERROR_PERMISSION_DENIED:
617			ret = SMBC_SMF_NO_PERMISSION;
618			break;
619		}
620	}
621
622	/*
623	 * cleanup if there were any errors that didn't leave these
624	 * values where they would be cleaned up later.
625	 */
626	if (value != NULL)
627		scf_value_destroy(value);
628	if (entry != NULL)
629		scf_entry_destroy(entry);
630	return (ret);
631}
632
633/*
634 * Gets string property value.upto sz size.
635 * Caller is responsible to have enough memory allocated.
636 */
637int
638smb_smf_get_string_property(smb_scfhandle_t *handle, char *propname,
639    char *valstr, size_t sz)
640{
641	int ret = SMBC_SMF_OK;
642	scf_value_t *value;
643	scf_property_t *prop;
644
645	if (handle == NULL) {
646		return (SMBC_SMF_SYSTEM_ERR);
647	}
648
649	value = scf_value_create(handle->scf_handle);
650	prop = scf_property_create(handle->scf_handle);
651	if (value && prop &&
652	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
653		if (scf_property_get_value(prop, value) == 0) {
654			if (scf_value_get_astring(value, valstr, sz) < 0) {
655				ret = SMBC_SMF_SYSTEM_ERR;
656			}
657		} else {
658			ret = SMBC_SMF_SYSTEM_ERR;
659		}
660	} else {
661		ret = SMBC_SMF_SYSTEM_ERR;
662	}
663	if (value != NULL)
664		scf_value_destroy(value);
665	if (prop != NULL)
666		scf_property_destroy(prop);
667	return (ret);
668}
669
670/*
671 * Get integer value of property.
672 * The value is returned as int64_t value
673 * Caller ensures appropriate translation.
674 */
675int
676smb_smf_set_integer_property(smb_scfhandle_t *handle, char *propname,
677    int64_t valint)
678{
679	int ret = SMBC_SMF_OK;
680	scf_value_t *value = NULL;
681	scf_transaction_entry_t *entry = NULL;
682
683	if (handle == NULL) {
684		return (SMBC_SMF_SYSTEM_ERR);
685	}
686
687	/*
688	 * properties must be set in transactions and don't take
689	 * effect until the transaction has been ended/committed.
690	 */
691	value = scf_value_create(handle->scf_handle);
692	entry = scf_entry_create(handle->scf_handle);
693	if (value != NULL && entry != NULL) {
694		if (scf_transaction_property_change(handle->scf_trans, entry,
695		    propname, SCF_TYPE_INTEGER) == 0 ||
696		    scf_transaction_property_new(handle->scf_trans, entry,
697		    propname, SCF_TYPE_INTEGER) == 0) {
698			scf_value_set_integer(value, valint);
699			if (scf_entry_add_value(entry, value) != 0) {
700				ret = SMBC_SMF_SYSTEM_ERR;
701				scf_value_destroy(value);
702			}
703			/* the value is in the transaction */
704			value = NULL;
705		}
706		/* the entry is in the transaction */
707		entry = NULL;
708	} else {
709		ret = SMBC_SMF_SYSTEM_ERR;
710	}
711	if (ret == SMBC_SMF_SYSTEM_ERR) {
712		switch (scf_error()) {
713		case SCF_ERROR_PERMISSION_DENIED:
714			ret = SMBC_SMF_NO_PERMISSION;
715			break;
716		}
717	}
718	/*
719	 * cleanup if there were any errors that didn't leave these
720	 * values where they would be cleaned up later.
721	 */
722	if (value != NULL)
723		scf_value_destroy(value);
724	if (entry != NULL)
725		scf_entry_destroy(entry);
726	return (ret);
727}
728
729/*
730 * Sets integer property value.
731 * Caller is responsible to have enough memory allocated.
732 */
733int
734smb_smf_get_integer_property(smb_scfhandle_t *handle, char *propname,
735    int64_t *valint)
736{
737	int ret = SMBC_SMF_OK;
738	scf_value_t *value = NULL;
739	scf_property_t *prop = NULL;
740
741	if (handle == NULL) {
742		return (SMBC_SMF_SYSTEM_ERR);
743	}
744
745	value = scf_value_create(handle->scf_handle);
746	prop = scf_property_create(handle->scf_handle);
747	if ((prop) && (value) &&
748	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
749		if (scf_property_get_value(prop, value) == 0) {
750			if (scf_value_get_integer(value,
751			    valint) != 0) {
752				ret = SMBC_SMF_SYSTEM_ERR;
753			}
754		} else {
755			ret = SMBC_SMF_SYSTEM_ERR;
756		}
757	} else {
758		ret = SMBC_SMF_SYSTEM_ERR;
759	}
760	if (value != NULL)
761		scf_value_destroy(value);
762	if (prop != NULL)
763		scf_property_destroy(prop);
764	return (ret);
765}
766
767/*
768 * Get boolean value of property.
769 * The value is returned as int64_t value
770 * Caller ensures appropriate translation.
771 */
772int
773smb_smf_set_boolean_property(smb_scfhandle_t *handle, char *propname,
774    uint8_t valbool)
775{
776	int ret = SMBC_SMF_OK;
777	scf_value_t *value = NULL;
778	scf_transaction_entry_t *entry = NULL;
779
780	if (handle == NULL) {
781		return (SMBC_SMF_SYSTEM_ERR);
782	}
783
784	/*
785	 * properties must be set in transactions and don't take
786	 * effect until the transaction has been ended/committed.
787	 */
788	value = scf_value_create(handle->scf_handle);
789	entry = scf_entry_create(handle->scf_handle);
790	if (value != NULL && entry != NULL) {
791		if (scf_transaction_property_change(handle->scf_trans, entry,
792		    propname, SCF_TYPE_BOOLEAN) == 0 ||
793		    scf_transaction_property_new(handle->scf_trans, entry,
794		    propname, SCF_TYPE_BOOLEAN) == 0) {
795			scf_value_set_boolean(value, valbool);
796			if (scf_entry_add_value(entry, value) != 0) {
797				ret = SMBC_SMF_SYSTEM_ERR;
798				scf_value_destroy(value);
799			}
800			/* the value is in the transaction */
801			value = NULL;
802		}
803		/* the entry is in the transaction */
804		entry = NULL;
805	} else {
806		ret = SMBC_SMF_SYSTEM_ERR;
807	}
808	if (ret == SMBC_SMF_SYSTEM_ERR) {
809		switch (scf_error()) {
810		case SCF_ERROR_PERMISSION_DENIED:
811			ret = SMBC_SMF_NO_PERMISSION;
812			break;
813		}
814	}
815	/*
816	 * cleanup if there were any errors that didn't leave these
817	 * values where they would be cleaned up later.
818	 */
819	if (value != NULL)
820		scf_value_destroy(value);
821	if (entry != NULL)
822		scf_entry_destroy(entry);
823	return (ret);
824}
825
826/*
827 * Sets boolean property value.
828 * Caller is responsible to have enough memory allocated.
829 */
830int
831smb_smf_get_boolean_property(smb_scfhandle_t *handle, char *propname,
832    uint8_t *valbool)
833{
834	int ret = SMBC_SMF_OK;
835	scf_value_t *value = NULL;
836	scf_property_t *prop = NULL;
837
838	if (handle == NULL) {
839		return (SMBC_SMF_SYSTEM_ERR);
840	}
841
842	value = scf_value_create(handle->scf_handle);
843	prop = scf_property_create(handle->scf_handle);
844	if ((prop) && (value) &&
845	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
846		if (scf_property_get_value(prop, value) == 0) {
847			if (scf_value_get_boolean(value,
848			    valbool) != 0) {
849				ret = SMBC_SMF_SYSTEM_ERR;
850			}
851		} else {
852			ret = SMBC_SMF_SYSTEM_ERR;
853		}
854	} else {
855		ret = SMBC_SMF_SYSTEM_ERR;
856	}
857	if (value != NULL)
858		scf_value_destroy(value);
859	if (prop != NULL)
860		scf_property_destroy(prop);
861	return (ret);
862}
863
864/*
865 * Sets a blob property value.
866 */
867int
868smb_smf_set_opaque_property(smb_scfhandle_t *handle, char *propname,
869    void *voidval, size_t sz)
870{
871	int ret = SMBC_SMF_OK;
872	scf_value_t *value;
873	scf_transaction_entry_t *entry;
874
875	if (handle == NULL) {
876		return (SMBC_SMF_SYSTEM_ERR);
877	}
878
879	/*
880	 * properties must be set in transactions and don't take
881	 * effect until the transaction has been ended/committed.
882	 */
883	value = scf_value_create(handle->scf_handle);
884	entry = scf_entry_create(handle->scf_handle);
885	if (value != NULL && entry != NULL) {
886		if (scf_transaction_property_change(handle->scf_trans, entry,
887		    propname, SCF_TYPE_OPAQUE) == 0 ||
888		    scf_transaction_property_new(handle->scf_trans, entry,
889		    propname, SCF_TYPE_OPAQUE) == 0) {
890			if (scf_value_set_opaque(value, voidval, sz) == 0) {
891				if (scf_entry_add_value(entry, value) != 0) {
892					ret = SMBC_SMF_SYSTEM_ERR;
893					scf_value_destroy(value);
894				}
895				/* the value is in the transaction */
896				value = NULL;
897			} else {
898				/* value couldn't be constructed */
899				ret = SMBC_SMF_SYSTEM_ERR;
900			}
901			/* the entry is in the transaction */
902			entry = NULL;
903		} else {
904			ret = SMBC_SMF_SYSTEM_ERR;
905		}
906	} else {
907		ret = SMBC_SMF_SYSTEM_ERR;
908	}
909	if (ret == SMBC_SMF_SYSTEM_ERR) {
910		switch (scf_error()) {
911		case SCF_ERROR_PERMISSION_DENIED:
912			ret = SMBC_SMF_NO_PERMISSION;
913			break;
914		}
915	}
916	/*
917	 * cleanup if there were any errors that didn't leave these
918	 * values where they would be cleaned up later.
919	 */
920	if (value != NULL)
921		scf_value_destroy(value);
922	if (entry != NULL)
923		scf_entry_destroy(entry);
924	return (ret);
925}
926
927/*
928 * Gets a blob property value.
929 * Caller is responsible to have enough memory allocated.
930 */
931int
932smb_smf_get_opaque_property(smb_scfhandle_t *handle, char *propname,
933    void *v, size_t sz)
934{
935	int ret = SMBC_SMF_OK;
936	scf_value_t *value = NULL;
937	scf_property_t *prop = NULL;
938
939	if (handle == NULL) {
940		return (SMBC_SMF_SYSTEM_ERR);
941	}
942
943	value = scf_value_create(handle->scf_handle);
944	prop = scf_property_create(handle->scf_handle);
945	if ((prop) && (value) &&
946	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
947		if (scf_property_get_value(prop, value) == 0) {
948			if (scf_value_get_opaque(value, (char *)v, sz) != sz) {
949				ret = SMBC_SMF_SYSTEM_ERR;
950			}
951		} else {
952			ret = SMBC_SMF_SYSTEM_ERR;
953		}
954	} else {
955		ret = SMBC_SMF_SYSTEM_ERR;
956	}
957	if (value != NULL)
958		scf_value_destroy(value);
959	if (prop != NULL)
960		scf_property_destroy(prop);
961	return (ret);
962}
963
964/*
965 * Gets an instance iterator for the service specified.
966 */
967smb_scfhandle_t *
968smb_smf_get_iterator(char *svc_name)
969{
970	smb_scfhandle_t *handle = NULL;
971
972	handle = smb_smf_scf_init(svc_name);
973	if (!handle) {
974		return (NULL);
975	}
976
977	handle->scf_inst_iter = scf_iter_create(handle->scf_handle);
978	if (handle->scf_inst_iter) {
979		if (scf_iter_service_instances(handle->scf_inst_iter,
980		    handle->scf_service) != 0) {
981			smb_smf_scf_fini(handle);
982			handle = NULL;
983		} else {
984			handle->scf_instance = NULL;
985		}
986	} else {
987		smb_smf_scf_fini(handle);
988		handle = NULL;
989	}
990	return (handle);
991}
992