xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c (revision a21e16923712d68dbeecfc9660b47a4279005efd)
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