xref: /illumos-gate/usr/src/lib/libshare/smbfs/smbfs_scfutil.c (revision 4bff34e37def8a90f9194d81bc345c52ba20086a)
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  */
50 static void
51 smb_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  */
68 void
69 smb_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  */
114 int
115 smb_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  */
136 int
137 smb_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  */
178 int
179 smb_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  */
208 smb_scfhandle_t *
209 smb_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 */
250 err:
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  */
261 int
262 smb_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  */
308 int
309 smb_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  */
357 int
358 smb_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  */
408 int
409 smb_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  */
459 int
460 smb_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  */
501 int
502 smb_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  */
528 int
529 smb_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  */
572 int
573 smb_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  */
637 int
638 smb_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  */
675 int
676 smb_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  */
733 int
734 smb_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  */
772 int
773 smb_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  */
830 int
831 smb_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  */
867 int
868 smb_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  */
931 int
932 smb_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  */
967 smb_scfhandle_t *
968 smb_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