xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_scfutil.c (revision 89a7715a55deca73d03076f5c24463717f0aaa91)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
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/alloc.h>
44 
45 #include <smbsrv/libsmb.h>
46 
47 /*
48  * smb_smf_scf_log_error(msg)
49  * Logs error messages from scf API's
50  */
51 static void
52 smb_smf_scf_log_error(char *msg)
53 {
54 	if (!msg) {
55 		syslog(LOG_ERR, " SMBD SMF problem: %s\n",
56 		    scf_strerror(scf_error()));
57 	} else { /*LINTED E_SEC_PRINTF_E_VAR_FMT*/
58 		syslog(LOG_ERR, msg, scf_strerror(scf_error()));
59 	}
60 }
61 
62 /*
63  * Check if instance with given name exists for a service.
64  * Returns 0 is instance exist
65  */
66 int
67 smb_smf_instance_exists(smb_scfhandle_t *handle, char *inst_name)
68 {
69 	int ret = SMBD_SMF_OK;
70 	if (handle == NULL)
71 		return (SMBD_SMF_SYSTEM_ERR);
72 
73 	handle->scf_instance = scf_instance_create(handle->scf_handle);
74 	if (scf_service_get_instance(handle->scf_service, inst_name,
75 	    handle->scf_instance) != SCF_SUCCESS)
76 		ret = SMBD_SMF_SYSTEM_ERR;
77 
78 	scf_instance_destroy(handle->scf_instance);
79 	handle->scf_instance = NULL;
80 	return (ret);
81 }
82 
83 /*
84  * Create a service instance. returns 0 if successful.
85  * If instance already exists enable it.
86  */
87 int
88 smb_smf_instance_create(smb_scfhandle_t *handle, char *serv_prefix,
89 	char *inst_name)
90 {
91 	char *instance;
92 	int ret = SMBD_SMF_OK;
93 	int sz;
94 
95 	if (handle == NULL)
96 		return (SMBD_SMF_SYSTEM_ERR);
97 
98 	if (!serv_prefix || !inst_name)
99 		return (SMBD_SMF_SYSTEM_ERR);
100 
101 	sz = strlen(serv_prefix) + strlen(inst_name) + 2;
102 	instance = malloc(sz);
103 	if (!instance)
104 		return (SMBD_SMF_NO_MEMORY);
105 
106 	(void) snprintf(instance, sz, "%s:%s", serv_prefix, inst_name);
107 	handle->scf_instance = scf_instance_create(handle->scf_handle);
108 	if (scf_service_get_instance(handle->scf_service, inst_name,
109 	    handle->scf_instance) != SCF_SUCCESS) {
110 		if (scf_service_add_instance(handle->scf_service,
111 		    inst_name, handle->scf_instance) == SCF_SUCCESS) {
112 			if (smf_enable_instance(instance, 0))
113 				ret = SMBD_SMF_SYSTEM_ERR;
114 		} else {
115 			ret = SMBD_SMF_SYSTEM_ERR;
116 		}
117 	} else {
118 		if (smf_enable_instance(instance, 0))
119 			ret = SMBD_SMF_SYSTEM_ERR;
120 	}
121 	free(instance);
122 	return (ret);
123 }
124 
125 /*
126  * Delete a specified instance. Return SMBD_SMF_OK for success.
127  */
128 int
129 smb_smf_instance_delete(smb_scfhandle_t *handle, char *inst_name)
130 {
131 	int ret = SMBD_SMF_OK;
132 
133 	if (handle == NULL)
134 		return (SMBD_SMF_SYSTEM_ERR);
135 
136 	handle->scf_instance = scf_instance_create(handle->scf_handle);
137 	if (scf_service_get_instance(handle->scf_service, inst_name,
138 	    handle->scf_instance) == SCF_SUCCESS) {
139 		if (scf_instance_delete(handle->scf_instance) == SCF_SUCCESS) {
140 			return (ret);
141 		} else {
142 			ret = SMBD_SMF_SYSTEM_ERR;
143 		}
144 	} else {
145 		smb_smf_scf_log_error(NULL);
146 		ret = SMBD_SMF_SYSTEM_ERR;
147 	}
148 	return (ret);
149 }
150 
151 /*
152  * smb_smf_create_service_pgroup(handle, pgroup)
153  *
154  * create a new property group at service level.
155  */
156 int
157 smb_smf_create_service_pgroup(smb_scfhandle_t *handle, char *pgroup)
158 {
159 	int ret = SMBD_SMF_OK;
160 	int err;
161 
162 	if (handle == NULL) {
163 		return (SMBD_SMF_SYSTEM_ERR);
164 	}
165 
166 	/*
167 	 * only create a handle if it doesn't exist. It is ok to exist
168 	 * since the pg handle will be set as a side effect.
169 	 */
170 	if (handle->scf_pg == NULL)
171 		handle->scf_pg = scf_pg_create(handle->scf_handle);
172 
173 	/*
174 	 * if the pgroup exists, we are done. If it doesn't, then we
175 	 * need to actually add one to the service instance.
176 	 */
177 	if (scf_service_get_pg(handle->scf_service,
178 	    pgroup, handle->scf_pg) != 0) {
179 		/* doesn't exist so create one */
180 		if (scf_service_add_pg(handle->scf_service, pgroup,
181 		    SCF_GROUP_APPLICATION, 0, handle->scf_pg) != 0) {
182 			err = scf_error();
183 			if (err != SCF_ERROR_NONE)
184 				smb_smf_scf_log_error(NULL);
185 			switch (err) {
186 			case SCF_ERROR_PERMISSION_DENIED:
187 				ret = SMBD_SMF_NO_PERMISSION;
188 				break;
189 			default:
190 				ret = SMBD_SMF_SYSTEM_ERR;
191 				break;
192 			}
193 		}
194 	}
195 	return (ret);
196 }
197 
198 /*
199  * smb_smf_create_instance_pgroup(handle, pgroup)
200  *
201  * create a new property group at instance level.
202  */
203 int
204 smb_smf_create_instance_pgroup(smb_scfhandle_t *handle, char *pgroup)
205 {
206 	int ret = SMBD_SMF_OK;
207 	int err;
208 
209 	if (handle == NULL) {
210 		return (SMBD_SMF_SYSTEM_ERR);
211 	}
212 
213 	/*
214 	 * only create a handle if it doesn't exist. It is ok to exist
215 	 * since the pg handle will be set as a side effect.
216 	 */
217 	if (handle->scf_pg == NULL)
218 		handle->scf_pg = scf_pg_create(handle->scf_handle);
219 
220 	/*
221 	 * if the pgroup exists, we are done. If it doesn't, then we
222 	 * need to actually add one to the service instance.
223 	 */
224 	if (scf_instance_get_pg(handle->scf_instance,
225 	    pgroup, handle->scf_pg) != 0) {
226 		/* doesn't exist so create one */
227 		if (scf_instance_add_pg(handle->scf_instance, pgroup,
228 		    SCF_GROUP_FRAMEWORK, 0, handle->scf_pg) != 0) {
229 			err = scf_error();
230 			if (err != SCF_ERROR_NONE)
231 				smb_smf_scf_log_error(NULL);
232 			switch (err) {
233 			case SCF_ERROR_PERMISSION_DENIED:
234 				ret = SMBD_SMF_NO_PERMISSION;
235 				break;
236 			default:
237 				ret = SMBD_SMF_SYSTEM_ERR;
238 				break;
239 			}
240 		}
241 	}
242 	return (ret);
243 }
244 
245 /*
246  * smb_smf_delete_service_pgroup(handle, pgroup)
247  *
248  * remove the property group from the current service.
249  * but only if it actually exists.
250  */
251 int
252 smb_smf_delete_service_pgroup(smb_scfhandle_t *handle, char *pgroup)
253 {
254 	int ret = SMBD_SMF_OK;
255 	int err;
256 
257 	if (handle == NULL) {
258 		return (SMBD_SMF_SYSTEM_ERR);
259 	}
260 
261 	/*
262 	 * only create a handle if it doesn't exist. It is ok to exist
263 	 * since the pg handle will be set as a side effect.
264 	 */
265 	if (handle->scf_pg == NULL)
266 		handle->scf_pg = scf_pg_create(handle->scf_handle);
267 
268 	/*
269 	 * only delete if it does exist.
270 	 */
271 	if (scf_service_get_pg(handle->scf_service,
272 	    pgroup, handle->scf_pg) == 0) {
273 		/* does exist so delete it */
274 		if (scf_pg_delete(handle->scf_pg) != 0) {
275 			ret = SMBD_SMF_SYSTEM_ERR;
276 			err = scf_error();
277 			if (err != SCF_ERROR_NONE) {
278 				smb_smf_scf_log_error("SMF delpg "
279 				    "problem: %s\n");
280 			}
281 		}
282 	} else {
283 		err = scf_error();
284 		if (err != SCF_ERROR_NONE)
285 			smb_smf_scf_log_error("SMF getpg problem: %s\n");
286 		ret = SMBD_SMF_SYSTEM_ERR;
287 	}
288 	if (ret == SMBD_SMF_SYSTEM_ERR &&
289 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
290 		ret = SMBD_SMF_NO_PERMISSION;
291 	}
292 	return (ret);
293 }
294 
295 /*
296  * smb_smf_delete_instance_pgroup(handle, pgroup)
297  *
298  * remove the property group from the current instance.
299  * but only if it actually exists.
300  */
301 int
302 smb_smf_delete_instance_pgroup(smb_scfhandle_t *handle, char *pgroup)
303 {
304 	int ret = SMBD_SMF_OK;
305 	int err;
306 
307 	if (handle == NULL)
308 		return (SMBD_SMF_SYSTEM_ERR);
309 
310 	/*
311 	 * only create a handle if it doesn't exist. It is ok to exist
312 	 * since the pg handle will be set as a side effect.
313 	 */
314 	if (handle->scf_pg == NULL)
315 		handle->scf_pg = scf_pg_create(handle->scf_handle);
316 
317 	/*
318 	 * only delete if it does exist.
319 	 */
320 	if (scf_instance_get_pg(handle->scf_instance,
321 	    pgroup, handle->scf_pg) == 0) {
322 		/* does exist so delete it */
323 		if (scf_pg_delete(handle->scf_pg) != 0) {
324 			ret = SMBD_SMF_SYSTEM_ERR;
325 			err = scf_error();
326 			if (err != SCF_ERROR_NONE) {
327 				smb_smf_scf_log_error("SMF delpg "
328 				    "problem: %s\n");
329 			}
330 		}
331 	} else {
332 		err = scf_error();
333 		if (err != SCF_ERROR_NONE)
334 			smb_smf_scf_log_error("SMF getpg problem: %s\n");
335 		ret = SMBD_SMF_SYSTEM_ERR;
336 	}
337 	if (ret == SMBD_SMF_SYSTEM_ERR &&
338 	    scf_error() == SCF_ERROR_PERMISSION_DENIED)
339 		ret = SMBD_SMF_NO_PERMISSION;
340 
341 	return (ret);
342 }
343 
344 /*
345  * Start transaction on current pg in handle.
346  * The pg could be service or instance level.
347  * Must be called after pg handle is obtained
348  * from create or get.
349  */
350 int
351 smb_smf_start_transaction(smb_scfhandle_t *handle)
352 {
353 	int ret = SMBD_SMF_OK;
354 
355 	if (!handle || (!handle->scf_pg))
356 		return (SMBD_SMF_SYSTEM_ERR);
357 
358 	/*
359 	 * lookup the property group and create it if it doesn't already
360 	 * exist.
361 	 */
362 	if (handle->scf_state == SCH_STATE_INIT) {
363 		if (ret == SMBD_SMF_OK) {
364 			handle->scf_trans =
365 			    scf_transaction_create(handle->scf_handle);
366 			if (handle->scf_trans != NULL) {
367 				if (scf_transaction_start(handle->scf_trans,
368 				    handle->scf_pg) != 0) {
369 					ret = SMBD_SMF_SYSTEM_ERR;
370 					scf_transaction_destroy(
371 					    handle->scf_trans);
372 					handle->scf_trans = NULL;
373 				}
374 			} else {
375 				ret = SMBD_SMF_SYSTEM_ERR;
376 			}
377 		}
378 	}
379 	if (ret == SMBD_SMF_SYSTEM_ERR &&
380 	    scf_error() == SCF_ERROR_PERMISSION_DENIED)
381 		ret = SMBD_SMF_NO_PERMISSION;
382 
383 	return (ret);
384 }
385 
386 /*
387  * smb_smf_end_transaction(handle)
388  *
389  * Commit the changes that were added to the transaction in the
390  * handle. Do all necessary cleanup.
391  */
392 int
393 smb_smf_end_transaction(smb_scfhandle_t *handle)
394 {
395 	int ret = SMBD_SMF_OK;
396 
397 	if (handle == NULL)
398 		return (SMBD_SMF_SYSTEM_ERR);
399 
400 	if (handle->scf_trans == NULL) {
401 		ret = SMBD_SMF_SYSTEM_ERR;
402 	} else {
403 		if (scf_transaction_commit(handle->scf_trans) < 0) {
404 			ret = SMBD_SMF_SYSTEM_ERR;
405 			smb_smf_scf_log_error("Failed to commit "
406 			    "transaction: %s");
407 		}
408 		scf_transaction_destroy_children(handle->scf_trans);
409 		scf_transaction_destroy(handle->scf_trans);
410 		handle->scf_trans = NULL;
411 	}
412 	return (ret);
413 }
414 
415 /*
416  * Deletes property in current pg
417  */
418 int
419 smb_smf_delete_property(smb_scfhandle_t *handle, char *propname)
420 {
421 	int ret = SMBD_SMF_OK;
422 	scf_transaction_entry_t *entry = NULL;
423 
424 	if (handle == NULL)
425 		return (SMBD_SMF_SYSTEM_ERR);
426 
427 	/*
428 	 * properties must be set in transactions and don't take
429 	 * effect until the transaction has been ended/committed.
430 	 */
431 	entry = scf_entry_create(handle->scf_handle);
432 	if (entry != NULL) {
433 		if (scf_transaction_property_delete(handle->scf_trans, entry,
434 		    propname) != 0) {
435 			ret = SMBD_SMF_SYSTEM_ERR;
436 		}
437 	} else {
438 		ret = SMBD_SMF_SYSTEM_ERR;
439 	}
440 	if (ret == SMBD_SMF_SYSTEM_ERR) {
441 		switch (scf_error()) {
442 		case SCF_ERROR_PERMISSION_DENIED:
443 			ret = SMBD_SMF_NO_PERMISSION;
444 			break;
445 		}
446 	}
447 
448 	/*
449 	 * cleanup if there were any errors that didn't leave these
450 	 * values where they would be cleaned up later.
451 	 */
452 	if ((ret != SMBD_SMF_OK) && (entry != NULL))
453 		scf_entry_destroy(entry);
454 
455 	return (ret);
456 }
457 
458 /*
459  * Sets string property in current pg
460  */
461 int
462 smb_smf_set_string_property(smb_scfhandle_t *handle,
463     char *propname, char *valstr)
464 {
465 	int ret = SMBD_SMF_OK;
466 	scf_value_t *value = NULL;
467 	scf_transaction_entry_t *entry = NULL;
468 
469 	if (handle == NULL)
470 		return (SMBD_SMF_SYSTEM_ERR);
471 
472 	/*
473 	 * properties must be set in transactions and don't take
474 	 * effect until the transaction has been ended/committed.
475 	 */
476 	value = scf_value_create(handle->scf_handle);
477 	entry = scf_entry_create(handle->scf_handle);
478 	if (value != NULL && entry != NULL) {
479 		if (scf_transaction_property_change(handle->scf_trans, entry,
480 		    propname, SCF_TYPE_ASTRING) == 0 ||
481 		    scf_transaction_property_new(handle->scf_trans, entry,
482 		    propname, SCF_TYPE_ASTRING) == 0) {
483 			if (scf_value_set_astring(value, valstr) == 0) {
484 				if (scf_entry_add_value(entry, value) != 0) {
485 					ret = SMBD_SMF_SYSTEM_ERR;
486 					scf_value_destroy(value);
487 				}
488 				/* the value is in the transaction */
489 				value = NULL;
490 			} else {
491 				/* value couldn't be constructed */
492 				ret = SMBD_SMF_SYSTEM_ERR;
493 			}
494 			/* the entry is in the transaction */
495 			entry = NULL;
496 		} else {
497 			ret = SMBD_SMF_SYSTEM_ERR;
498 		}
499 	} else {
500 		ret = SMBD_SMF_SYSTEM_ERR;
501 	}
502 	if (ret == SMBD_SMF_SYSTEM_ERR) {
503 		switch (scf_error()) {
504 		case SCF_ERROR_PERMISSION_DENIED:
505 			ret = SMBD_SMF_NO_PERMISSION;
506 			break;
507 		}
508 	}
509 
510 	/*
511 	 * cleanup if there were any errors that didn't leave these
512 	 * values where they would be cleaned up later.
513 	 */
514 	if (value != NULL)
515 		scf_value_destroy(value);
516 	if (entry != NULL)
517 		scf_entry_destroy(entry);
518 	return (ret);
519 }
520 
521 /*
522  * Gets string property value.upto sz size.
523  * Caller is responsible to have enough memory allocated.
524  */
525 int
526 smb_smf_get_string_property(smb_scfhandle_t *handle, char *propname,
527     char *valstr, size_t sz)
528 {
529 	int ret = SMBD_SMF_OK;
530 	scf_value_t *value;
531 	scf_property_t *prop;
532 
533 	if (handle == NULL)
534 		return (SMBD_SMF_SYSTEM_ERR);
535 
536 	value = scf_value_create(handle->scf_handle);
537 	prop = scf_property_create(handle->scf_handle);
538 	if (value && prop &&
539 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
540 		if (scf_property_get_value(prop, value) == 0) {
541 			if (scf_value_get_astring(value, valstr, sz) < 0) {
542 				ret = SMBD_SMF_SYSTEM_ERR;
543 			}
544 		} else {
545 			ret = SMBD_SMF_SYSTEM_ERR;
546 		}
547 	} else {
548 		ret = SMBD_SMF_SYSTEM_ERR;
549 	}
550 	if (value != NULL)
551 		scf_value_destroy(value);
552 	if (prop != NULL)
553 		scf_property_destroy(prop);
554 	return (ret);
555 }
556 
557 /*
558  * Set integer value of property.
559  * The value is returned as int64_t value
560  * Caller ensures appropriate translation.
561  */
562 int
563 smb_smf_set_integer_property(smb_scfhandle_t *handle, char *propname,
564     int64_t valint)
565 {
566 	int ret = SMBD_SMF_OK;
567 	scf_value_t *value = NULL;
568 	scf_transaction_entry_t *entry = NULL;
569 
570 	if (handle == NULL)
571 		return (SMBD_SMF_SYSTEM_ERR);
572 
573 	/*
574 	 * properties must be set in transactions and don't take
575 	 * effect until the transaction has been ended/committed.
576 	 */
577 	value = scf_value_create(handle->scf_handle);
578 	entry = scf_entry_create(handle->scf_handle);
579 	if (value != NULL && entry != NULL) {
580 		if (scf_transaction_property_change(handle->scf_trans, entry,
581 		    propname, SCF_TYPE_INTEGER) == 0 ||
582 		    scf_transaction_property_new(handle->scf_trans, entry,
583 		    propname, SCF_TYPE_INTEGER) == 0) {
584 			scf_value_set_integer(value, valint);
585 			if (scf_entry_add_value(entry, value) != 0) {
586 				ret = SMBD_SMF_SYSTEM_ERR;
587 				scf_value_destroy(value);
588 			}
589 			/* the value is in the transaction */
590 			value = NULL;
591 		}
592 		/* the entry is in the transaction */
593 		entry = NULL;
594 	} else {
595 		ret = SMBD_SMF_SYSTEM_ERR;
596 	}
597 	if (ret == SMBD_SMF_SYSTEM_ERR) {
598 		switch (scf_error()) {
599 		case SCF_ERROR_PERMISSION_DENIED:
600 			ret = SMBD_SMF_NO_PERMISSION;
601 			break;
602 		}
603 	}
604 	/*
605 	 * cleanup if there were any errors that didn't leave these
606 	 * values where they would be cleaned up later.
607 	 */
608 	if (value != NULL)
609 		scf_value_destroy(value);
610 	if (entry != NULL)
611 		scf_entry_destroy(entry);
612 	return (ret);
613 }
614 
615 /*
616  * Gets integer property value.
617  * Caller is responsible to have enough memory allocated.
618  */
619 int
620 smb_smf_get_integer_property(smb_scfhandle_t *handle, char *propname,
621     int64_t *valint)
622 {
623 	int ret = SMBD_SMF_OK;
624 	scf_value_t *value = NULL;
625 	scf_property_t *prop = NULL;
626 
627 	if (handle == NULL)
628 		return (SMBD_SMF_SYSTEM_ERR);
629 
630 	value = scf_value_create(handle->scf_handle);
631 	prop = scf_property_create(handle->scf_handle);
632 	if ((prop) && (value) &&
633 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
634 		if (scf_property_get_value(prop, value) == 0) {
635 			if (scf_value_get_integer(value,
636 			    valint) != 0) {
637 				ret = SMBD_SMF_SYSTEM_ERR;
638 			}
639 		} else {
640 			ret = SMBD_SMF_SYSTEM_ERR;
641 		}
642 	} else {
643 		ret = SMBD_SMF_SYSTEM_ERR;
644 	}
645 	if (value != NULL)
646 		scf_value_destroy(value);
647 	if (prop != NULL)
648 		scf_property_destroy(prop);
649 	return (ret);
650 }
651 
652 /*
653  * Set boolean value of property.
654  * The value is returned as int64_t value
655  * Caller ensures appropriate translation.
656  */
657 int
658 smb_smf_set_boolean_property(smb_scfhandle_t *handle, char *propname,
659     uint8_t valbool)
660 {
661 	int ret = SMBD_SMF_OK;
662 	scf_value_t *value = NULL;
663 	scf_transaction_entry_t *entry = NULL;
664 
665 	if (handle == NULL)
666 		return (SMBD_SMF_SYSTEM_ERR);
667 
668 	/*
669 	 * properties must be set in transactions and don't take
670 	 * effect until the transaction has been ended/committed.
671 	 */
672 	value = scf_value_create(handle->scf_handle);
673 	entry = scf_entry_create(handle->scf_handle);
674 	if (value != NULL && entry != NULL) {
675 		if (scf_transaction_property_change(handle->scf_trans, entry,
676 		    propname, SCF_TYPE_BOOLEAN) == 0 ||
677 		    scf_transaction_property_new(handle->scf_trans, entry,
678 		    propname, SCF_TYPE_BOOLEAN) == 0) {
679 			scf_value_set_boolean(value, valbool);
680 			if (scf_entry_add_value(entry, value) != 0) {
681 				ret = SMBD_SMF_SYSTEM_ERR;
682 				scf_value_destroy(value);
683 			}
684 			/* the value is in the transaction */
685 			value = NULL;
686 		}
687 		/* the entry is in the transaction */
688 		entry = NULL;
689 	} else {
690 		ret = SMBD_SMF_SYSTEM_ERR;
691 	}
692 	if (ret == SMBD_SMF_SYSTEM_ERR) {
693 		switch (scf_error()) {
694 		case SCF_ERROR_PERMISSION_DENIED:
695 			ret = SMBD_SMF_NO_PERMISSION;
696 			break;
697 		}
698 	}
699 	/*
700 	 * cleanup if there were any errors that didn't leave these
701 	 * values where they would be cleaned up later.
702 	 */
703 	if (value != NULL)
704 		scf_value_destroy(value);
705 	if (entry != NULL)
706 		scf_entry_destroy(entry);
707 	return (ret);
708 }
709 
710 /*
711  * Gets boolean property value.
712  * Caller is responsible to have enough memory allocated.
713  */
714 int
715 smb_smf_get_boolean_property(smb_scfhandle_t *handle, char *propname,
716     uint8_t *valbool)
717 {
718 	int ret = SMBD_SMF_OK;
719 	scf_value_t *value = NULL;
720 	scf_property_t *prop = NULL;
721 
722 	if (handle == NULL)
723 		return (SMBD_SMF_SYSTEM_ERR);
724 
725 	value = scf_value_create(handle->scf_handle);
726 	prop = scf_property_create(handle->scf_handle);
727 	if ((prop) && (value) &&
728 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
729 		if (scf_property_get_value(prop, value) == 0) {
730 			if (scf_value_get_boolean(value,
731 			    valbool) != 0) {
732 				ret = SMBD_SMF_SYSTEM_ERR;
733 			}
734 		} else {
735 			ret = SMBD_SMF_SYSTEM_ERR;
736 		}
737 	} else {
738 		ret = SMBD_SMF_SYSTEM_ERR;
739 	}
740 	if (value != NULL)
741 		scf_value_destroy(value);
742 	if (prop != NULL)
743 		scf_property_destroy(prop);
744 	return (ret);
745 }
746 
747 /*
748  * Sets a blob property value.
749  */
750 int
751 smb_smf_set_opaque_property(smb_scfhandle_t *handle, char *propname,
752     void *voidval, size_t sz)
753 {
754 	int ret = SMBD_SMF_OK;
755 	scf_value_t *value;
756 	scf_transaction_entry_t *entry;
757 
758 	if (handle == NULL)
759 		return (SMBD_SMF_SYSTEM_ERR);
760 
761 	/*
762 	 * properties must be set in transactions and don't take
763 	 * effect until the transaction has been ended/committed.
764 	 */
765 	value = scf_value_create(handle->scf_handle);
766 	entry = scf_entry_create(handle->scf_handle);
767 	if (value != NULL && entry != NULL) {
768 		if (scf_transaction_property_change(handle->scf_trans, entry,
769 		    propname, SCF_TYPE_OPAQUE) == 0 ||
770 		    scf_transaction_property_new(handle->scf_trans, entry,
771 		    propname, SCF_TYPE_OPAQUE) == 0) {
772 			if (scf_value_set_opaque(value, voidval, sz) == 0) {
773 				if (scf_entry_add_value(entry, value) != 0) {
774 					ret = SMBD_SMF_SYSTEM_ERR;
775 					scf_value_destroy(value);
776 				}
777 				/* the value is in the transaction */
778 				value = NULL;
779 			} else {
780 				/* value couldn't be constructed */
781 				ret = SMBD_SMF_SYSTEM_ERR;
782 			}
783 			/* the entry is in the transaction */
784 			entry = NULL;
785 		} else {
786 			ret = SMBD_SMF_SYSTEM_ERR;
787 		}
788 	} else {
789 		ret = SMBD_SMF_SYSTEM_ERR;
790 	}
791 	if (ret == SMBD_SMF_SYSTEM_ERR) {
792 		switch (scf_error()) {
793 		case SCF_ERROR_PERMISSION_DENIED:
794 			ret = SMBD_SMF_NO_PERMISSION;
795 			break;
796 		}
797 	}
798 	/*
799 	 * cleanup if there were any errors that didn't leave these
800 	 * values where they would be cleaned up later.
801 	 */
802 	if (value != NULL)
803 		scf_value_destroy(value);
804 	if (entry != NULL)
805 		scf_entry_destroy(entry);
806 	return (ret);
807 }
808 
809 /*
810  * Gets a blob property value.
811  * Caller is responsible to have enough memory allocated.
812  */
813 int
814 smb_smf_get_opaque_property(smb_scfhandle_t *handle, char *propname,
815     void *v, size_t sz)
816 {
817 	int ret = SMBD_SMF_OK;
818 	scf_value_t *value = NULL;
819 	scf_property_t *prop = NULL;
820 
821 	if (handle == NULL)
822 		return (SMBD_SMF_SYSTEM_ERR);
823 
824 	value = scf_value_create(handle->scf_handle);
825 	prop = scf_property_create(handle->scf_handle);
826 	if ((prop) && (value) &&
827 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
828 		if (scf_property_get_value(prop, value) == 0) {
829 			if (scf_value_get_opaque(value, (char *)v, sz) != sz) {
830 				ret = SMBD_SMF_SYSTEM_ERR;
831 			}
832 		} else {
833 			ret = SMBD_SMF_SYSTEM_ERR;
834 		}
835 	} else {
836 		ret = SMBD_SMF_SYSTEM_ERR;
837 	}
838 	if (value != NULL)
839 		scf_value_destroy(value);
840 	if (prop != NULL)
841 		scf_property_destroy(prop);
842 	return (ret);
843 }
844 
845 /*
846  * Get property based on property type. Returns string value of that
847  * property. Only SCF_TYPE_ASTRING, SCF_TYPE_INTEGER, SCF_TYPE_BOOLEAN
848  * supported.
849  */
850 int
851 smb_smf_get_property(smb_scfhandle_t *handle, int proptype, char *propname,
852     char *valstr, size_t sz)
853 {
854 	int64_t valint = 0;
855 	uint8_t valbool = 0;
856 	int ret = SMBD_SMF_OK;
857 
858 	switch (proptype) {
859 	case SCF_TYPE_ASTRING:
860 		ret = smb_smf_get_string_property(handle, propname,
861 		    valstr, sz);
862 		break;
863 	case SCF_TYPE_INTEGER:
864 		if ((ret = smb_smf_get_integer_property(handle, propname,
865 		    &valint)) != 0)
866 			return (ret);
867 		(void) snprintf(valstr, sz, "%lld", valint);
868 		break;
869 	case SCF_TYPE_BOOLEAN:
870 		if ((ret = smb_smf_get_boolean_property(handle, propname,
871 		    &valbool)) != 0)
872 			return (ret);
873 		(void) strlcpy(valstr, (valbool ? "true" : "false"), sz);
874 		break;
875 	default:
876 		return (SMBD_SMF_SYSTEM_ERR);
877 	}
878 	return (ret);
879 }
880 
881 /*
882  * Set property based on property type.
883  * Only SCF_TYPE_ASTRING, SCF_TYPE_INTEGER, SCF_TYPE_BOOLEAN supported.
884  */
885 int
886 smb_smf_set_property(smb_scfhandle_t *handle, int proptype,
887     char *propname, char *valstr)
888 {
889 	int64_t valint = 0;
890 	uint8_t valbool = 0;
891 	int ret = SMBD_SMF_OK;
892 
893 	switch (proptype) {
894 	case SCF_TYPE_ASTRING:
895 		ret = smb_smf_set_string_property(handle, propname,
896 		    valstr);
897 		break;
898 	case SCF_TYPE_INTEGER:
899 		valint = strtol(valstr, 0, 10);
900 		ret = smb_smf_set_integer_property(handle, propname,
901 		    valint);
902 		break;
903 	case SCF_TYPE_BOOLEAN:
904 		if (strcasecmp(valstr, "true") == 0)
905 			valbool = 1;
906 		ret = smb_smf_set_boolean_property(handle, propname, valbool);
907 		break;
908 	default:
909 		return (SMBD_SMF_SYSTEM_ERR);
910 	}
911 	return (ret);
912 }
913 
914 /*
915  * Gets an instance iterator for the service specified.
916  */
917 smb_scfhandle_t *
918 smb_smf_get_iterator(char *svc_name)
919 {
920 	smb_scfhandle_t *handle = NULL;
921 
922 	handle = smb_smf_scf_init(svc_name);
923 	if (!handle)
924 		return (NULL);
925 
926 	handle->scf_inst_iter = scf_iter_create(handle->scf_handle);
927 	if (handle->scf_inst_iter) {
928 		if (scf_iter_service_instances(handle->scf_inst_iter,
929 		    handle->scf_service) != 0) {
930 			smb_smf_scf_fini(handle);
931 			handle = NULL;
932 		} else {
933 			handle->scf_instance = NULL;
934 		}
935 	} else {
936 		smb_smf_scf_fini(handle);
937 		handle = NULL;
938 	}
939 	return (handle);
940 }
941 
942 /*
943  * smb_smf_scf_init()
944  *
945  * must be called before using any of the SCF functions.
946  * Returns smb_scfhandle_t pointer if success.
947  */
948 smb_scfhandle_t *
949 smb_smf_scf_init(char *svc_name)
950 {
951 	smb_scfhandle_t *handle;
952 
953 	handle = malloc(sizeof (smb_scfhandle_t));
954 	if (handle != NULL) {
955 		bzero((char *)handle, sizeof (smb_scfhandle_t));
956 		handle->scf_state = SCH_STATE_INITIALIZING;
957 		handle->scf_handle = scf_handle_create(SCF_VERSION);
958 		if (handle->scf_handle != NULL) {
959 			if (scf_handle_bind(handle->scf_handle) == 0) {
960 				handle->scf_scope =
961 				    scf_scope_create(handle->scf_handle);
962 				if (scf_handle_get_local_scope(
963 				    handle->scf_handle, handle->scf_scope) != 0)
964 					goto err;
965 
966 				handle->scf_service =
967 				    scf_service_create(handle->scf_handle);
968 
969 				if (scf_scope_get_service(handle->scf_scope,
970 				    svc_name, handle->scf_service)
971 				    != SCF_SUCCESS) {
972 					goto err;
973 				}
974 				handle->scf_pg =
975 				    scf_pg_create(handle->scf_handle);
976 				handle->scf_state = SCH_STATE_INIT;
977 			} else {
978 				goto err;
979 			}
980 		} else {
981 			free(handle);
982 			handle = NULL;
983 			smb_smf_scf_log_error("Could not access SMF "
984 			    "repository: %s\n");
985 		}
986 	}
987 	return (handle);
988 
989 	/* error handling/unwinding */
990 err:
991 	(void) smb_smf_scf_fini(handle);
992 	(void) smb_smf_scf_log_error("SMF initialization problem: %s\n");
993 	return (NULL);
994 }
995 
996 /*
997  * smb_smf_scf_fini(handle)
998  *
999  * must be called when done. Called with the handle allocated in
1000  * smb_smf_scf_init(), it cleans up the state and frees any SCF resources
1001  * still in use.
1002  */
1003 void
1004 smb_smf_scf_fini(smb_scfhandle_t *handle)
1005 {
1006 	if (handle != NULL) {
1007 		int unbind = 0;
1008 		scf_iter_destroy(handle->scf_pg_iter);
1009 		handle->scf_pg_iter = NULL;
1010 
1011 		scf_iter_destroy(handle->scf_inst_iter);
1012 		handle->scf_inst_iter = NULL;
1013 
1014 		unbind = 1;
1015 		scf_scope_destroy(handle->scf_scope);
1016 		handle->scf_scope = NULL;
1017 
1018 		scf_instance_destroy(handle->scf_instance);
1019 		handle->scf_instance = NULL;
1020 
1021 		scf_service_destroy(handle->scf_service);
1022 		handle->scf_service = NULL;
1023 
1024 		scf_pg_destroy(handle->scf_pg);
1025 		handle->scf_pg = NULL;
1026 
1027 		handle->scf_state = SCH_STATE_UNINIT;
1028 		if (unbind)
1029 			(void) scf_handle_unbind(handle->scf_handle);
1030 		scf_handle_destroy(handle->scf_handle);
1031 		handle->scf_handle = NULL;
1032 
1033 		free(handle);
1034 	}
1035 }
1036