xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c (revision 5d9d9091f564c198a760790b0bfa72c44e17912b)
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 2022 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 		switch (scf_error()) {
232 		case SCF_ERROR_PERMISSION_DENIED:
233 			ret = SMBD_SMF_NO_PERMISSION;
234 			break;
235 		}
236 	}
237 
238 	/*
239 	 * cleanup if there were any errors that didn't leave these
240 	 * values where they would be cleaned up later.
241 	 */
242 	if (value != NULL)
243 		scf_value_destroy(value);
244 	if (entry != NULL)
245 		scf_entry_destroy(entry);
246 	return (ret);
247 }
248 
249 /*
250  * Gets string property value.upto sz size.
251  * Caller is responsible to have enough memory allocated.
252  */
253 int
254 smb_smf_get_string_property(smb_scfhandle_t *handle, char *propname,
255     char *valstr, size_t sz)
256 {
257 	int ret = SMBD_SMF_OK;
258 	scf_value_t *value;
259 	scf_property_t *prop;
260 
261 	if (handle == NULL)
262 		return (SMBD_SMF_SYSTEM_ERR);
263 
264 	value = scf_value_create(handle->scf_handle);
265 	prop = scf_property_create(handle->scf_handle);
266 	if (value && prop &&
267 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
268 		if (scf_property_get_value(prop, value) == 0) {
269 			if (scf_value_get_astring(value, valstr, sz) < 0) {
270 				ret = SMBD_SMF_SYSTEM_ERR;
271 			}
272 		} else {
273 			ret = SMBD_SMF_SYSTEM_ERR;
274 		}
275 	} else {
276 		ret = SMBD_SMF_SYSTEM_ERR;
277 	}
278 	if (value != NULL)
279 		scf_value_destroy(value);
280 	if (prop != NULL)
281 		scf_property_destroy(prop);
282 	return (ret);
283 }
284 
285 /*
286  * Set integer value of property.
287  * The value is returned as int64_t value
288  * Caller ensures appropriate translation.
289  */
290 int
291 smb_smf_set_integer_property(smb_scfhandle_t *handle, char *propname,
292     int64_t valint)
293 {
294 	int ret = SMBD_SMF_OK;
295 	scf_value_t *value = NULL;
296 	scf_transaction_entry_t *entry = NULL;
297 
298 	if (handle == NULL)
299 		return (SMBD_SMF_SYSTEM_ERR);
300 
301 	/*
302 	 * properties must be set in transactions and don't take
303 	 * effect until the transaction has been ended/committed.
304 	 */
305 	value = scf_value_create(handle->scf_handle);
306 	entry = scf_entry_create(handle->scf_handle);
307 	if (value != NULL && entry != NULL) {
308 		if (scf_transaction_property_change(handle->scf_trans, entry,
309 		    propname, SCF_TYPE_INTEGER) == 0 ||
310 		    scf_transaction_property_new(handle->scf_trans, entry,
311 		    propname, SCF_TYPE_INTEGER) == 0) {
312 			scf_value_set_integer(value, valint);
313 			if (scf_entry_add_value(entry, value) != 0) {
314 				ret = SMBD_SMF_SYSTEM_ERR;
315 				scf_value_destroy(value);
316 			}
317 			/* the value is in the transaction */
318 			value = NULL;
319 		}
320 		/* the entry is in the transaction */
321 		entry = NULL;
322 	} else {
323 		ret = SMBD_SMF_SYSTEM_ERR;
324 	}
325 	if (ret == SMBD_SMF_SYSTEM_ERR) {
326 		switch (scf_error()) {
327 		case SCF_ERROR_PERMISSION_DENIED:
328 			ret = SMBD_SMF_NO_PERMISSION;
329 			break;
330 		}
331 	}
332 	/*
333 	 * cleanup if there were any errors that didn't leave these
334 	 * values where they would be cleaned up later.
335 	 */
336 	if (value != NULL)
337 		scf_value_destroy(value);
338 	if (entry != NULL)
339 		scf_entry_destroy(entry);
340 	return (ret);
341 }
342 
343 /*
344  * Gets integer property value.
345  * Caller is responsible to have enough memory allocated.
346  */
347 int
348 smb_smf_get_integer_property(smb_scfhandle_t *handle, char *propname,
349     int64_t *valint)
350 {
351 	int ret = SMBD_SMF_OK;
352 	scf_value_t *value = NULL;
353 	scf_property_t *prop = NULL;
354 
355 	if (handle == NULL)
356 		return (SMBD_SMF_SYSTEM_ERR);
357 
358 	value = scf_value_create(handle->scf_handle);
359 	prop = scf_property_create(handle->scf_handle);
360 	if ((prop) && (value) &&
361 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
362 		if (scf_property_get_value(prop, value) == 0) {
363 			if (scf_value_get_integer(value,
364 			    valint) != 0) {
365 				ret = SMBD_SMF_SYSTEM_ERR;
366 			}
367 		} else {
368 			ret = SMBD_SMF_SYSTEM_ERR;
369 		}
370 	} else {
371 		ret = SMBD_SMF_SYSTEM_ERR;
372 	}
373 	if (value != NULL)
374 		scf_value_destroy(value);
375 	if (prop != NULL)
376 		scf_property_destroy(prop);
377 	return (ret);
378 }
379 
380 /*
381  * Set boolean value of property.
382  * The value is returned as int64_t value
383  * Caller ensures appropriate translation.
384  */
385 int
386 smb_smf_set_boolean_property(smb_scfhandle_t *handle, char *propname,
387     uint8_t valbool)
388 {
389 	int ret = SMBD_SMF_OK;
390 	scf_value_t *value = NULL;
391 	scf_transaction_entry_t *entry = NULL;
392 
393 	if (handle == NULL)
394 		return (SMBD_SMF_SYSTEM_ERR);
395 
396 	/*
397 	 * properties must be set in transactions and don't take
398 	 * effect until the transaction has been ended/committed.
399 	 */
400 	value = scf_value_create(handle->scf_handle);
401 	entry = scf_entry_create(handle->scf_handle);
402 	if (value != NULL && entry != NULL) {
403 		if (scf_transaction_property_change(handle->scf_trans, entry,
404 		    propname, SCF_TYPE_BOOLEAN) == 0 ||
405 		    scf_transaction_property_new(handle->scf_trans, entry,
406 		    propname, SCF_TYPE_BOOLEAN) == 0) {
407 			scf_value_set_boolean(value, valbool);
408 			if (scf_entry_add_value(entry, value) != 0) {
409 				ret = SMBD_SMF_SYSTEM_ERR;
410 				scf_value_destroy(value);
411 			}
412 			/* the value is in the transaction */
413 			value = NULL;
414 		}
415 		/* the entry is in the transaction */
416 		entry = NULL;
417 	} else {
418 		ret = SMBD_SMF_SYSTEM_ERR;
419 	}
420 	if (ret == SMBD_SMF_SYSTEM_ERR) {
421 		switch (scf_error()) {
422 		case SCF_ERROR_PERMISSION_DENIED:
423 			ret = SMBD_SMF_NO_PERMISSION;
424 			break;
425 		}
426 	}
427 	/*
428 	 * cleanup if there were any errors that didn't leave these
429 	 * values where they would be cleaned up later.
430 	 */
431 	if (value != NULL)
432 		scf_value_destroy(value);
433 	if (entry != NULL)
434 		scf_entry_destroy(entry);
435 	return (ret);
436 }
437 
438 /*
439  * Gets boolean property value.
440  * Caller is responsible to have enough memory allocated.
441  */
442 int
443 smb_smf_get_boolean_property(smb_scfhandle_t *handle, char *propname,
444     uint8_t *valbool)
445 {
446 	int ret = SMBD_SMF_OK;
447 	scf_value_t *value = NULL;
448 	scf_property_t *prop = NULL;
449 
450 	if (handle == NULL)
451 		return (SMBD_SMF_SYSTEM_ERR);
452 
453 	value = scf_value_create(handle->scf_handle);
454 	prop = scf_property_create(handle->scf_handle);
455 	if ((prop) && (value) &&
456 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
457 		if (scf_property_get_value(prop, value) == 0) {
458 			if (scf_value_get_boolean(value,
459 			    valbool) != 0) {
460 				ret = SMBD_SMF_SYSTEM_ERR;
461 			}
462 		} else {
463 			ret = SMBD_SMF_SYSTEM_ERR;
464 		}
465 	} else {
466 		ret = SMBD_SMF_SYSTEM_ERR;
467 	}
468 	if (value != NULL)
469 		scf_value_destroy(value);
470 	if (prop != NULL)
471 		scf_property_destroy(prop);
472 	return (ret);
473 }
474 
475 /*
476  * Sets a blob property value.
477  */
478 int
479 smb_smf_set_opaque_property(smb_scfhandle_t *handle, char *propname,
480     void *voidval, size_t sz)
481 {
482 	int ret = SMBD_SMF_OK;
483 	scf_value_t *value;
484 	scf_transaction_entry_t *entry;
485 
486 	if (handle == NULL)
487 		return (SMBD_SMF_SYSTEM_ERR);
488 
489 	/*
490 	 * properties must be set in transactions and don't take
491 	 * effect until the transaction has been ended/committed.
492 	 */
493 	value = scf_value_create(handle->scf_handle);
494 	entry = scf_entry_create(handle->scf_handle);
495 	if (value != NULL && entry != NULL) {
496 		if (scf_transaction_property_change(handle->scf_trans, entry,
497 		    propname, SCF_TYPE_OPAQUE) == 0 ||
498 		    scf_transaction_property_new(handle->scf_trans, entry,
499 		    propname, SCF_TYPE_OPAQUE) == 0) {
500 			if (scf_value_set_opaque(value, voidval, sz) == 0) {
501 				if (scf_entry_add_value(entry, value) != 0) {
502 					ret = SMBD_SMF_SYSTEM_ERR;
503 					scf_value_destroy(value);
504 				}
505 				/* the value is in the transaction */
506 				value = NULL;
507 			} else {
508 				/* value couldn't be constructed */
509 				ret = SMBD_SMF_SYSTEM_ERR;
510 			}
511 			/* the entry is in the transaction */
512 			entry = NULL;
513 		} else {
514 			ret = SMBD_SMF_SYSTEM_ERR;
515 		}
516 	} else {
517 		ret = SMBD_SMF_SYSTEM_ERR;
518 	}
519 	if (ret == SMBD_SMF_SYSTEM_ERR) {
520 		switch (scf_error()) {
521 		case SCF_ERROR_PERMISSION_DENIED:
522 			ret = SMBD_SMF_NO_PERMISSION;
523 			break;
524 		}
525 	}
526 	/*
527 	 * cleanup if there were any errors that didn't leave these
528 	 * values where they would be cleaned up later.
529 	 */
530 	if (value != NULL)
531 		scf_value_destroy(value);
532 	if (entry != NULL)
533 		scf_entry_destroy(entry);
534 	return (ret);
535 }
536 
537 /*
538  * Gets a blob property value.
539  * Caller is responsible to have enough memory allocated.
540  */
541 int
542 smb_smf_get_opaque_property(smb_scfhandle_t *handle, char *propname,
543     void *v, size_t sz)
544 {
545 	int ret = SMBD_SMF_OK;
546 	scf_value_t *value = NULL;
547 	scf_property_t *prop = NULL;
548 
549 	if (handle == NULL)
550 		return (SMBD_SMF_SYSTEM_ERR);
551 
552 	value = scf_value_create(handle->scf_handle);
553 	prop = scf_property_create(handle->scf_handle);
554 	if ((prop) && (value) &&
555 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
556 		if (scf_property_get_value(prop, value) == 0) {
557 			if (scf_value_get_opaque(value, (char *)v, sz) != sz) {
558 				ret = SMBD_SMF_SYSTEM_ERR;
559 			}
560 		} else {
561 			ret = SMBD_SMF_SYSTEM_ERR;
562 		}
563 	} else {
564 		ret = SMBD_SMF_SYSTEM_ERR;
565 	}
566 	if (value != NULL)
567 		scf_value_destroy(value);
568 	if (prop != NULL)
569 		scf_property_destroy(prop);
570 	return (ret);
571 }
572 
573 /*
574  * Delete a property (for properties obsoleted during an upgrade).
575  */
576 int
577 smb_smf_delete_property(smb_scfhandle_t *handle, char *propname)
578 {
579 	scf_transaction_entry_t *entry;
580 	int ret = SMBD_SMF_OK;
581 
582 	if (handle == NULL)
583 		return (SMBD_SMF_SYSTEM_ERR);
584 	if (handle->scf_trans == NULL)
585 		return (SMBD_SMF_SYSTEM_ERR);
586 
587 	/*
588 	 * properties must be set in transactions and don't take
589 	 * effect until the transaction has been ended/committed.
590 	 */
591 	entry = scf_entry_create(handle->scf_handle);
592 	if (entry == NULL) {
593 		ret = SMBD_SMF_SYSTEM_ERR;
594 		goto out;
595 	}
596 
597 	if (scf_transaction_property_delete(handle->scf_trans,
598 	    entry, propname) == 0) {
599 		/* the entry is in the transaction */
600 		entry = NULL;
601 	} else {
602 		switch (scf_error()) {
603 		case SCF_ERROR_NOT_FOUND:
604 			/* Did not exist.  We're done. */
605 			ret = SMBD_SMF_OK;
606 			goto out;
607 		case SCF_ERROR_PERMISSION_DENIED:
608 			ret = SMBD_SMF_NO_PERMISSION;
609 			goto out;
610 		default:
611 			ret = SMBD_SMF_SYSTEM_ERR;
612 			goto out;
613 		}
614 	}
615 
616 out:
617 	scf_entry_destroy(entry);
618 	return (ret);
619 }
620 
621 /*
622  * Put the smb service into maintenance mode.
623  */
624 int
625 smb_smf_maintenance_mode(void)
626 {
627 	return (smf_maintain_instance(SMBD_DEFAULT_INSTANCE_FMRI, 0));
628 }
629 
630 /*
631  * Restart the smb service.
632  */
633 int
634 smb_smf_restart_service(void)
635 {
636 	return (smf_restart_instance(SMBD_DEFAULT_INSTANCE_FMRI));
637 }
638 
639 /*
640  * smb_smf_scf_init()
641  *
642  * must be called before using any of the SCF functions.
643  * Returns smb_scfhandle_t pointer if success.
644  */
645 smb_scfhandle_t *
646 smb_smf_scf_init(char *svc_name)
647 {
648 	smb_scfhandle_t *handle;
649 
650 	handle = malloc(sizeof (smb_scfhandle_t));
651 	if (handle != NULL) {
652 		bzero((char *)handle, sizeof (smb_scfhandle_t));
653 		handle->scf_state = SCH_STATE_INITIALIZING;
654 		handle->scf_handle = scf_handle_create(SCF_VERSION);
655 		if (handle->scf_handle != NULL) {
656 			if (scf_handle_bind(handle->scf_handle) == 0) {
657 				handle->scf_scope =
658 				    scf_scope_create(handle->scf_handle);
659 
660 				if (handle->scf_scope == NULL)
661 					goto err;
662 
663 				if (scf_handle_get_local_scope(
664 				    handle->scf_handle, handle->scf_scope) != 0)
665 					goto err;
666 
667 				handle->scf_service =
668 				    scf_service_create(handle->scf_handle);
669 
670 				if (handle->scf_service == NULL)
671 					goto err;
672 
673 				if (scf_scope_get_service(handle->scf_scope,
674 				    svc_name, handle->scf_service)
675 				    != SCF_SUCCESS) {
676 					goto err;
677 				}
678 				handle->scf_pg =
679 				    scf_pg_create(handle->scf_handle);
680 
681 				if (handle->scf_pg == NULL)
682 					goto err;
683 
684 				handle->scf_state = SCH_STATE_INIT;
685 			} else {
686 				goto err;
687 			}
688 		} else {
689 			free(handle);
690 			handle = NULL;
691 			smb_smf_scf_log_error(
692 			    "Could not access SMF repository");
693 		}
694 	}
695 	return (handle);
696 
697 	/* error handling/unwinding */
698 err:
699 	(void) smb_smf_scf_fini(handle);
700 	(void) smb_smf_scf_log_error("SMF initialization problem");
701 	return (NULL);
702 }
703 
704 /*
705  * smb_smf_scf_fini(handle)
706  *
707  * must be called when done. Called with the handle allocated in
708  * smb_smf_scf_init(), it cleans up the state and frees any SCF resources
709  * still in use.
710  */
711 void
712 smb_smf_scf_fini(smb_scfhandle_t *handle)
713 {
714 	if (handle != NULL) {
715 		int unbind = 0;
716 		scf_iter_destroy(handle->scf_pg_iter);
717 		handle->scf_pg_iter = NULL;
718 
719 		scf_iter_destroy(handle->scf_inst_iter);
720 		handle->scf_inst_iter = NULL;
721 
722 		unbind = 1;
723 		scf_scope_destroy(handle->scf_scope);
724 		handle->scf_scope = NULL;
725 
726 		scf_instance_destroy(handle->scf_instance);
727 		handle->scf_instance = NULL;
728 
729 		scf_service_destroy(handle->scf_service);
730 		handle->scf_service = NULL;
731 
732 		scf_pg_destroy(handle->scf_pg);
733 		handle->scf_pg = NULL;
734 
735 		handle->scf_state = SCH_STATE_UNINIT;
736 		if (unbind)
737 			(void) scf_handle_unbind(handle->scf_handle);
738 		scf_handle_destroy(handle->scf_handle);
739 		handle->scf_handle = NULL;
740 
741 		free(handle);
742 	}
743 }
744