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