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