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 * $P4: //depot/projects/trustedbsd/openbsm/libbsm/bsm_flags.c#16 $
31 */
32
33#include <config/config.h>
34
35#include <bsm/libbsm.h>
36
37#include <errno.h>
38#include <stdio.h>
39#include <string.h>
40
41#ifndef HAVE_STRLCPY
42#include <compat/strlcpy.h>
43#endif
44
45static const char	*flagdelim = ",";
46
47/*
48 * Convert the character representation of audit values into the au_mask_t
49 * field.
50 */
51int
52getauditflagsbin(char *auditstr, au_mask_t *masks)
53{
54	char class_ent_name[AU_CLASS_NAME_MAX];
55	char class_ent_desc[AU_CLASS_DESC_MAX];
56	struct au_class_ent c;
57	char *tok;
58	char sel, sub;
59	char *last;
60
61	bzero(&c, sizeof(c));
62	bzero(class_ent_name, sizeof(class_ent_name));
63	bzero(class_ent_desc, sizeof(class_ent_desc));
64	c.ac_name = class_ent_name;
65	c.ac_desc = class_ent_desc;
66
67	masks->am_success = 0;
68	masks->am_failure = 0;
69
70	tok = strtok_r(auditstr, flagdelim, &last);
71	while (tok != NULL) {
72		/* Check for the events that should not be audited. */
73		if (tok[0] == '^') {
74			sub = 1;
75			tok++;
76		} else
77			sub = 0;
78
79		/* Check for the events to be audited for success. */
80		if (tok[0] == '+') {
81			sel = AU_PRS_SUCCESS;
82			tok++;
83		} else if (tok[0] == '-') {
84			sel = AU_PRS_FAILURE;
85			tok++;
86		} else
87			sel = AU_PRS_BOTH;
88
89		if ((getauclassnam_r(&c, tok)) != NULL) {
90			if (sub)
91				SUB_FROM_MASK(masks, c.ac_class, sel);
92			else
93				ADD_TO_MASK(masks, c.ac_class, sel);
94		} else {
95			errno = EINVAL;
96			return (-1);
97		}
98
99		/* Get the next class. */
100		tok = strtok_r(NULL, flagdelim, &last);
101	}
102	return (0);
103}
104
105/*
106 * Convert the au_mask_t fields into a string value.  If verbose is non-zero
107 * the long flag names are used else the short (2-character)flag names are
108 * used.
109 *
110 * XXXRW: If bits are specified that are not matched by any class, they are
111 * omitted rather than rejected with EINVAL.
112 *
113 * XXXRW: This is not thread-safe as it relies on atomicity between
114 * setauclass() and sequential calls to getauclassent().  This could be
115 * fixed by iterating through the bitmask fields rather than iterating
116 * through the classes.
117 */
118int
119getauditflagschar(char *auditstr, au_mask_t *masks, int verbose)
120{
121	char class_ent_name[AU_CLASS_NAME_MAX];
122	char class_ent_desc[AU_CLASS_DESC_MAX];
123	struct au_class_ent c;
124	char *strptr = auditstr;
125	u_char sel;
126
127	bzero(&c, sizeof(c));
128	bzero(class_ent_name, sizeof(class_ent_name));
129	bzero(class_ent_desc, sizeof(class_ent_desc));
130	c.ac_name = class_ent_name;
131	c.ac_desc = class_ent_desc;
132
133	/*
134	 * Enumerate the class entries, check if each is selected in either
135	 * the success or failure masks.
136	 */
137	setauclass();
138	while ((getauclassent_r(&c)) != NULL) {
139		sel = 0;
140
141		/* Dont do anything for class = no. */
142		if (c.ac_class == 0)
143			continue;
144
145		sel |= ((c.ac_class & masks->am_success) == c.ac_class) ?
146		    AU_PRS_SUCCESS : 0;
147		sel |= ((c.ac_class & masks->am_failure) == c.ac_class) ?
148		    AU_PRS_FAILURE : 0;
149
150		/*
151		 * No prefix should be attached if both success and failure
152		 * are selected.
153		 */
154		if ((sel & AU_PRS_BOTH) == 0) {
155			if ((sel & AU_PRS_SUCCESS) != 0) {
156				*strptr = '+';
157				strptr = strptr + 1;
158			} else if ((sel & AU_PRS_FAILURE) != 0) {
159				*strptr = '-';
160				strptr = strptr + 1;
161			}
162		}
163
164		if (sel != 0) {
165			if (verbose) {
166				strlcpy(strptr, c.ac_desc, AU_CLASS_DESC_MAX);
167				strptr += strlen(c.ac_desc);
168			} else {
169				strlcpy(strptr, c.ac_name, AU_CLASS_NAME_MAX);
170				strptr += strlen(c.ac_name);
171			}
172			*strptr = ','; /* delimiter */
173			strptr = strptr + 1;
174		}
175	}
176
177	/* Overwrite the last delimiter with the string terminator. */
178	if (strptr != auditstr)
179		*(strptr-1) = '\0';
180
181	return (0);
182}
183