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