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