1/*-
2 * Copyright (c) 2004 Apple Inc.
3 * Copyright (c) 2006 Robert N. M. Watson
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1.  Redistributions of source code must retain the above copyright
10 *     notice, this list of conditions and the following disclaimer.
11 * 2.  Redistributions in binary form must reproduce the above copyright
12 *     notice, this list of conditions and the following disclaimer in the
13 *     documentation and/or other materials provided with the distribution.
14 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15 *     its contributors may be used to endorse or promote products derived
16 *     from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <config/config.h>
32
33#include <bsm/libbsm.h>
34
35#include <errno.h>
36#include <stdio.h>
37#include <string.h>
38
39#ifndef HAVE_STRLCPY
40#include <compat/strlcpy.h>
41#endif
42
43static const char	*flagdelim = ",";
44
45/*
46 * Convert the character representation of audit values into the au_mask_t
47 * field.
48 */
49int
50getauditflagsbin(char *auditstr, au_mask_t *masks)
51{
52	char class_ent_name[AU_CLASS_NAME_MAX];
53	char class_ent_desc[AU_CLASS_DESC_MAX];
54	struct au_class_ent c;
55	char *tok;
56	char sel, sub;
57	char *last;
58
59	bzero(&c, sizeof(c));
60	bzero(class_ent_name, sizeof(class_ent_name));
61	bzero(class_ent_desc, sizeof(class_ent_desc));
62	c.ac_name = class_ent_name;
63	c.ac_desc = class_ent_desc;
64
65	masks->am_success = 0;
66	masks->am_failure = 0;
67
68	tok = strtok_r(auditstr, flagdelim, &last);
69	while (tok != NULL) {
70		/* Check for the events that should not be audited. */
71		if (tok[0] == '^') {
72			sub = 1;
73			tok++;
74		} else
75			sub = 0;
76
77		/* Check for the events to be audited for success. */
78		if (tok[0] == '+') {
79			sel = AU_PRS_SUCCESS;
80			tok++;
81		} else if (tok[0] == '-') {
82			sel = AU_PRS_FAILURE;
83			tok++;
84		} else
85			sel = AU_PRS_BOTH;
86
87		if ((getauclassnam_r(&c, tok)) != NULL) {
88			if (sub)
89				SUB_FROM_MASK(masks, c.ac_class, sel);
90			else
91				ADD_TO_MASK(masks, c.ac_class, sel);
92		} else {
93			errno = EINVAL;
94			return (-1);
95		}
96
97		/* Get the next class. */
98		tok = strtok_r(NULL, flagdelim, &last);
99	}
100	return (0);
101}
102
103/*
104 * Convert the au_mask_t fields into a string value.  If verbose is non-zero
105 * the long flag names are used else the short (2-character)flag names are
106 * used.
107 *
108 * XXXRW: If bits are specified that are not matched by any class, they are
109 * omitted rather than rejected with EINVAL.
110 *
111 * XXXRW: This is not thread-safe as it relies on atomicity between
112 * setauclass() and sequential calls to getauclassent().  This could be
113 * fixed by iterating through the bitmask fields rather than iterating
114 * through the classes.
115 */
116int
117getauditflagschar(char *auditstr, au_mask_t *masks, int verbose)
118{
119	char class_ent_name[AU_CLASS_NAME_MAX];
120	char class_ent_desc[AU_CLASS_DESC_MAX];
121	struct au_class_ent c;
122	char *strptr = auditstr;
123	u_char sel;
124
125	bzero(&c, sizeof(c));
126	bzero(class_ent_name, sizeof(class_ent_name));
127	bzero(class_ent_desc, sizeof(class_ent_desc));
128	c.ac_name = class_ent_name;
129	c.ac_desc = class_ent_desc;
130
131	/*
132	 * Enumerate the class entries, check if each is selected in either
133	 * the success or failure masks.
134	 */
135	setauclass();
136	while ((getauclassent_r(&c)) != NULL) {
137		sel = 0;
138
139		/* Dont do anything for class = no. */
140		if (c.ac_class == 0)
141			continue;
142
143		sel |= ((c.ac_class & masks->am_success) == c.ac_class) ?
144		    AU_PRS_SUCCESS : 0;
145		sel |= ((c.ac_class & masks->am_failure) == c.ac_class) ?
146		    AU_PRS_FAILURE : 0;
147
148		/*
149		 * No prefix should be attached if both success and failure
150		 * are selected.
151		 */
152		if ((sel & AU_PRS_BOTH) == 0) {
153			if ((sel & AU_PRS_SUCCESS) != 0) {
154				*strptr = '+';
155				strptr = strptr + 1;
156			} else if ((sel & AU_PRS_FAILURE) != 0) {
157				*strptr = '-';
158				strptr = strptr + 1;
159			}
160		}
161
162		if (sel != 0) {
163			if (verbose) {
164				strlcpy(strptr, c.ac_desc, AU_CLASS_DESC_MAX);
165				strptr += strlen(c.ac_desc);
166			} else {
167				strlcpy(strptr, c.ac_name, AU_CLASS_NAME_MAX);
168				strptr += strlen(c.ac_name);
169			}
170			*strptr = ','; /* delimiter */
171			strptr = strptr + 1;
172		}
173	}
174
175	/* Overwrite the last delimiter with the string terminator. */
176	if (strptr != auditstr)
177		*(strptr-1) = '\0';
178
179	return (0);
180}
181