xref: /illumos-gate/usr/src/lib/libbsm/common/audit_scf.c (revision 5422785d352a2bb398daceab3d1898a8aa64d006)
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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /* auditd smf(5)/libscf(3LIB) interface - set and display audit parameters */
26 #include <audit_scf.h>
27 #include <audit_policy.h>
28 
29 /* propvec array must be NULL terminated */
30 scf_propvec_t	prop_vect[MAX_PROPVECS + 1];
31 
32 /*
33  * prt_error() - prt_error_va() wrapper; see prt_error_va() for more contextual
34  * information. Note, that the function disregards errno; if you need to print
35  * out strerror()/errno use directly prt_error_va().
36  * Inputs - program error format and message.
37  */
38 /*PRINTFLIKE1*/
39 static void
40 prt_error(char *fmt, ...)
41 {
42 	va_list 	args;
43 
44 	errno = 0;
45 
46 	va_start(args, fmt);
47 	prt_error_va(fmt, args);
48 	va_end(args);
49 }
50 
51 /*
52  * prt_error_va() - prints an error message along with corresponding system
53  * error number. Inputs - program error format and the va_list already prepared
54  * by the preceding functions.
55  *
56  */
57 /*PRINTFLIKE1*/
58 void
59 prt_error_va(char *fmt, va_list args)
60 {
61 	(void) vfprintf(stderr, fmt, args);
62 	(void) fputc('\n', stderr);
63 	if (errno)
64 		(void) fprintf(stderr, "error: %s(%d)\n",
65 		    strerror(errno), errno);
66 	(void) fflush(stderr);
67 }
68 
69 /*
70  * prt_scf_err() - scf_error()/scf_strerror() wrapper.
71  */
72 static void
73 prt_scf_err(void)
74 {
75 	(void) fprintf(stderr, "error: %s\n", scf_strerror(scf_error()));
76 }
77 
78 /*
79  * add_prop_vect_scf() - adds vector to the array of vectors later passed to
80  * get_/set_val_scf(). The first argument (vector) points to particular position
81  * in the vector of properties.
82  */
83 static void
84 add_prop_vect_scf(scf_propvec_t *vector, const char *prop_str,
85     scf_type_t prop_type, void *prop_val_ptr)
86 {
87 	vector->pv_prop = prop_str;
88 	vector->pv_type = prop_type;
89 	vector->pv_ptr = prop_val_ptr;
90 }
91 
92 /*
93  * get_val_scf() - get a property values from the audit service
94  *
95  * Arguments:	vector = pointers to the head end of array of property vectors
96  * 		pgroup_str = property group of property in AUDITD_FMRI
97  *
98  */
99 static boolean_t
100 get_val_scf(scf_propvec_t *vector, char *pgroup_str)
101 {
102 	scf_propvec_t	*bad_prop_vec = NULL;
103 
104 	/*
105 	 * Get the property vector from the editing snapshot (B_FALSE).
106 	 * For documentation on property vectors see <libscf_priv.h>.
107 	 */
108 	if (scf_read_propvec(AUDITD_FMRI, pgroup_str, B_FALSE, vector,
109 	    &bad_prop_vec) != SCF_SUCCESS) {
110 		prt_scf_err();
111 		if (bad_prop_vec != NULL) {
112 			prt_error(gettext("Reading the %s property in the %s "
113 			    "property group failed.\n"), bad_prop_vec->pv_prop,
114 			    pgroup_str);
115 		}
116 		return (B_FALSE);
117 	}
118 
119 	return (B_TRUE);
120 }
121 
122 /*
123  * set_val_scf() - set property values of the audit service.
124  *
125  * arguments:	vector = pointers to the head end of array of property vectors
126  * 		pgroup_str = property group of property in AUDITD_FMRI
127  *
128  */
129 static boolean_t
130 set_val_scf(scf_propvec_t *vector, char *pgroup_str)
131 {
132 	scf_propvec_t	*bad_prop_vec = NULL;
133 
134 	/* for documentation on property vectors see <libscf_priv.h> */
135 	if (scf_write_propvec(AUDITD_FMRI, pgroup_str, vector,
136 	    &bad_prop_vec) != SCF_SUCCESS) {
137 		prt_scf_err();
138 		if (bad_prop_vec != NULL) {
139 			prt_error(gettext("Setting the %s property in the %s "
140 			    "property group failed.\n"), bad_prop_vec->pv_prop,
141 			    pgroup_str);
142 		}
143 		return (B_FALSE);
144 	}
145 
146 	return (B_TRUE);
147 }
148 
149 /*
150  * free_prop_vect() - deallocate heap memory used for propvect values.
151  */
152 static void
153 free_prop_vect(void)
154 {
155 	scf_propvec_t	*prop_vect_ptr;
156 
157 	prop_vect_ptr = prop_vect;
158 
159 	while (prop_vect_ptr->pv_prop != NULL) {
160 		if (stack_inbounds(prop_vect_ptr->pv_ptr) == 0) {
161 			free(prop_vect_ptr->pv_ptr);
162 		}
163 		prop_vect_ptr++;
164 	}
165 }
166 
167 /*
168  * chk_prop_vect() - check for prop_vect boundaries and possibly process
169  * (typically) full prop_vect.
170  */
171 static boolean_t
172 chk_prop_vect(scf_propvec_t **prop_vect_ptr, char *pgrp_str)
173 {
174 	if (*prop_vect_ptr < prop_vect ||
175 	    *prop_vect_ptr >= (prop_vect + MAX_PROPVECS)) {
176 		DPRINT((dbfp, "prop_vect is full; flushing\n"));
177 		if (!set_val_scf(prop_vect, pgrp_str)) {
178 			return (B_FALSE);
179 		}
180 		free_prop_vect();
181 		bzero(prop_vect, sizeof (prop_vect));
182 		*prop_vect_ptr = prop_vect;
183 	}
184 	return (B_TRUE);
185 }
186 
187 /*
188  * get_props_kva_all() - get all properties and fill in the plugin_kva.
189  */
190 static boolean_t
191 get_props_kva_all(asi_scfhandle_t *handle, asi_scfhandle_iter_t *handle_iter,
192     kva_t **plugin_kva)
193 {
194 	char		key_buf[PLUGIN_MAXKEY];
195 	char		val_buf[PLUGIN_MAXVAL];
196 	char		attr_string[PLUGIN_MAXATT];
197 	char		attr_buf[PLUGIN_MAXATT];
198 	int		len = 0;
199 	scf_type_t	prop_type;
200 
201 	attr_string[0] = 0;
202 	attr_buf[0] = 0;
203 
204 	while (scf_iter_next_property(handle_iter->prop, handle->prop) == 1) {
205 		if (scf_property_get_name(handle->prop, key_buf,
206 		    PLUGIN_MAXKEY) == -1) {
207 			prt_scf_err();
208 			return (B_FALSE);
209 		}
210 
211 		/*
212 		 * We do not fully support multi-valued properties.
213 		 * scf_property_get_value() only supports single-valued
214 		 * properties. It returns SCF_ERROR_CONSTRAINT_VIOLATED and one
215 		 * of the property values. The audit service configuration
216 		 * values are all single-valued properties. The authorizations
217 		 * to configure and read the audit service properties may be
218 		 * multi-valued, these may safely be ignored here as not an
219 		 * error.
220 		 */
221 		if (scf_property_get_value(handle->prop,
222 		    handle_iter->prop_val) != 0 &&
223 		    scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) {
224 			prt_scf_err();
225 			return (B_FALSE);
226 		}
227 		if (scf_property_type(handle->prop, &prop_type) == -1) {
228 			prt_scf_err();
229 			return (B_FALSE);
230 		}
231 		switch (prop_type) {
232 		case SCF_TYPE_BOOLEAN: {
233 			uint8_t	pval_bool;
234 			if (scf_value_get_boolean(handle_iter->prop_val,
235 			    &pval_bool) == -1) {
236 				prt_scf_err();
237 				return (B_FALSE);
238 			}
239 			len = snprintf(attr_buf, PLUGIN_MAXATT, "%s=%d;",
240 			    key_buf, pval_bool);
241 			if (len < 0 || len >= PLUGIN_MAXATT) {
242 				prt_error(gettext("Too long attribute: %s\n"),
243 				    key_buf);
244 				return (B_FALSE);
245 			}
246 			if (strlcat(attr_string, attr_buf, PLUGIN_MAXATT) >=
247 			    PLUGIN_MAXATT) {
248 				prt_error(gettext("Too long attribute string: "
249 				    "%s\n"), key_buf);
250 				return (B_FALSE);
251 			}
252 			break;
253 		}
254 		case SCF_TYPE_ASTRING: {
255 			if (scf_value_get_as_string(handle_iter->prop_val,
256 			    val_buf, PLUGIN_MAXATT) == -1) {
257 				prt_scf_err();
258 				return (B_FALSE);
259 			}
260 			len = snprintf(attr_buf, PLUGIN_MAXATT, "%s=%s;",
261 			    key_buf, val_buf);
262 			if (len < 0 || len >= PLUGIN_MAXATT) {
263 				prt_error(gettext("Too long attribute: %s\n"),
264 				    key_buf);
265 				return (B_FALSE);
266 			}
267 			if (strlcat(attr_string, attr_buf, PLUGIN_MAXATT) >=
268 			    PLUGIN_MAXATT) {
269 				prt_error(gettext("Too long attribute string: "
270 				    "%s\n"), key_buf);
271 				return (B_FALSE);
272 			}
273 			break;
274 		}
275 		case SCF_TYPE_COUNT: {
276 			uint64_t	pval_count;
277 			if (scf_value_get_count(handle_iter->prop_val,
278 			    &pval_count) == -1) {
279 				prt_scf_err();
280 				return (B_FALSE);
281 			}
282 			len = snprintf(attr_buf, PLUGIN_MAXATT, "%s=%llu;",
283 			    key_buf, pval_count);
284 			if (len < 0 || len >= PLUGIN_MAXATT) {
285 				prt_error(gettext("Too long attribute: %s\n"),
286 				    key_buf);
287 				return (B_FALSE);
288 			}
289 			if (strlcat(attr_string, attr_buf, PLUGIN_MAXATT) >=
290 			    PLUGIN_MAXATT) {
291 				prt_error(gettext("Too long attribute string: "
292 				    "%s\n"), key_buf);
293 				return (B_FALSE);
294 			}
295 			break;
296 		}
297 		default:
298 			(void) printf("Unsupported value type %s [%d]\n",
299 			    key_buf, prop_type);
300 			break;
301 		}
302 	}
303 
304 	if (*attr_string == '\0' ||
305 	    (*plugin_kva = _str2kva(attr_string, "=", ";")) == NULL) {
306 		prt_error(gettext("Empty or invalid attribute string."));
307 		return (B_FALSE);
308 	}
309 
310 	return (B_TRUE);
311 }
312 
313 /*
314  * get_plugin_kva() - get and save config attributes of given plugin plugin_str
315  * (or all plugins in case plugin_str == NULL) into scf_plugin_kva_node_t.
316  */
317 static boolean_t
318 get_plugin_kva(asi_scfhandle_t *handle, asi_scfhandle_iter_t *handle_iter,
319     scf_plugin_kva_node_t **plugin_kva_ll, char *plugin_str)
320 {
321 
322 	scf_plugin_kva_node_t	*node = NULL;
323 	scf_plugin_kva_node_t	*node_prev = NULL;
324 	scf_plugin_kva_node_t	*node_head = NULL;
325 	char			plugin_str_tmp[PLUGIN_MAXBUF];
326 
327 	bzero(plugin_str_tmp, PLUGIN_MAXBUF);
328 
329 	if (scf_iter_instance_pgs_typed(handle_iter->pgrp, handle->inst,
330 	    (const char *)"plugin") == -1) {
331 		prt_scf_err();
332 		return (B_FALSE);
333 	}
334 
335 	while (scf_iter_next_pg(handle_iter->pgrp, handle->pgrp) == 1) {
336 		if (scf_pg_get_name(handle->pgrp, plugin_str_tmp,
337 		    PLUGIN_MAXBUF) == -1) {
338 			prt_scf_err();
339 			plugin_kva_ll_free(node);
340 			return (B_FALSE);
341 		}
342 
343 		if (plugin_str != NULL &&
344 		    strcmp(plugin_str_tmp, plugin_str) != 0) {
345 			continue;
346 		}
347 
348 		if ((node =
349 		    calloc(1, sizeof (scf_plugin_kva_node_t))) == NULL) {
350 			prt_error(gettext("No available memory."));
351 			plugin_kva_ll_free(node_prev);
352 			return (B_FALSE);
353 		}
354 		if (node_head == NULL) {
355 			node_head = node;
356 		}
357 		if (node_prev != NULL) {
358 			node_prev->next = node;
359 			node->prev = node_prev;
360 		}
361 		node_prev = node;
362 
363 		(void) strlcat((char *)&(node->plugin_name), plugin_str_tmp,
364 		    PLUGIN_MAXBUF);
365 
366 		if (scf_iter_pg_properties(handle_iter->prop,
367 		    handle->pgrp) != 0) {
368 			prt_scf_err();
369 			plugin_kva_ll_free(node);
370 			return (B_FALSE);
371 		}
372 
373 		if (!get_props_kva_all(handle, handle_iter,
374 		    &(node->plugin_kva))) {
375 			plugin_kva_ll_free(node);
376 			return (B_FALSE);
377 		}
378 	}
379 
380 #if DEBUG
381 	{
382 		scf_plugin_kva_node_t	*node_debug = node_head;
383 		char			attr_string[PLUGIN_MAXATT];
384 
385 		while (node_debug != NULL) {
386 			if (_kva2str(node_debug->plugin_kva, attr_string,
387 			    PLUGIN_MAXATT, "=", ";") == 0) {
388 				DPRINT((dbfp, "Found plugin - %s: %s\n",
389 				    node_debug->plugin_name, attr_string));
390 			} else {
391 				DPRINT((dbfp, "Could not get attribute string "
392 				    "for %s\n", node_debug->plugin_name));
393 			}
394 			node_debug = node_debug->prev;
395 		}
396 	}
397 #endif
398 
399 	*plugin_kva_ll = node_head;
400 
401 	return (B_TRUE);
402 }
403 
404 /*
405  * scf_free() - free scf handles
406  */
407 static void
408 scf_free(asi_scfhandle_t *handle)
409 {
410 	if (handle == NULL) {
411 		return;
412 	}
413 
414 	if (handle->prop != NULL) {
415 		scf_property_destroy(handle->prop);
416 	}
417 	if (handle->pgrp != NULL) {
418 		scf_pg_destroy(handle->pgrp);
419 	}
420 	if (handle->inst != NULL) {
421 		scf_instance_destroy(handle->inst);
422 	}
423 	if (handle->hndl != NULL) {
424 		if (scf_handle_unbind(handle->hndl) == -1) {
425 			prt_error(gettext("Internal error."));
426 			prt_scf_err();
427 		}
428 		scf_handle_destroy(handle->hndl);
429 	}
430 }
431 
432 /*
433  * scf_init() - initiate scf handles
434  */
435 static boolean_t
436 scf_init(asi_scfhandle_t *handle)
437 {
438 	bzero(handle, sizeof (asi_scfhandle_t));
439 
440 	if ((handle->hndl = scf_handle_create(SCF_VERSION)) == NULL ||
441 	    scf_handle_bind(handle->hndl) != 0) {
442 		goto err_out;
443 	}
444 	if ((handle->inst = scf_instance_create(handle->hndl)) == NULL) {
445 		goto err_out;
446 	}
447 	if ((handle->pgrp = scf_pg_create(handle->hndl)) == NULL) {
448 		goto err_out;
449 	}
450 	if ((handle->prop = scf_property_create(handle->hndl)) == NULL) {
451 		goto err_out;
452 	}
453 
454 	return (B_TRUE);
455 
456 err_out:
457 	prt_scf_err();
458 	scf_free(handle);
459 	return (B_FALSE);
460 }
461 
462 /*
463  * scf_free_iter() - free scf iter handles
464  */
465 static void
466 scf_free_iter(asi_scfhandle_iter_t *handle_iter)
467 {
468 	if (handle_iter == NULL) {
469 		return;
470 	}
471 
472 	if (handle_iter->pgrp != NULL) {
473 		scf_iter_destroy(handle_iter->pgrp);
474 	}
475 	if (handle_iter->prop != NULL) {
476 		scf_iter_destroy(handle_iter->prop);
477 	}
478 	if (handle_iter->prop_val != NULL) {
479 		scf_value_destroy(handle_iter->prop_val);
480 	}
481 }
482 
483 /*
484  * scf_init_iter() - initiate scf iter handles
485  */
486 static boolean_t
487 scf_init_iter(asi_scfhandle_iter_t *handle_iter,
488     asi_scfhandle_t *handle)
489 {
490 	bzero(handle_iter, sizeof (asi_scfhandle_iter_t));
491 
492 	if ((handle_iter->pgrp = scf_iter_create(handle->hndl)) == NULL) {
493 		goto err_out;
494 	}
495 	if ((handle_iter->prop = scf_iter_create(handle->hndl)) == NULL) {
496 		goto err_out;
497 	}
498 	if ((handle_iter->prop_val = scf_value_create(handle->hndl)) == NULL) {
499 		goto err_out;
500 	}
501 
502 	return (B_TRUE);
503 
504 err_out:
505 	prt_scf_err();
506 	scf_free_iter(handle_iter);
507 	return (B_FALSE);
508 }
509 
510 /*
511  * chk_policy_context() - does some policy based checks, checks the context
512  * (zone, smf) in which the policy could make some sense.
513  */
514 static boolean_t
515 chk_policy_context(char *policy_str)
516 {
517 
518 	/*
519 	 * "all" and "none" policy flags, since they represent
520 	 * sub/set of auditing policies, are not stored in the
521 	 * AUDITD_FMRI service instance configuration.
522 	 */
523 	DPRINT((dbfp, "Walking policy - %s: ", policy_str));
524 	if (strcmp("all", policy_str) == 0 ||
525 	    strcmp("none", policy_str) == 0) {
526 		DPRINT((dbfp, "skipped\n"));
527 		return (B_FALSE);
528 	}
529 	/*
530 	 * In the local zone (!= GLOBAL_ZONEID) we do not touch
531 	 * "ahlt" and "perzone" policy flags, since these are
532 	 * relevant only in the global zone.
533 	 */
534 	if ((getzoneid() != GLOBAL_ZONEID) &&
535 	    (strcmp("ahlt", policy_str) == 0 ||
536 	    strcmp("perzone", policy_str) == 0)) {
537 		DPRINT((dbfp, "skipped\n"));
538 		return (B_FALSE);
539 	}
540 
541 	return (B_TRUE);
542 }
543 
544 /*
545  * free_static_att_kva() - free hardcoded/static plugin attributes (key/value
546  * pairs) from the kva plugin structure.
547  */
548 void
549 free_static_att_kva(kva_t *plugin_kva)
550 {
551 	_kva_free_value(plugin_kva, PLUGIN_ACTIVE);
552 	_kva_free_value(plugin_kva, PLUGIN_PATH);
553 	_kva_free_value(plugin_kva, PLUGIN_QSIZE);
554 	_kva_free_value(plugin_kva, "read_authorization");
555 	_kva_free_value(plugin_kva, "value_authorization");
556 }
557 
558 
559 /*
560  * do_getqctrl_scf() - get the values of qctrl properties of the audit service
561  */
562 boolean_t
563 do_getqctrl_scf(struct au_qctrl *cval)
564 {
565 	scf_propvec_t   	*prop_vect_ptr;
566 	scf_qctrl_t		cval_scf;
567 
568 	bzero(prop_vect, sizeof (prop_vect));
569 
570 	prop_vect_ptr = prop_vect;
571 	add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QHIWATER,
572 	    SCF_TYPE_COUNT, &cval_scf.scf_qhiwater);
573 	add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QLOWATER,
574 	    SCF_TYPE_COUNT, &cval_scf.scf_qlowater);
575 	add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QBUFSZ,
576 	    SCF_TYPE_COUNT, &cval_scf.scf_qbufsz);
577 	add_prop_vect_scf(prop_vect_ptr, QUEUECTRL_QDELAY,
578 	    SCF_TYPE_COUNT, &cval_scf.scf_qdelay);
579 
580 	if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) {
581 		return (B_FALSE);
582 	}
583 
584 	cval->aq_hiwater = (size_t)cval_scf.scf_qhiwater;
585 	cval->aq_lowater = (size_t)cval_scf.scf_qlowater;
586 	cval->aq_bufsz = (size_t)cval_scf.scf_qbufsz;
587 	cval->aq_delay = (clock_t)cval_scf.scf_qdelay;
588 
589 	scf_clean_propvec(prop_vect);
590 
591 	return (B_TRUE);
592 }
593 
594 /*
595  * do_getqbufsz_scf() - get the qbufsz audit service property value
596  */
597 boolean_t
598 do_getqbufsz_scf(size_t *cval)
599 {
600 	uint64_t	cval_l;
601 
602 	bzero(prop_vect, sizeof (prop_vect));
603 	add_prop_vect_scf(prop_vect, QUEUECTRL_QBUFSZ, SCF_TYPE_COUNT, &cval_l);
604 
605 	if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) {
606 		return (B_FALSE);
607 	}
608 
609 	*cval = (size_t)cval_l;
610 
611 	return (B_TRUE);
612 }
613 
614 /*
615  * do_getqdelay_scf() - get the qdelay audit service property value
616  */
617 boolean_t
618 do_getqdelay_scf(clock_t *cval)
619 {
620 	uint64_t	cval_l;
621 
622 	bzero(prop_vect, sizeof (prop_vect));
623 	add_prop_vect_scf(prop_vect, QUEUECTRL_QDELAY, SCF_TYPE_COUNT, &cval_l);
624 
625 	if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) {
626 		return (B_FALSE);
627 	}
628 
629 	*cval = (clock_t)cval_l;
630 
631 	return (B_TRUE);
632 }
633 
634 /*
635  * do_getqhiwater_scf() - get the qhiwater audit service property value
636  */
637 boolean_t
638 do_getqhiwater_scf(size_t *cval)
639 {
640 	uint64_t	cval_l;
641 
642 	bzero(prop_vect, sizeof (prop_vect));
643 	add_prop_vect_scf(prop_vect, QUEUECTRL_QHIWATER, SCF_TYPE_COUNT,
644 	    &cval_l);
645 
646 	if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) {
647 		return (B_FALSE);
648 	}
649 
650 	*cval = (size_t)cval_l;
651 
652 	return (B_TRUE);
653 }
654 
655 /*
656  * do_getqlowater_scf() - get the qlowater audit service property value
657  */
658 boolean_t
659 do_getqlowater_scf(size_t *cval)
660 {
661 	uint64_t	cval_l;
662 
663 	bzero(prop_vect, sizeof (prop_vect));
664 	add_prop_vect_scf(prop_vect, QUEUECTRL_QLOWATER, SCF_TYPE_COUNT,
665 	    &cval_l);
666 
667 	if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) {
668 		return (B_FALSE);
669 	}
670 
671 	*cval = (size_t)cval_l;
672 
673 	return (B_TRUE);
674 }
675 
676 /*
677  * do_getpolicy_scf() - get the audit policy flags from service
678  */
679 boolean_t
680 do_getpolicy_scf(uint32_t *policy_mask)
681 {
682 	int			i;
683 	scf_propvec_t		*prop_vect_ptr;
684 	char			*cur_policy_str;
685 	policy_sw_t		policy_arr[POLICY_TBL_SZ + 1];
686 	policy_sw_t		*policy_arr_ptr;
687 
688 	prop_vect_ptr = prop_vect;
689 	policy_arr_ptr = policy_arr;
690 
691 	bzero(prop_vect, sizeof (prop_vect));
692 	bzero(policy_arr, sizeof (policy_arr));
693 
694 	/* prepare the smf(5) query */
695 	for (i = 0; i < POLICY_TBL_SZ; i++) {
696 
697 		cur_policy_str = policy_table[i].policy_str;
698 
699 		/* Do some basic policy dependent checks */
700 		if (!chk_policy_context(cur_policy_str)) {
701 			continue;
702 		}
703 		DPRINT((dbfp, "will be queried\n"));
704 
705 		add_prop_vect_scf(prop_vect_ptr++, cur_policy_str,
706 		    SCF_TYPE_BOOLEAN, &policy_arr_ptr->flag);
707 
708 		policy_arr_ptr->policy = cur_policy_str;
709 		policy_arr_ptr++;
710 
711 	}
712 	if (!get_val_scf(prop_vect, ASI_PGROUP_POLICY)) {
713 		return (B_FALSE);
714 	}
715 
716 	/* set the policy mask */
717 	policy_arr_ptr = policy_arr;
718 	*policy_mask = 0;
719 	while (policy_arr_ptr->policy != NULL) {
720 		if (policy_arr_ptr->flag) {
721 			*policy_mask |= get_policy(policy_arr_ptr->policy);
722 		}
723 		policy_arr_ptr++;
724 	}
725 
726 	return (B_TRUE);
727 }
728 
729 /*
730  * do_setpolicy_scf() - sets the policy flags in audit service configuration
731  */
732 boolean_t
733 do_setpolicy_scf(uint32_t policy)
734 {
735 	int		i;
736 	char		*cur_policy_str;
737 	scf_propvec_t	*prop_vect_ptr;
738 	boolean_t	bool_arr[POLICY_TBL_SZ];
739 	boolean_t	*bool_arr_ptr;
740 
741 	prop_vect_ptr = prop_vect;
742 	bool_arr_ptr = bool_arr;
743 
744 	bzero(prop_vect, sizeof (prop_vect));
745 	bzero(bool_arr, sizeof (bool_arr));
746 
747 	for (i = 0; i < POLICY_TBL_SZ; i++) {
748 
749 		cur_policy_str = policy_table[i].policy_str;
750 
751 		/* Do some basic policy dependent checks */
752 		if (!chk_policy_context(cur_policy_str)) {
753 			continue;
754 		}
755 
756 		if (policy_table[i].policy_mask & policy) {
757 			*bool_arr_ptr = B_TRUE;
758 		} else {
759 			*bool_arr_ptr = B_FALSE;
760 		}
761 
762 		DPRINT((dbfp, "%s%s\n", (*bool_arr_ptr == B_TRUE ? "+" : "-"),
763 		    cur_policy_str));
764 
765 		add_prop_vect_scf(prop_vect_ptr++, cur_policy_str,
766 		    SCF_TYPE_BOOLEAN, bool_arr_ptr++);
767 
768 	}
769 
770 	return (set_val_scf(prop_vect, ASI_PGROUP_POLICY));
771 }
772 
773 /*
774  * do_setqctrl_scf() - set the values of qctrl properties of the audit service
775  */
776 boolean_t
777 do_setqctrl_scf(struct au_qctrl *cval)
778 {
779 	scf_propvec_t		*prop_vect_ptr;
780 	scf_qctrl_t		cval_scf;
781 
782 	if (!CHK_BDRY_QHIWATER(cval->aq_lowater, cval->aq_hiwater) &&
783 	    cval->aq_hiwater != 0) {
784 		(void) printf(gettext("Specified audit queue hiwater mark is "
785 		    "outside of allowed boundaries.\n"));
786 		return (B_FALSE);
787 	}
788 	if (!CHK_BDRY_QLOWATER(cval->aq_lowater, cval->aq_hiwater) &&
789 	    cval->aq_lowater != 0) {
790 		(void) printf(gettext("Specified audit queue lowater mark is "
791 		    "outside of allowed boundaries.\n"));
792 		return (B_FALSE);
793 	}
794 	if (!CHK_BDRY_QBUFSZ(cval->aq_bufsz) && cval->aq_bufsz != 0) {
795 		(void) printf(gettext("Specified audit queue buffer size is "
796 		    "outside of allowed boundaries.\n"));
797 		return (B_FALSE);
798 	}
799 	if (!CHK_BDRY_QDELAY(cval->aq_delay) && cval->aq_delay != 0) {
800 		(void) printf(gettext("Specified audit queue delay is "
801 		    "outside of allowed boundaries.\n"));
802 		return (B_FALSE);
803 	}
804 
805 	cval_scf.scf_qhiwater = (uint64_t)cval->aq_hiwater;
806 	cval_scf.scf_qlowater = (uint64_t)cval->aq_lowater;
807 	cval_scf.scf_qbufsz = (uint64_t)cval->aq_bufsz;
808 	cval_scf.scf_qdelay = (uint64_t)cval->aq_delay;
809 
810 	bzero(prop_vect, sizeof (prop_vect));
811 
812 	prop_vect_ptr = prop_vect;
813 	add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QHIWATER, SCF_TYPE_COUNT,
814 	    &cval_scf.scf_qhiwater);
815 	add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QLOWATER, SCF_TYPE_COUNT,
816 	    &cval_scf.scf_qlowater);
817 	add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QBUFSZ, SCF_TYPE_COUNT,
818 	    &cval_scf.scf_qbufsz);
819 	add_prop_vect_scf(prop_vect_ptr, QUEUECTRL_QDELAY, SCF_TYPE_COUNT,
820 	    &cval_scf.scf_qdelay);
821 
822 	return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL));
823 }
824 
825 /*
826  * do_setqbufsz_scf() - set the qbufsz property value of the audit service
827  */
828 boolean_t
829 do_setqbufsz_scf(size_t *cval)
830 {
831 	uint64_t	cval_l;
832 
833 	if (!CHK_BDRY_QBUFSZ(*cval) && *cval != 0) {
834 		(void) printf(gettext("Specified audit queue buffer size is "
835 		    "outside of allowed boundaries.\n"));
836 		return (B_FALSE);
837 	}
838 
839 	cval_l = (uint64_t)*cval;
840 
841 	bzero(prop_vect, sizeof (prop_vect));
842 	add_prop_vect_scf(prop_vect, QUEUECTRL_QBUFSZ, SCF_TYPE_COUNT, &cval_l);
843 
844 	return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL));
845 }
846 
847 /*
848  * do_setqdelay_scf() - set the qdelay property value of the audit service
849  */
850 boolean_t
851 do_setqdelay_scf(clock_t *cval)
852 {
853 	uint64_t	cval_l;
854 
855 	if (!CHK_BDRY_QDELAY(*cval) && *cval != 0) {
856 		(void) printf(gettext("Specified audit queue delay is "
857 		    "outside of allowed boundaries.\n"));
858 		return (B_FALSE);
859 	}
860 
861 	cval_l = (uint64_t)*cval;
862 
863 	bzero(prop_vect, sizeof (prop_vect));
864 	add_prop_vect_scf(prop_vect, QUEUECTRL_QDELAY, SCF_TYPE_COUNT, &cval_l);
865 
866 	return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL));
867 }
868 
869 /*
870  * do_setqhiwater_scf() - set the qhiwater property value of the audit service
871  */
872 boolean_t
873 do_setqhiwater_scf(size_t *cval)
874 {
875 	uint64_t	cval_l;
876 	size_t		cval_lowater;
877 
878 	if (!do_getqlowater_scf(&cval_lowater)) {
879 		(void) printf(gettext("Could not get configured value of "
880 		    "queue lowater mark.\n"));
881 		return (B_FALSE);
882 	}
883 	if (cval_lowater == 0) {
884 		cval_lowater = AQ_MINLOW;
885 	}
886 	if (!CHK_BDRY_QHIWATER(cval_lowater, *cval) && *cval != 0) {
887 		(void) printf(gettext("Specified audit queue hiwater mark is "
888 		    "outside of allowed boundaries.\n"));
889 		return (B_FALSE);
890 	}
891 
892 	cval_l = (uint64_t)*cval;
893 
894 	bzero(prop_vect, sizeof (prop_vect));
895 	add_prop_vect_scf(prop_vect, QUEUECTRL_QHIWATER, SCF_TYPE_COUNT,
896 	    &cval_l);
897 
898 	return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL));
899 }
900 
901 /*
902  * do_setqlowater_scf() - set the qlowater property value of the audit service
903  */
904 boolean_t
905 do_setqlowater_scf(size_t *cval)
906 {
907 	uint64_t	cval_l;
908 	size_t		cval_hiwater;
909 
910 	if (!do_getqhiwater_scf(&cval_hiwater)) {
911 		(void) printf(gettext("Could not get configured value of "
912 		    "queue hiwater mark.\n"));
913 		return (B_FALSE);
914 	}
915 	if (cval_hiwater == 0) {
916 		cval_hiwater = AQ_MAXHIGH;
917 	}
918 	if (!CHK_BDRY_QLOWATER(*cval, cval_hiwater) && *cval != 0) {
919 		(void) printf(gettext("Specified audit queue lowater mark is "
920 		    "outside of allowed boundaries.\n"));
921 		return (B_FALSE);
922 	}
923 
924 	cval_l = (uint64_t)*cval;
925 
926 	bzero(prop_vect, sizeof (prop_vect));
927 	add_prop_vect_scf(prop_vect, QUEUECTRL_QLOWATER, SCF_TYPE_COUNT,
928 	    &cval_l);
929 
930 	return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL));
931 }
932 
933 /*
934  * do_getflags_scf() - get the audit attributable flags from service
935  */
936 boolean_t
937 do_getflags_scf(char **flags)
938 {
939 	bzero(prop_vect, sizeof (prop_vect));
940 	add_prop_vect_scf(prop_vect, PRESELECTION_FLAGS, SCF_TYPE_ASTRING,
941 	    flags);
942 
943 	if (!get_val_scf(prop_vect, ASI_PGROUP_PRESELECTION)) {
944 		return (B_FALSE);
945 	}
946 
947 	return (B_TRUE);
948 }
949 
950 /*
951  * do_getnaflags_scf() - get the audit non-attributable flags from service
952  */
953 boolean_t
954 do_getnaflags_scf(char **naflags)
955 {
956 	bzero(prop_vect, sizeof (prop_vect));
957 	add_prop_vect_scf(prop_vect, PRESELECTION_NAFLAGS, SCF_TYPE_ASTRING,
958 	    naflags);
959 
960 	if (!get_val_scf(prop_vect, ASI_PGROUP_PRESELECTION)) {
961 		return (B_FALSE);
962 	}
963 
964 	return (B_TRUE);
965 }
966 
967 /*
968  * do_setflags_scf() - set the attributable mask property value of the audit
969  * service
970  */
971 boolean_t
972 do_setflags_scf(char *flags)
973 {
974 	bzero(prop_vect, sizeof (prop_vect));
975 	add_prop_vect_scf(prop_vect, PRESELECTION_FLAGS, SCF_TYPE_ASTRING,
976 	    flags);
977 
978 	return (set_val_scf(prop_vect, ASI_PGROUP_PRESELECTION));
979 }
980 
981 /*
982  * do_setnaflags_scf() - set the attributable mask property value of the audit
983  * service
984  */
985 boolean_t
986 do_setnaflags_scf(char *naflags)
987 {
988 	bzero(prop_vect, sizeof (prop_vect));
989 	add_prop_vect_scf(prop_vect, PRESELECTION_NAFLAGS, SCF_TYPE_ASTRING,
990 	    naflags);
991 
992 	return (set_val_scf(prop_vect, ASI_PGROUP_PRESELECTION));
993 }
994 
995 /*
996  * plugin_avail_scf() - look for the plugin in the audit service configuration
997  */
998 boolean_t
999 plugin_avail_scf(const char *plugin_str)
1000 {
1001 	scf_simple_handle_t	*sh;
1002 
1003 	if (plugin_str == NULL || *plugin_str == '\0') {
1004 		return (B_FALSE);
1005 	}
1006 
1007 	if ((sh = scf_general_pg_setup(AUDITD_FMRI, plugin_str)) == NULL) {
1008 		DPRINT((dbfp, "No such plugin found: %s (%s)\n", plugin_str,
1009 		    scf_strerror(scf_error())));
1010 		return (B_FALSE);
1011 	}
1012 
1013 	scf_simple_handle_destroy(sh);
1014 	return (B_TRUE);
1015 }
1016 
1017 /*
1018  * do_getpluginconfig_scf() - get plugin configuration from the audit service
1019  * configuration.
1020  */
1021 boolean_t
1022 do_getpluginconfig_scf(char *plugin_str, scf_plugin_kva_node_t **plugin_kva_ll)
1023 {
1024 
1025 	char			*asi_fmri;
1026 	asi_scfhandle_t		handle;
1027 	asi_scfhandle_iter_t	handle_iter;
1028 	boolean_t		plugin_all = B_FALSE;
1029 	boolean_t		rv = B_TRUE;
1030 
1031 	if (plugin_str == NULL || *plugin_str == '\0') {
1032 		if (asprintf(&asi_fmri, "%s", AUDITD_FMRI) == -1) {
1033 			prt_error(gettext("Out of memory."));
1034 			return (B_FALSE);
1035 		}
1036 		plugin_all = B_TRUE;
1037 	} else {
1038 		if (asprintf(&asi_fmri, "%s%s%s", AUDITD_FMRI,
1039 		    SCF_FMRI_PROPERTYGRP_PREFIX, plugin_str) == -1) {
1040 			prt_error(gettext("Out of memory."));
1041 			return (B_FALSE);
1042 		}
1043 	}
1044 	DPRINT((dbfp, "%s will be decoded\n", asi_fmri));
1045 
1046 	if (!scf_init(&handle)) {
1047 		prt_error(gettext("Unable to initialize scf handles."));
1048 		free(asi_fmri);
1049 		return (B_FALSE);
1050 	}
1051 
1052 	if (scf_handle_decode_fmri(handle.hndl, asi_fmri, NULL, NULL,
1053 	    handle.inst, plugin_all ? NULL : handle.pgrp, NULL,
1054 	    SCF_DECODE_FMRI_EXACT) == -1) {
1055 		prt_scf_err();
1056 		scf_free(&handle);
1057 		free(asi_fmri);
1058 		return (B_FALSE);
1059 	}
1060 
1061 	if (!scf_init_iter(&handle_iter, &handle)) {
1062 		prt_error(gettext("Unable to initialize scf iter handles."));
1063 		scf_free(&handle);
1064 		free(asi_fmri);
1065 		return (B_FALSE);
1066 	}
1067 
1068 
1069 	if (plugin_all) {
1070 		rv = get_plugin_kva(&handle, &handle_iter, plugin_kva_ll, NULL);
1071 	} else {
1072 		rv = get_plugin_kva(&handle, &handle_iter, plugin_kva_ll,
1073 		    plugin_str);
1074 	}
1075 
1076 	scf_free(&handle);
1077 	scf_free_iter(&handle_iter);
1078 	free(asi_fmri);
1079 	return (rv);
1080 }
1081 
1082 /*
1083  * do_setpluginconfig_scf() - set plugin configuration in the audit service
1084  * configuration.
1085  */
1086 boolean_t
1087 do_setpluginconfig_scf(char *plugin_str, boolean_t plugin_state,
1088     char *plugin_att, int plugin_qsize)
1089 {
1090 	kva_t			*plugin_att_kva = NULL;
1091 	char			*plugin_att_ptr = plugin_att;
1092 	char			*plugin_att_clr_ptr = plugin_att;
1093 	scf_simple_prop_t	*plugin_prop;
1094 	scf_type_t		plugin_prop_type;
1095 	scf_propvec_t		*prop_vect_ptr;
1096 	int			cnt = 0;
1097 	kv_t			*data;
1098 	boolean_t		rval = B_TRUE;
1099 	uint64_t		plugin_qsize_l = (uint64_t)plugin_qsize;
1100 
1101 	DPRINT((dbfp, "Auditd plugin configuration to be set:\n\tplugin=%s\n\t"
1102 	    "state=%d (%s)\n\tattributes=%s\n\tqsize=%d%s\n", plugin_str,
1103 	    plugin_state, plugin_state == B_TRUE ? "active" : "inactive",
1104 	    plugin_att == NULL ? " (unspecified)" : plugin_att,
1105 	    plugin_qsize, plugin_qsize == -1 ? " (unspecified)" : ""));
1106 
1107 	bzero(prop_vect, sizeof (prop_vect));
1108 	prop_vect_ptr = prop_vect;
1109 
1110 	if (plugin_att != NULL) {
1111 
1112 		/* get rid of white-space chars */
1113 		if (*plugin_att_ptr != '\0') {
1114 			while (*plugin_att_ptr != '\0') {
1115 				if (isspace(*plugin_att_ptr) == 0) {
1116 					*plugin_att_clr_ptr++ = *plugin_att_ptr;
1117 				}
1118 				plugin_att_ptr++;
1119 			}
1120 			*plugin_att_clr_ptr = '\0';
1121 		}
1122 		DPRINT((dbfp, "attributes (no white-space): %s\n", plugin_att));
1123 
1124 		/* allow empty plugin_att */
1125 		if (*plugin_att == '\0') {
1126 			cnt = 0;
1127 			data = NULL;
1128 		} else {
1129 			plugin_att_kva = _str2kva(plugin_att, "=", ";");
1130 			if (plugin_att_kva == NULL) {
1131 				prt_error(gettext("Could not parse plugin "
1132 				    "attributes."));
1133 				return (B_FALSE);
1134 			}
1135 
1136 			free_static_att_kva(plugin_att_kva);
1137 			cnt = plugin_att_kva->length;
1138 			data = plugin_att_kva->data;
1139 		}
1140 	}
1141 
1142 	/* set state */
1143 	add_prop_vect_scf(prop_vect_ptr++, PLUGIN_ACTIVE, SCF_TYPE_BOOLEAN,
1144 	    &plugin_state);
1145 	DPRINT((dbfp, "Prepared active -> %d\n", plugin_state));
1146 
1147 	/* set attributes */
1148 	while (cnt) {
1149 		if (data->value == NULL) {
1150 			cnt--;
1151 			data++;
1152 			continue;
1153 		}
1154 		if (!chk_prop_vect(&prop_vect_ptr, plugin_str)) {
1155 			rval = B_FALSE;
1156 			goto err_out;
1157 		}
1158 
1159 		if ((plugin_prop = scf_simple_prop_get(NULL,
1160 		    AUDITD_FMRI, plugin_str, data->key)) == NULL) {
1161 			prt_error(gettext("Could not get configuration for "
1162 			    "attribute: %s"), data->key);
1163 			prt_scf_err();
1164 			rval = B_FALSE;
1165 			goto err_out;
1166 		}
1167 		if ((plugin_prop_type = scf_simple_prop_type(plugin_prop))
1168 		    == -1) {
1169 			prt_error(gettext("Could not get property type: %s"),
1170 			    data->key);
1171 			prt_scf_err();
1172 			rval = B_FALSE;
1173 			goto err_out;
1174 		}
1175 
1176 		switch (plugin_prop_type) {
1177 		case SCF_TYPE_BOOLEAN: {
1178 			uint8_t	*pval_bool;
1179 			pval_bool = (uint8_t *)malloc(sizeof (uint8_t));
1180 			if (pval_bool == NULL) {
1181 				prt_error(gettext("No free memory available."));
1182 				rval = B_FALSE;
1183 				goto err_out;
1184 			}
1185 			*pval_bool = (uint8_t)atoi(data->value);
1186 			add_prop_vect_scf(prop_vect_ptr++, data->key,
1187 			    SCF_TYPE_BOOLEAN, pval_bool);
1188 			break;
1189 		}
1190 		case SCF_TYPE_ASTRING: {
1191 			char	*pval_str;
1192 			if ((pval_str = strdup(data->value)) == NULL) {
1193 				prt_error(gettext("No free memory available."));
1194 				rval = B_FALSE;
1195 				goto err_out;
1196 			}
1197 			add_prop_vect_scf(prop_vect_ptr++, data->key,
1198 			    SCF_TYPE_ASTRING, pval_str);
1199 			break;
1200 		}
1201 		case SCF_TYPE_COUNT: {
1202 			uint64_t	*pval_count;
1203 			pval_count = (uint64_t *)malloc(sizeof (uint64_t));
1204 			if (pval_count == NULL) {
1205 				prt_error(gettext("No free memory available."));
1206 				rval = B_FALSE;
1207 				goto err_out;
1208 			}
1209 			*pval_count = (uint64_t)atoll(data->value);
1210 			add_prop_vect_scf(prop_vect_ptr++, data->key,
1211 			    SCF_TYPE_COUNT, pval_count);
1212 			break;
1213 		}
1214 		default:
1215 			prt_error(gettext("Unsupported property type: %s (%d)"),
1216 			    data->key, plugin_prop_type);
1217 			break;
1218 		}
1219 
1220 		DPRINT((dbfp, "Prepared %s -> %s\n", data->key, data->value));
1221 		scf_simple_prop_free(plugin_prop);
1222 		data++;
1223 		cnt--;
1224 	}
1225 
1226 	if (!chk_prop_vect(&prop_vect_ptr, plugin_str)) {
1227 		rval = B_FALSE;
1228 		goto err_out;
1229 	}
1230 
1231 	/* set qsize */
1232 	if (plugin_qsize != -1) {
1233 		add_prop_vect_scf(prop_vect_ptr, PLUGIN_QSIZE, SCF_TYPE_COUNT,
1234 		    &plugin_qsize_l);
1235 		DPRINT((dbfp, "Prepared qsize -> %d\n", plugin_qsize));
1236 	}
1237 
1238 	if (!set_val_scf(prop_vect, plugin_str)) {
1239 		rval = B_FALSE;
1240 	}
1241 
1242 err_out:
1243 	free_prop_vect();
1244 	_kva_free(plugin_att_kva);
1245 	return (rval);
1246 }
1247 
1248 /*
1249  * plugin_kva_ll_free() - free the memory used by plugin kva linked list.
1250  */
1251 void
1252 plugin_kva_ll_free(scf_plugin_kva_node_t *node)
1253 {
1254 	scf_plugin_kva_node_t *node_next;
1255 
1256 	if (node == NULL) {
1257 		return;
1258 	}
1259 
1260 	while (node->prev != NULL) {
1261 		node = node->prev;
1262 	}
1263 	while (node != NULL) {
1264 		_kva_free(node->plugin_kva);
1265 		node_next = node->next;
1266 		free(node);
1267 		node = node_next;
1268 	}
1269 }
1270 
1271 /*
1272  * get_policy() - get policy mask entry
1273  */
1274 uint32_t
1275 get_policy(char *policy)
1276 {
1277 	int i;
1278 
1279 	for (i = 0; i < POLICY_TBL_SZ; i++) {
1280 		if (strcasecmp(policy, policy_table[i].policy_str) == 0) {
1281 			return (policy_table[i].policy_mask);
1282 		}
1283 	}
1284 
1285 	return (0);
1286 }
1287