audit_scf.c revision 12918:32a41a5f8110
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 */
30scf_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*/
39static void
40prt_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*/
58void
59prt_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 */
72static void
73prt_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 */
83static void
84add_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 */
99static boolean_t
100get_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 */
129static boolean_t
130set_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 */
152static void
153free_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 */
171static boolean_t
172chk_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 */
190static boolean_t
191get_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 */
317static boolean_t
318get_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 */
407static void
408scf_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 */
435static boolean_t
436scf_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
456err_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 */
465static void
466scf_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 */
486static boolean_t
487scf_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
504err_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 */
514static boolean_t
515chk_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 */
548void
549free_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 */
562boolean_t
563do_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 */
597boolean_t
598do_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 */
617boolean_t
618do_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 */
637boolean_t
638do_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 */
658boolean_t
659do_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 */
679boolean_t
680do_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 */
732boolean_t
733do_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 */
776boolean_t
777do_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 */
828boolean_t
829do_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 */
850boolean_t
851do_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 */
872boolean_t
873do_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 */
904boolean_t
905do_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 */
936boolean_t
937do_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 */
953boolean_t
954do_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 */
971boolean_t
972do_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 */
985boolean_t
986do_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 */
998boolean_t
999plugin_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 */
1021boolean_t
1022do_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 */
1086boolean_t
1087do_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
1242err_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 */
1251void
1252plugin_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 */
1274uint32_t
1275get_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