1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "@(#)smb_scfutil.c 1.5 08/07/30 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/libsmb.h>
44
45 /*
46 * smb_smf_scf_log_error(msg)
47 * Logs error messages from scf API's
48 */
49 static void
smb_smf_scf_log_error(char * msg)50 smb_smf_scf_log_error(char *msg)
51 {
52 if (!msg) {
53 syslog(LOG_ERR, " SMBD SMF problem: %s\n",
54 scf_strerror(scf_error()));
55 } else { /*LINTED E_SEC_PRINTF_E_VAR_FMT*/
56 syslog(LOG_ERR, msg, scf_strerror(scf_error()));
57 }
58 }
59
60 /*
61 * smb_smf_create_service_pgroup(handle, pgroup)
62 *
63 * create a new property group at service level.
64 */
65 int
smb_smf_create_service_pgroup(smb_scfhandle_t * handle,char * pgroup)66 smb_smf_create_service_pgroup(smb_scfhandle_t *handle, char *pgroup)
67 {
68 int ret = SMBD_SMF_OK;
69 int err;
70
71 if (handle == NULL)
72 return (SMBD_SMF_SYSTEM_ERR);
73
74 /*
75 * only create a handle if it doesn't exist. It is ok to exist
76 * since the pg handle will be set as a side effect.
77 */
78 if (handle->scf_pg == NULL)
79 if ((handle->scf_pg =
80 scf_pg_create(handle->scf_handle)) == NULL)
81 return (SMBD_SMF_SYSTEM_ERR);
82
83 /*
84 * if the pgroup exists, we are done. If it doesn't, then we
85 * need to actually add one to the service instance.
86 */
87 if (scf_service_get_pg(handle->scf_service,
88 pgroup, handle->scf_pg) != 0) {
89 /* doesn't exist so create one */
90 if (scf_service_add_pg(handle->scf_service, pgroup,
91 SCF_GROUP_APPLICATION, 0, handle->scf_pg) != 0) {
92 err = scf_error();
93 if (err != SCF_ERROR_NONE)
94 smb_smf_scf_log_error(NULL);
95 switch (err) {
96 case SCF_ERROR_PERMISSION_DENIED:
97 ret = SMBD_SMF_NO_PERMISSION;
98 break;
99 default:
100 ret = SMBD_SMF_SYSTEM_ERR;
101 break;
102 }
103 }
104 }
105 return (ret);
106 }
107
108 /*
109 * Start transaction on current pg in handle.
110 * The pg could be service or instance level.
111 * Must be called after pg handle is obtained
112 * from create or get.
113 */
114 int
smb_smf_start_transaction(smb_scfhandle_t * handle)115 smb_smf_start_transaction(smb_scfhandle_t *handle)
116 {
117 int ret = SMBD_SMF_OK;
118
119 if (!handle || (!handle->scf_pg))
120 return (SMBD_SMF_SYSTEM_ERR);
121
122 /*
123 * lookup the property group and create it if it doesn't already
124 * exist.
125 */
126 if (handle->scf_state == SCH_STATE_INIT) {
127 if (ret == SMBD_SMF_OK) {
128 handle->scf_trans =
129 scf_transaction_create(handle->scf_handle);
130 if (handle->scf_trans != NULL) {
131 if (scf_transaction_start(handle->scf_trans,
132 handle->scf_pg) != 0) {
133 ret = SMBD_SMF_SYSTEM_ERR;
134 scf_transaction_destroy(
135 handle->scf_trans);
136 handle->scf_trans = NULL;
137 }
138 } else {
139 ret = SMBD_SMF_SYSTEM_ERR;
140 }
141 }
142 }
143 if (ret == SMBD_SMF_SYSTEM_ERR &&
144 scf_error() == SCF_ERROR_PERMISSION_DENIED)
145 ret = SMBD_SMF_NO_PERMISSION;
146
147 return (ret);
148 }
149
150 /*
151 * smb_smf_end_transaction(handle)
152 *
153 * Commit the changes that were added to the transaction in the
154 * handle. Do all necessary cleanup.
155 */
156 int
smb_smf_end_transaction(smb_scfhandle_t * handle)157 smb_smf_end_transaction(smb_scfhandle_t *handle)
158 {
159 int ret = SMBD_SMF_OK;
160
161 if (handle == NULL)
162 return (SMBD_SMF_SYSTEM_ERR);
163
164 if (handle->scf_trans == NULL) {
165 ret = SMBD_SMF_SYSTEM_ERR;
166 } else {
167 if (scf_transaction_commit(handle->scf_trans) < 0) {
168 ret = SMBD_SMF_SYSTEM_ERR;
169 smb_smf_scf_log_error("Failed to commit "
170 "transaction: %s");
171 }
172 scf_transaction_destroy_children(handle->scf_trans);
173 scf_transaction_destroy(handle->scf_trans);
174 handle->scf_trans = NULL;
175 }
176 return (ret);
177 }
178
179 /*
180 * Sets string property in current pg
181 */
182 int
smb_smf_set_string_property(smb_scfhandle_t * handle,char * propname,char * valstr)183 smb_smf_set_string_property(smb_scfhandle_t *handle,
184 char *propname, char *valstr)
185 {
186 int ret = SMBD_SMF_OK;
187 scf_value_t *value = NULL;
188 scf_transaction_entry_t *entry = NULL;
189
190 if (handle == NULL)
191 return (SMBD_SMF_SYSTEM_ERR);
192
193 /*
194 * properties must be set in transactions and don't take
195 * effect until the transaction has been ended/committed.
196 */
197 value = scf_value_create(handle->scf_handle);
198 entry = scf_entry_create(handle->scf_handle);
199 if (value != NULL && entry != NULL) {
200 if (scf_transaction_property_change(handle->scf_trans, entry,
201 propname, SCF_TYPE_ASTRING) == 0 ||
202 scf_transaction_property_new(handle->scf_trans, entry,
203 propname, SCF_TYPE_ASTRING) == 0) {
204 if (scf_value_set_astring(value, valstr) == 0) {
205 if (scf_entry_add_value(entry, value) != 0) {
206 ret = SMBD_SMF_SYSTEM_ERR;
207 scf_value_destroy(value);
208 }
209 /* the value is in the transaction */
210 value = NULL;
211 } else {
212 /* value couldn't be constructed */
213 ret = SMBD_SMF_SYSTEM_ERR;
214 }
215 /* the entry is in the transaction */
216 entry = NULL;
217 } else {
218 ret = SMBD_SMF_SYSTEM_ERR;
219 }
220 } else {
221 ret = SMBD_SMF_SYSTEM_ERR;
222 }
223 if (ret == SMBD_SMF_SYSTEM_ERR) {
224 switch (scf_error()) {
225 case SCF_ERROR_PERMISSION_DENIED:
226 ret = SMBD_SMF_NO_PERMISSION;
227 break;
228 }
229 }
230
231 /*
232 * cleanup if there were any errors that didn't leave these
233 * values where they would be cleaned up later.
234 */
235 if (value != NULL)
236 scf_value_destroy(value);
237 if (entry != NULL)
238 scf_entry_destroy(entry);
239 return (ret);
240 }
241
242 /*
243 * Gets string property value.upto sz size.
244 * Caller is responsible to have enough memory allocated.
245 */
246 int
smb_smf_get_string_property(smb_scfhandle_t * handle,char * propname,char * valstr,size_t sz)247 smb_smf_get_string_property(smb_scfhandle_t *handle, char *propname,
248 char *valstr, size_t sz)
249 {
250 int ret = SMBD_SMF_OK;
251 scf_value_t *value;
252 scf_property_t *prop;
253
254 if (handle == NULL)
255 return (SMBD_SMF_SYSTEM_ERR);
256
257 value = scf_value_create(handle->scf_handle);
258 prop = scf_property_create(handle->scf_handle);
259 if (value && prop &&
260 (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
261 if (scf_property_get_value(prop, value) == 0) {
262 if (scf_value_get_astring(value, valstr, sz) < 0) {
263 ret = SMBD_SMF_SYSTEM_ERR;
264 }
265 } else {
266 ret = SMBD_SMF_SYSTEM_ERR;
267 }
268 } else {
269 ret = SMBD_SMF_SYSTEM_ERR;
270 }
271 if (value != NULL)
272 scf_value_destroy(value);
273 if (prop != NULL)
274 scf_property_destroy(prop);
275 return (ret);
276 }
277
278 /*
279 * Set integer value of property.
280 * The value is returned as int64_t value
281 * Caller ensures appropriate translation.
282 */
283 int
smb_smf_set_integer_property(smb_scfhandle_t * handle,char * propname,int64_t valint)284 smb_smf_set_integer_property(smb_scfhandle_t *handle, char *propname,
285 int64_t valint)
286 {
287 int ret = SMBD_SMF_OK;
288 scf_value_t *value = NULL;
289 scf_transaction_entry_t *entry = NULL;
290
291 if (handle == NULL)
292 return (SMBD_SMF_SYSTEM_ERR);
293
294 /*
295 * properties must be set in transactions and don't take
296 * effect until the transaction has been ended/committed.
297 */
298 value = scf_value_create(handle->scf_handle);
299 entry = scf_entry_create(handle->scf_handle);
300 if (value != NULL && entry != NULL) {
301 if (scf_transaction_property_change(handle->scf_trans, entry,
302 propname, SCF_TYPE_INTEGER) == 0 ||
303 scf_transaction_property_new(handle->scf_trans, entry,
304 propname, SCF_TYPE_INTEGER) == 0) {
305 scf_value_set_integer(value, valint);
306 if (scf_entry_add_value(entry, value) != 0) {
307 ret = SMBD_SMF_SYSTEM_ERR;
308 scf_value_destroy(value);
309 }
310 /* the value is in the transaction */
311 value = NULL;
312 }
313 /* the entry is in the transaction */
314 entry = NULL;
315 } else {
316 ret = SMBD_SMF_SYSTEM_ERR;
317 }
318 if (ret == SMBD_SMF_SYSTEM_ERR) {
319 switch (scf_error()) {
320 case SCF_ERROR_PERMISSION_DENIED:
321 ret = SMBD_SMF_NO_PERMISSION;
322 break;
323 }
324 }
325 /*
326 * cleanup if there were any errors that didn't leave these
327 * values where they would be cleaned up later.
328 */
329 if (value != NULL)
330 scf_value_destroy(value);
331 if (entry != NULL)
332 scf_entry_destroy(entry);
333 return (ret);
334 }
335
336 /*
337 * Gets integer property value.
338 * Caller is responsible to have enough memory allocated.
339 */
340 int
smb_smf_get_integer_property(smb_scfhandle_t * handle,char * propname,int64_t * valint)341 smb_smf_get_integer_property(smb_scfhandle_t *handle, char *propname,
342 int64_t *valint)
343 {
344 int ret = SMBD_SMF_OK;
345 scf_value_t *value = NULL;
346 scf_property_t *prop = NULL;
347
348 if (handle == NULL)
349 return (SMBD_SMF_SYSTEM_ERR);
350
351 value = scf_value_create(handle->scf_handle);
352 prop = scf_property_create(handle->scf_handle);
353 if ((prop) && (value) &&
354 (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
355 if (scf_property_get_value(prop, value) == 0) {
356 if (scf_value_get_integer(value,
357 valint) != 0) {
358 ret = SMBD_SMF_SYSTEM_ERR;
359 }
360 } else {
361 ret = SMBD_SMF_SYSTEM_ERR;
362 }
363 } else {
364 ret = SMBD_SMF_SYSTEM_ERR;
365 }
366 if (value != NULL)
367 scf_value_destroy(value);
368 if (prop != NULL)
369 scf_property_destroy(prop);
370 return (ret);
371 }
372
373 /*
374 * Set boolean value of property.
375 * The value is returned as int64_t value
376 * Caller ensures appropriate translation.
377 */
378 int
smb_smf_set_boolean_property(smb_scfhandle_t * handle,char * propname,uint8_t valbool)379 smb_smf_set_boolean_property(smb_scfhandle_t *handle, char *propname,
380 uint8_t valbool)
381 {
382 int ret = SMBD_SMF_OK;
383 scf_value_t *value = NULL;
384 scf_transaction_entry_t *entry = NULL;
385
386 if (handle == NULL)
387 return (SMBD_SMF_SYSTEM_ERR);
388
389 /*
390 * properties must be set in transactions and don't take
391 * effect until the transaction has been ended/committed.
392 */
393 value = scf_value_create(handle->scf_handle);
394 entry = scf_entry_create(handle->scf_handle);
395 if (value != NULL && entry != NULL) {
396 if (scf_transaction_property_change(handle->scf_trans, entry,
397 propname, SCF_TYPE_BOOLEAN) == 0 ||
398 scf_transaction_property_new(handle->scf_trans, entry,
399 propname, SCF_TYPE_BOOLEAN) == 0) {
400 scf_value_set_boolean(value, valbool);
401 if (scf_entry_add_value(entry, value) != 0) {
402 ret = SMBD_SMF_SYSTEM_ERR;
403 scf_value_destroy(value);
404 }
405 /* the value is in the transaction */
406 value = NULL;
407 }
408 /* the entry is in the transaction */
409 entry = NULL;
410 } else {
411 ret = SMBD_SMF_SYSTEM_ERR;
412 }
413 if (ret == SMBD_SMF_SYSTEM_ERR) {
414 switch (scf_error()) {
415 case SCF_ERROR_PERMISSION_DENIED:
416 ret = SMBD_SMF_NO_PERMISSION;
417 break;
418 }
419 }
420 /*
421 * cleanup if there were any errors that didn't leave these
422 * values where they would be cleaned up later.
423 */
424 if (value != NULL)
425 scf_value_destroy(value);
426 if (entry != NULL)
427 scf_entry_destroy(entry);
428 return (ret);
429 }
430
431 /*
432 * Gets boolean property value.
433 * Caller is responsible to have enough memory allocated.
434 */
435 int
smb_smf_get_boolean_property(smb_scfhandle_t * handle,char * propname,uint8_t * valbool)436 smb_smf_get_boolean_property(smb_scfhandle_t *handle, char *propname,
437 uint8_t *valbool)
438 {
439 int ret = SMBD_SMF_OK;
440 scf_value_t *value = NULL;
441 scf_property_t *prop = NULL;
442
443 if (handle == NULL)
444 return (SMBD_SMF_SYSTEM_ERR);
445
446 value = scf_value_create(handle->scf_handle);
447 prop = scf_property_create(handle->scf_handle);
448 if ((prop) && (value) &&
449 (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
450 if (scf_property_get_value(prop, value) == 0) {
451 if (scf_value_get_boolean(value,
452 valbool) != 0) {
453 ret = SMBD_SMF_SYSTEM_ERR;
454 }
455 } else {
456 ret = SMBD_SMF_SYSTEM_ERR;
457 }
458 } else {
459 ret = SMBD_SMF_SYSTEM_ERR;
460 }
461 if (value != NULL)
462 scf_value_destroy(value);
463 if (prop != NULL)
464 scf_property_destroy(prop);
465 return (ret);
466 }
467
468 /*
469 * Sets a blob property value.
470 */
471 int
smb_smf_set_opaque_property(smb_scfhandle_t * handle,char * propname,void * voidval,size_t sz)472 smb_smf_set_opaque_property(smb_scfhandle_t *handle, char *propname,
473 void *voidval, size_t sz)
474 {
475 int ret = SMBD_SMF_OK;
476 scf_value_t *value;
477 scf_transaction_entry_t *entry;
478
479 if (handle == NULL)
480 return (SMBD_SMF_SYSTEM_ERR);
481
482 /*
483 * properties must be set in transactions and don't take
484 * effect until the transaction has been ended/committed.
485 */
486 value = scf_value_create(handle->scf_handle);
487 entry = scf_entry_create(handle->scf_handle);
488 if (value != NULL && entry != NULL) {
489 if (scf_transaction_property_change(handle->scf_trans, entry,
490 propname, SCF_TYPE_OPAQUE) == 0 ||
491 scf_transaction_property_new(handle->scf_trans, entry,
492 propname, SCF_TYPE_OPAQUE) == 0) {
493 if (scf_value_set_opaque(value, voidval, sz) == 0) {
494 if (scf_entry_add_value(entry, value) != 0) {
495 ret = SMBD_SMF_SYSTEM_ERR;
496 scf_value_destroy(value);
497 }
498 /* the value is in the transaction */
499 value = NULL;
500 } else {
501 /* value couldn't be constructed */
502 ret = SMBD_SMF_SYSTEM_ERR;
503 }
504 /* the entry is in the transaction */
505 entry = NULL;
506 } else {
507 ret = SMBD_SMF_SYSTEM_ERR;
508 }
509 } else {
510 ret = SMBD_SMF_SYSTEM_ERR;
511 }
512 if (ret == SMBD_SMF_SYSTEM_ERR) {
513 switch (scf_error()) {
514 case SCF_ERROR_PERMISSION_DENIED:
515 ret = SMBD_SMF_NO_PERMISSION;
516 break;
517 }
518 }
519 /*
520 * cleanup if there were any errors that didn't leave these
521 * values where they would be cleaned up later.
522 */
523 if (value != NULL)
524 scf_value_destroy(value);
525 if (entry != NULL)
526 scf_entry_destroy(entry);
527 return (ret);
528 }
529
530 /*
531 * Gets a blob property value.
532 * Caller is responsible to have enough memory allocated.
533 */
534 int
smb_smf_get_opaque_property(smb_scfhandle_t * handle,char * propname,void * v,size_t sz)535 smb_smf_get_opaque_property(smb_scfhandle_t *handle, char *propname,
536 void *v, size_t sz)
537 {
538 int ret = SMBD_SMF_OK;
539 scf_value_t *value = NULL;
540 scf_property_t *prop = NULL;
541
542 if (handle == NULL)
543 return (SMBD_SMF_SYSTEM_ERR);
544
545 value = scf_value_create(handle->scf_handle);
546 prop = scf_property_create(handle->scf_handle);
547 if ((prop) && (value) &&
548 (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
549 if (scf_property_get_value(prop, value) == 0) {
550 if (scf_value_get_opaque(value, (char *)v, sz) != sz) {
551 ret = SMBD_SMF_SYSTEM_ERR;
552 }
553 } else {
554 ret = SMBD_SMF_SYSTEM_ERR;
555 }
556 } else {
557 ret = SMBD_SMF_SYSTEM_ERR;
558 }
559 if (value != NULL)
560 scf_value_destroy(value);
561 if (prop != NULL)
562 scf_property_destroy(prop);
563 return (ret);
564 }
565
566 /*
567 * Put the smb service into maintenance mode.
568 */
569 int
smb_smf_maintenance_mode(void)570 smb_smf_maintenance_mode(void)
571 {
572 return (smf_maintain_instance(SMBD_DEFAULT_INSTANCE_FMRI, 0));
573 }
574
575 /*
576 * Restart the smb service.
577 */
578 int
smb_smf_restart_service(void)579 smb_smf_restart_service(void)
580 {
581 return (smf_restart_instance(SMBD_DEFAULT_INSTANCE_FMRI));
582 }
583
584 /*
585 * smb_smf_scf_init()
586 *
587 * must be called before using any of the SCF functions.
588 * Returns smb_scfhandle_t pointer if success.
589 */
590 smb_scfhandle_t *
smb_smf_scf_init(char * svc_name)591 smb_smf_scf_init(char *svc_name)
592 {
593 smb_scfhandle_t *handle;
594
595 handle = malloc(sizeof (smb_scfhandle_t));
596 if (handle != NULL) {
597 bzero((char *)handle, sizeof (smb_scfhandle_t));
598 handle->scf_state = SCH_STATE_INITIALIZING;
599 handle->scf_handle = scf_handle_create(SCF_VERSION);
600 if (handle->scf_handle != NULL) {
601 if (scf_handle_bind(handle->scf_handle) == 0) {
602 handle->scf_scope =
603 scf_scope_create(handle->scf_handle);
604
605 if (handle->scf_scope == NULL)
606 goto err;
607
608 if (scf_handle_get_local_scope(
609 handle->scf_handle, handle->scf_scope) != 0)
610 goto err;
611
612 handle->scf_service =
613 scf_service_create(handle->scf_handle);
614
615 if (handle->scf_service == NULL)
616 goto err;
617
618 if (scf_scope_get_service(handle->scf_scope,
619 svc_name, handle->scf_service)
620 != SCF_SUCCESS) {
621 goto err;
622 }
623 handle->scf_pg =
624 scf_pg_create(handle->scf_handle);
625
626 if (handle->scf_pg == NULL)
627 goto err;
628
629 handle->scf_state = SCH_STATE_INIT;
630 } else {
631 goto err;
632 }
633 } else {
634 free(handle);
635 handle = NULL;
636 smb_smf_scf_log_error("Could not access SMF "
637 "repository: %s\n");
638 }
639 }
640 return (handle);
641
642 /* error handling/unwinding */
643 err:
644 (void) smb_smf_scf_fini(handle);
645 (void) smb_smf_scf_log_error("SMF initialization problem: %s\n");
646 return (NULL);
647 }
648
649 /*
650 * smb_smf_scf_fini(handle)
651 *
652 * must be called when done. Called with the handle allocated in
653 * smb_smf_scf_init(), it cleans up the state and frees any SCF resources
654 * still in use.
655 */
656 void
smb_smf_scf_fini(smb_scfhandle_t * handle)657 smb_smf_scf_fini(smb_scfhandle_t *handle)
658 {
659 if (handle != NULL) {
660 int unbind = 0;
661 scf_iter_destroy(handle->scf_pg_iter);
662 handle->scf_pg_iter = NULL;
663
664 scf_iter_destroy(handle->scf_inst_iter);
665 handle->scf_inst_iter = NULL;
666
667 unbind = 1;
668 scf_scope_destroy(handle->scf_scope);
669 handle->scf_scope = NULL;
670
671 scf_instance_destroy(handle->scf_instance);
672 handle->scf_instance = NULL;
673
674 scf_service_destroy(handle->scf_service);
675 handle->scf_service = NULL;
676
677 scf_pg_destroy(handle->scf_pg);
678 handle->scf_pg = NULL;
679
680 handle->scf_state = SCH_STATE_UNINIT;
681 if (unbind)
682 (void) scf_handle_unbind(handle->scf_handle);
683 scf_handle_destroy(handle->scf_handle);
684 handle->scf_handle = NULL;
685
686 free(handle);
687 }
688 }
689