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