xref: /illumos-gate/usr/src/lib/libshare/smbfs/smbfs_scfutil.c (revision a4955f4fa65e38d70c07d38e657a9aff43fa155f)
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 2022 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 	(void) smb_smf_scf_log_error("SMF initialization problem");
251 	return (NULL);
252 }
253 
254 /*
255  * smb_smf_create_service_pgroup(handle, pgroup)
256  *
257  * create a new property group at service level.
258  */
259 int
260 smb_smf_create_service_pgroup(smb_scfhandle_t *handle, char *pgroup)
261 {
262 	int ret = SMBC_SMF_OK;
263 	int err;
264 
265 	if (handle == NULL) {
266 		return (SMBC_SMF_SYSTEM_ERR);
267 	}
268 
269 	/*
270 	 * only create a handle if it doesn't exist. It is ok to exist
271 	 * since the pg handle will be set as a side effect.
272 	 */
273 	if (handle->scf_pg == NULL) {
274 		handle->scf_pg = scf_pg_create(handle->scf_handle);
275 	}
276 	/*
277 	 * if the pgroup exists, we are done. If it doesn't, then we
278 	 * need to actually add one to the service instance.
279 	 */
280 	if (scf_service_get_pg(handle->scf_service,
281 	    pgroup, handle->scf_pg) != 0) {
282 		/* doesn't exist so create one */
283 		if (scf_service_add_pg(handle->scf_service, pgroup,
284 		    SCF_GROUP_FRAMEWORK, 0, handle->scf_pg) != 0) {
285 			err = scf_error();
286 			if (err != SCF_ERROR_NONE)
287 				smb_smf_scf_log_error(NULL);
288 			switch (err) {
289 			case SCF_ERROR_PERMISSION_DENIED:
290 				ret = SMBC_SMF_NO_PERMISSION;
291 				break;
292 			default:
293 				ret = SMBC_SMF_SYSTEM_ERR;
294 				break;
295 			}
296 		}
297 	}
298 	return (ret);
299 }
300 
301 /*
302  * smb_smf_create_instance_pgroup(handle, pgroup)
303  *
304  * create a new property group at instance level.
305  */
306 int
307 smb_smf_create_instance_pgroup(smb_scfhandle_t *handle, char *pgroup)
308 {
309 	int ret = SMBC_SMF_OK;
310 	int err;
311 
312 	if (handle == NULL) {
313 		return (SMBC_SMF_SYSTEM_ERR);
314 	}
315 
316 	/*
317 	 * only create a handle if it doesn't exist. It is ok to exist
318 	 * since the pg handle will be set as a side effect.
319 	 */
320 	if (handle->scf_pg == NULL) {
321 		handle->scf_pg = scf_pg_create(handle->scf_handle);
322 	}
323 
324 	/*
325 	 * if the pgroup exists, we are done. If it doesn't, then we
326 	 * need to actually add one to the service instance.
327 	 */
328 	if (scf_instance_get_pg(handle->scf_instance,
329 	    pgroup, handle->scf_pg) != 0) {
330 		/* doesn't exist so create one */
331 		if (scf_instance_add_pg(handle->scf_instance, pgroup,
332 		    SCF_GROUP_APPLICATION, 0, handle->scf_pg) != 0) {
333 			err = scf_error();
334 			if (err != SCF_ERROR_NONE)
335 				smb_smf_scf_log_error(NULL);
336 			switch (err) {
337 			case SCF_ERROR_PERMISSION_DENIED:
338 				ret = SMBC_SMF_NO_PERMISSION;
339 				break;
340 			default:
341 				ret = SMBC_SMF_SYSTEM_ERR;
342 				break;
343 			}
344 		}
345 	}
346 	return (ret);
347 }
348 
349 /*
350  * smb_smf_delete_service_pgroup(handle, pgroup)
351  *
352  * remove the property group from the current service.
353  * but only if it actually exists.
354  */
355 int
356 smb_smf_delete_service_pgroup(smb_scfhandle_t *handle, char *pgroup)
357 {
358 	int ret = SMBC_SMF_OK;
359 	int err;
360 
361 	if (handle == NULL) {
362 		return (SMBC_SMF_SYSTEM_ERR);
363 	}
364 
365 	/*
366 	 * only create a handle if it doesn't exist. It is ok to exist
367 	 * since the pg handle will be set as a side effect.
368 	 */
369 	if (handle->scf_pg == NULL) {
370 		handle->scf_pg = scf_pg_create(handle->scf_handle);
371 	}
372 
373 	/*
374 	 * only delete if it does exist.
375 	 */
376 	if (scf_service_get_pg(handle->scf_service,
377 	    pgroup, handle->scf_pg) == 0) {
378 		/* does exist so delete it */
379 		if (scf_pg_delete(handle->scf_pg) != 0) {
380 			ret = SMBC_SMF_SYSTEM_ERR;
381 			err = scf_error();
382 			if (err != SCF_ERROR_NONE) {
383 				smb_smf_scf_log_error("SMF delpg problem");
384 			}
385 		}
386 	} else {
387 		err = scf_error();
388 		if (err != SCF_ERROR_NONE)
389 			smb_smf_scf_log_error("SMF getpg problem");
390 		ret = SMBC_SMF_SYSTEM_ERR;
391 	}
392 	if (ret == SMBC_SMF_SYSTEM_ERR &&
393 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
394 		ret = SMBC_SMF_NO_PERMISSION;
395 	}
396 	return (ret);
397 }
398 
399 /*
400  * smb_smf_delete_instance_pgroup(handle, pgroup)
401  *
402  * remove the property group from the current instance.
403  * but only if it actually exists.
404  */
405 int
406 smb_smf_delete_instance_pgroup(smb_scfhandle_t *handle, char *pgroup)
407 {
408 	int ret = SMBC_SMF_OK;
409 	int err;
410 
411 	if (handle == NULL) {
412 		return (SMBC_SMF_SYSTEM_ERR);
413 	}
414 
415 	/*
416 	 * only create a handle if it doesn't exist. It is ok to exist
417 	 * since the pg handle will be set as a side effect.
418 	 */
419 	if (handle->scf_pg == NULL) {
420 		handle->scf_pg = scf_pg_create(handle->scf_handle);
421 	}
422 
423 	/*
424 	 * only delete if it does exist.
425 	 */
426 	if (scf_instance_get_pg(handle->scf_instance,
427 	    pgroup, handle->scf_pg) == 0) {
428 		/* does exist so delete it */
429 		if (scf_pg_delete(handle->scf_pg) != 0) {
430 			ret = SMBC_SMF_SYSTEM_ERR;
431 			err = scf_error();
432 			if (err != SCF_ERROR_NONE) {
433 				smb_smf_scf_log_error("SMF delpg problem");
434 			}
435 		}
436 	} else {
437 		err = scf_error();
438 		if (err != SCF_ERROR_NONE)
439 			smb_smf_scf_log_error("SMF getpg problem");
440 		ret = SMBC_SMF_SYSTEM_ERR;
441 	}
442 	if (ret == SMBC_SMF_SYSTEM_ERR &&
443 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
444 		ret = SMBC_SMF_NO_PERMISSION;
445 	}
446 	return (ret);
447 }
448 
449 /*
450  * Start transaction on current pg in handle.
451  * The pg could be service or instance level.
452  * Must be called after pg handle is obtained
453  * from create or get.
454  */
455 int
456 smb_smf_start_transaction(smb_scfhandle_t *handle)
457 {
458 	int ret = SMBC_SMF_OK;
459 
460 	if (!handle || (!handle->scf_pg)) {
461 		return (SMBC_SMF_SYSTEM_ERR);
462 	}
463 	/*
464 	 * lookup the property group and create it if it doesn't already
465 	 * exist.
466 	 */
467 	if (handle->scf_state == SCH_STATE_INIT) {
468 		if (ret == SMBC_SMF_OK) {
469 			handle->scf_trans =
470 			    scf_transaction_create(handle->scf_handle);
471 			if (handle->scf_trans != NULL) {
472 				if (scf_transaction_start(handle->scf_trans,
473 				    handle->scf_pg) != 0) {
474 					ret = SMBC_SMF_SYSTEM_ERR;
475 					scf_transaction_destroy(
476 					    handle->scf_trans);
477 					handle->scf_trans = NULL;
478 				}
479 			} else {
480 				ret = SMBC_SMF_SYSTEM_ERR;
481 			}
482 		}
483 	}
484 	if (ret == SMBC_SMF_SYSTEM_ERR &&
485 	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
486 		ret = SMBC_SMF_NO_PERMISSION;
487 	}
488 	return (ret);
489 }
490 
491 /*
492  * smb_smf_end_transaction(handle)
493  *
494  * Commit the changes that were added to the transaction in the
495  * handle. Do all necessary cleanup.
496  */
497 int
498 smb_smf_end_transaction(smb_scfhandle_t *handle)
499 {
500 	int ret = SMBC_SMF_OK;
501 
502 	if (handle == NULL) {
503 		return (SMBC_SMF_SYSTEM_ERR);
504 	}
505 
506 	if (handle->scf_trans == NULL) {
507 		ret = SMBC_SMF_SYSTEM_ERR;
508 	} else {
509 		if (scf_transaction_commit(handle->scf_trans) < 0) {
510 			ret = SMBC_SMF_SYSTEM_ERR;
511 			smb_smf_scf_log_error("Failed to commit transaction");
512 		}
513 		scf_transaction_destroy_children(handle->scf_trans);
514 		scf_transaction_destroy(handle->scf_trans);
515 		handle->scf_trans = NULL;
516 	}
517 	return (ret);
518 }
519 
520 /*
521  * Deletes property in current pg
522  */
523 int
524 smb_smf_delete_property(smb_scfhandle_t *handle, char *propname)
525 {
526 	int ret = SMBC_SMF_OK;
527 	scf_transaction_entry_t *entry = NULL;
528 
529 	if (handle == NULL) {
530 		return (SMBC_SMF_SYSTEM_ERR);
531 	}
532 
533 	/*
534 	 * properties must be set in transactions and don't take
535 	 * effect until the transaction has been ended/committed.
536 	 */
537 	entry = scf_entry_create(handle->scf_handle);
538 	if (entry != NULL) {
539 		if (scf_transaction_property_delete(handle->scf_trans, entry,
540 		    propname) != 0) {
541 			ret = SMBC_SMF_SYSTEM_ERR;
542 		}
543 	} else {
544 		ret = SMBC_SMF_SYSTEM_ERR;
545 	}
546 	if (ret == SMBC_SMF_SYSTEM_ERR) {
547 		switch (scf_error()) {
548 		case SCF_ERROR_PERMISSION_DENIED:
549 			ret = SMBC_SMF_NO_PERMISSION;
550 			break;
551 		}
552 	}
553 
554 	/*
555 	 * cleanup if there were any errors that didn't leave these
556 	 * values where they would be cleaned up later.
557 	 */
558 	if ((ret != SMBC_SMF_OK) && (entry != NULL)) {
559 		scf_entry_destroy(entry);
560 	}
561 	return (ret);
562 }
563 
564 /*
565  * Sets string property in current pg
566  */
567 int
568 smb_smf_set_string_property(smb_scfhandle_t *handle,
569     char *propname, char *valstr)
570 {
571 	int ret = SMBC_SMF_OK;
572 	scf_value_t *value = NULL;
573 	scf_transaction_entry_t *entry = NULL;
574 
575 	if (handle == NULL) {
576 		return (SMBC_SMF_SYSTEM_ERR);
577 	}
578 
579 	/*
580 	 * properties must be set in transactions and don't take
581 	 * effect until the transaction has been ended/committed.
582 	 */
583 	value = scf_value_create(handle->scf_handle);
584 	entry = scf_entry_create(handle->scf_handle);
585 	if (value != NULL && entry != NULL) {
586 		if (scf_transaction_property_change(handle->scf_trans, entry,
587 		    propname, SCF_TYPE_ASTRING) == 0 ||
588 		    scf_transaction_property_new(handle->scf_trans, entry,
589 		    propname, SCF_TYPE_ASTRING) == 0) {
590 			if (scf_value_set_astring(value, valstr) == 0) {
591 				if (scf_entry_add_value(entry, value) != 0) {
592 					ret = SMBC_SMF_SYSTEM_ERR;
593 					scf_value_destroy(value);
594 				}
595 				/* the value is in the transaction */
596 				value = NULL;
597 			} else {
598 				/* value couldn't be constructed */
599 				ret = SMBC_SMF_SYSTEM_ERR;
600 			}
601 			/* the entry is in the transaction */
602 			entry = NULL;
603 		} else {
604 			ret = SMBC_SMF_SYSTEM_ERR;
605 		}
606 	} else {
607 		ret = SMBC_SMF_SYSTEM_ERR;
608 	}
609 	if (ret == SMBC_SMF_SYSTEM_ERR) {
610 		switch (scf_error()) {
611 		case SCF_ERROR_PERMISSION_DENIED:
612 			ret = SMBC_SMF_NO_PERMISSION;
613 			break;
614 		}
615 	}
616 
617 	/*
618 	 * cleanup if there were any errors that didn't leave these
619 	 * values where they would be cleaned up later.
620 	 */
621 	if (value != NULL)
622 		scf_value_destroy(value);
623 	if (entry != NULL)
624 		scf_entry_destroy(entry);
625 	return (ret);
626 }
627 
628 /*
629  * Gets string property value.upto sz size.
630  * Caller is responsible to have enough memory allocated.
631  */
632 int
633 smb_smf_get_string_property(smb_scfhandle_t *handle, char *propname,
634     char *valstr, size_t sz)
635 {
636 	int ret = SMBC_SMF_OK;
637 	scf_value_t *value;
638 	scf_property_t *prop;
639 
640 	if (handle == NULL) {
641 		return (SMBC_SMF_SYSTEM_ERR);
642 	}
643 
644 	value = scf_value_create(handle->scf_handle);
645 	prop = scf_property_create(handle->scf_handle);
646 	if (value && prop &&
647 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
648 		if (scf_property_get_value(prop, value) == 0) {
649 			if (scf_value_get_astring(value, valstr, sz) < 0) {
650 				ret = SMBC_SMF_SYSTEM_ERR;
651 			}
652 		} else {
653 			ret = SMBC_SMF_SYSTEM_ERR;
654 		}
655 	} else {
656 		ret = SMBC_SMF_SYSTEM_ERR;
657 	}
658 	if (value != NULL)
659 		scf_value_destroy(value);
660 	if (prop != NULL)
661 		scf_property_destroy(prop);
662 	return (ret);
663 }
664 
665 /*
666  * Get integer value of property.
667  * The value is returned as int64_t value
668  * Caller ensures appropriate translation.
669  */
670 int
671 smb_smf_set_integer_property(smb_scfhandle_t *handle, char *propname,
672     int64_t valint)
673 {
674 	int ret = SMBC_SMF_OK;
675 	scf_value_t *value = NULL;
676 	scf_transaction_entry_t *entry = NULL;
677 
678 	if (handle == NULL) {
679 		return (SMBC_SMF_SYSTEM_ERR);
680 	}
681 
682 	/*
683 	 * properties must be set in transactions and don't take
684 	 * effect until the transaction has been ended/committed.
685 	 */
686 	value = scf_value_create(handle->scf_handle);
687 	entry = scf_entry_create(handle->scf_handle);
688 	if (value != NULL && entry != NULL) {
689 		if (scf_transaction_property_change(handle->scf_trans, entry,
690 		    propname, SCF_TYPE_INTEGER) == 0 ||
691 		    scf_transaction_property_new(handle->scf_trans, entry,
692 		    propname, SCF_TYPE_INTEGER) == 0) {
693 			scf_value_set_integer(value, valint);
694 			if (scf_entry_add_value(entry, value) != 0) {
695 				ret = SMBC_SMF_SYSTEM_ERR;
696 				scf_value_destroy(value);
697 			}
698 			/* the value is in the transaction */
699 			value = NULL;
700 		}
701 		/* the entry is in the transaction */
702 		entry = NULL;
703 	} else {
704 		ret = SMBC_SMF_SYSTEM_ERR;
705 	}
706 	if (ret == SMBC_SMF_SYSTEM_ERR) {
707 		switch (scf_error()) {
708 		case SCF_ERROR_PERMISSION_DENIED:
709 			ret = SMBC_SMF_NO_PERMISSION;
710 			break;
711 		}
712 	}
713 	/*
714 	 * cleanup if there were any errors that didn't leave these
715 	 * values where they would be cleaned up later.
716 	 */
717 	if (value != NULL)
718 		scf_value_destroy(value);
719 	if (entry != NULL)
720 		scf_entry_destroy(entry);
721 	return (ret);
722 }
723 
724 /*
725  * Sets integer property value.
726  * Caller is responsible to have enough memory allocated.
727  */
728 int
729 smb_smf_get_integer_property(smb_scfhandle_t *handle, char *propname,
730     int64_t *valint)
731 {
732 	int ret = SMBC_SMF_OK;
733 	scf_value_t *value = NULL;
734 	scf_property_t *prop = NULL;
735 
736 	if (handle == NULL) {
737 		return (SMBC_SMF_SYSTEM_ERR);
738 	}
739 
740 	value = scf_value_create(handle->scf_handle);
741 	prop = scf_property_create(handle->scf_handle);
742 	if ((prop) && (value) &&
743 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
744 		if (scf_property_get_value(prop, value) == 0) {
745 			if (scf_value_get_integer(value,
746 			    valint) != 0) {
747 				ret = SMBC_SMF_SYSTEM_ERR;
748 			}
749 		} else {
750 			ret = SMBC_SMF_SYSTEM_ERR;
751 		}
752 	} else {
753 		ret = SMBC_SMF_SYSTEM_ERR;
754 	}
755 	if (value != NULL)
756 		scf_value_destroy(value);
757 	if (prop != NULL)
758 		scf_property_destroy(prop);
759 	return (ret);
760 }
761 
762 /*
763  * Get boolean value of property.
764  * The value is returned as int64_t value
765  * Caller ensures appropriate translation.
766  */
767 int
768 smb_smf_set_boolean_property(smb_scfhandle_t *handle, char *propname,
769     uint8_t valbool)
770 {
771 	int ret = SMBC_SMF_OK;
772 	scf_value_t *value = NULL;
773 	scf_transaction_entry_t *entry = NULL;
774 
775 	if (handle == NULL) {
776 		return (SMBC_SMF_SYSTEM_ERR);
777 	}
778 
779 	/*
780 	 * properties must be set in transactions and don't take
781 	 * effect until the transaction has been ended/committed.
782 	 */
783 	value = scf_value_create(handle->scf_handle);
784 	entry = scf_entry_create(handle->scf_handle);
785 	if (value != NULL && entry != NULL) {
786 		if (scf_transaction_property_change(handle->scf_trans, entry,
787 		    propname, SCF_TYPE_BOOLEAN) == 0 ||
788 		    scf_transaction_property_new(handle->scf_trans, entry,
789 		    propname, SCF_TYPE_BOOLEAN) == 0) {
790 			scf_value_set_boolean(value, valbool);
791 			if (scf_entry_add_value(entry, value) != 0) {
792 				ret = SMBC_SMF_SYSTEM_ERR;
793 				scf_value_destroy(value);
794 			}
795 			/* the value is in the transaction */
796 			value = NULL;
797 		}
798 		/* the entry is in the transaction */
799 		entry = NULL;
800 	} else {
801 		ret = SMBC_SMF_SYSTEM_ERR;
802 	}
803 	if (ret == SMBC_SMF_SYSTEM_ERR) {
804 		switch (scf_error()) {
805 		case SCF_ERROR_PERMISSION_DENIED:
806 			ret = SMBC_SMF_NO_PERMISSION;
807 			break;
808 		}
809 	}
810 	/*
811 	 * cleanup if there were any errors that didn't leave these
812 	 * values where they would be cleaned up later.
813 	 */
814 	if (value != NULL)
815 		scf_value_destroy(value);
816 	if (entry != NULL)
817 		scf_entry_destroy(entry);
818 	return (ret);
819 }
820 
821 /*
822  * Sets boolean property value.
823  * Caller is responsible to have enough memory allocated.
824  */
825 int
826 smb_smf_get_boolean_property(smb_scfhandle_t *handle, char *propname,
827     uint8_t *valbool)
828 {
829 	int ret = SMBC_SMF_OK;
830 	scf_value_t *value = NULL;
831 	scf_property_t *prop = NULL;
832 
833 	if (handle == NULL) {
834 		return (SMBC_SMF_SYSTEM_ERR);
835 	}
836 
837 	value = scf_value_create(handle->scf_handle);
838 	prop = scf_property_create(handle->scf_handle);
839 	if ((prop) && (value) &&
840 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
841 		if (scf_property_get_value(prop, value) == 0) {
842 			if (scf_value_get_boolean(value,
843 			    valbool) != 0) {
844 				ret = SMBC_SMF_SYSTEM_ERR;
845 			}
846 		} else {
847 			ret = SMBC_SMF_SYSTEM_ERR;
848 		}
849 	} else {
850 		ret = SMBC_SMF_SYSTEM_ERR;
851 	}
852 	if (value != NULL)
853 		scf_value_destroy(value);
854 	if (prop != NULL)
855 		scf_property_destroy(prop);
856 	return (ret);
857 }
858 
859 /*
860  * Sets a blob property value.
861  */
862 int
863 smb_smf_set_opaque_property(smb_scfhandle_t *handle, char *propname,
864     void *voidval, size_t sz)
865 {
866 	int ret = SMBC_SMF_OK;
867 	scf_value_t *value;
868 	scf_transaction_entry_t *entry;
869 
870 	if (handle == NULL) {
871 		return (SMBC_SMF_SYSTEM_ERR);
872 	}
873 
874 	/*
875 	 * properties must be set in transactions and don't take
876 	 * effect until the transaction has been ended/committed.
877 	 */
878 	value = scf_value_create(handle->scf_handle);
879 	entry = scf_entry_create(handle->scf_handle);
880 	if (value != NULL && entry != NULL) {
881 		if (scf_transaction_property_change(handle->scf_trans, entry,
882 		    propname, SCF_TYPE_OPAQUE) == 0 ||
883 		    scf_transaction_property_new(handle->scf_trans, entry,
884 		    propname, SCF_TYPE_OPAQUE) == 0) {
885 			if (scf_value_set_opaque(value, voidval, sz) == 0) {
886 				if (scf_entry_add_value(entry, value) != 0) {
887 					ret = SMBC_SMF_SYSTEM_ERR;
888 					scf_value_destroy(value);
889 				}
890 				/* the value is in the transaction */
891 				value = NULL;
892 			} else {
893 				/* value couldn't be constructed */
894 				ret = SMBC_SMF_SYSTEM_ERR;
895 			}
896 			/* the entry is in the transaction */
897 			entry = NULL;
898 		} else {
899 			ret = SMBC_SMF_SYSTEM_ERR;
900 		}
901 	} else {
902 		ret = SMBC_SMF_SYSTEM_ERR;
903 	}
904 	if (ret == SMBC_SMF_SYSTEM_ERR) {
905 		switch (scf_error()) {
906 		case SCF_ERROR_PERMISSION_DENIED:
907 			ret = SMBC_SMF_NO_PERMISSION;
908 			break;
909 		}
910 	}
911 	/*
912 	 * cleanup if there were any errors that didn't leave these
913 	 * values where they would be cleaned up later.
914 	 */
915 	if (value != NULL)
916 		scf_value_destroy(value);
917 	if (entry != NULL)
918 		scf_entry_destroy(entry);
919 	return (ret);
920 }
921 
922 /*
923  * Gets a blob property value.
924  * Caller is responsible to have enough memory allocated.
925  */
926 int
927 smb_smf_get_opaque_property(smb_scfhandle_t *handle, char *propname,
928     void *v, size_t sz)
929 {
930 	int ret = SMBC_SMF_OK;
931 	scf_value_t *value = NULL;
932 	scf_property_t *prop = NULL;
933 
934 	if (handle == NULL) {
935 		return (SMBC_SMF_SYSTEM_ERR);
936 	}
937 
938 	value = scf_value_create(handle->scf_handle);
939 	prop = scf_property_create(handle->scf_handle);
940 	if ((prop) && (value) &&
941 	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
942 		if (scf_property_get_value(prop, value) == 0) {
943 			if (scf_value_get_opaque(value, (char *)v, sz) != sz) {
944 				ret = SMBC_SMF_SYSTEM_ERR;
945 			}
946 		} else {
947 			ret = SMBC_SMF_SYSTEM_ERR;
948 		}
949 	} else {
950 		ret = SMBC_SMF_SYSTEM_ERR;
951 	}
952 	if (value != NULL)
953 		scf_value_destroy(value);
954 	if (prop != NULL)
955 		scf_property_destroy(prop);
956 	return (ret);
957 }
958 
959 /*
960  * Gets an instance iterator for the service specified.
961  */
962 smb_scfhandle_t *
963 smb_smf_get_iterator(char *svc_name)
964 {
965 	smb_scfhandle_t *handle = NULL;
966 
967 	handle = smb_smf_scf_init(svc_name);
968 	if (!handle) {
969 		return (NULL);
970 	}
971 
972 	handle->scf_inst_iter = scf_iter_create(handle->scf_handle);
973 	if (handle->scf_inst_iter) {
974 		if (scf_iter_service_instances(handle->scf_inst_iter,
975 		    handle->scf_service) != 0) {
976 			smb_smf_scf_fini(handle);
977 			handle = NULL;
978 		} else {
979 			handle->scf_instance = NULL;
980 		}
981 	} else {
982 		smb_smf_scf_fini(handle);
983 		handle = NULL;
984 	}
985 	return (handle);
986 }
987