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