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