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
smb_smf_scf_log_error(char * msg)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
smb_smf_create_service_pgroup(smb_scfhandle_t * handle,char * pgroup)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
smb_smf_start_transaction(smb_scfhandle_t * handle)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
smb_smf_end_transaction(smb_scfhandle_t * handle)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
smb_smf_set_string_property(smb_scfhandle_t * handle,char * propname,char * valstr)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
smb_smf_get_string_property(smb_scfhandle_t * handle,char * propname,char * valstr,size_t sz)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
smb_smf_set_integer_property(smb_scfhandle_t * handle,char * propname,int64_t valint)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
smb_smf_get_integer_property(smb_scfhandle_t * handle,char * propname,int64_t * valint)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
smb_smf_set_boolean_property(smb_scfhandle_t * handle,char * propname,uint8_t valbool)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
smb_smf_get_boolean_property(smb_scfhandle_t * handle,char * propname,uint8_t * valbool)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
smb_smf_set_opaque_property(smb_scfhandle_t * handle,char * propname,void * voidval,size_t sz)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
smb_smf_get_opaque_property(smb_scfhandle_t * handle,char * propname,void * v,size_t sz)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
smb_smf_delete_property(smb_scfhandle_t * handle,char * propname)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
smb_smf_maintenance_mode(void)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
smb_smf_restart_service(void)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 *
smb_smf_scf_init(char * svc_name)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
smb_smf_scf_fini(smb_scfhandle_t * handle)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