2 * ausearch-report.c - Format and output events
3 * Copyright (c) 2005-09,2011-13 Red Hat Inc., Durham, North Carolina.
6 * This software may be freely redistributed and/or modified under the
7 * terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2, or (at your option) any
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING. If not, write to the
18 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Steve Grubb <sgrubb@redhat.com>
30 #include "ausearch-options.h"
31 #include "ausearch-parse.h"
32 #include "ausearch-lookup.h"
33 #include "auparse-idata.h"
34 #include "auparse-defs.h"
37 static void output_raw(llist *l);
38 static void output_default(llist *l);
39 static void output_interpreted(llist *l);
40 static void output_interpreted_node(const lnode *n, const event *e);
41 static void interpret(char *name, char *val, int comma, int rtype);
43 /* The machine based on elf type */
44 static unsigned long machine = -1;
45 static int cur_syscall = -1;
47 /* The first syscall argument */
48 static unsigned long long a0, a1;
50 /* This function branches to the correct output format */
51 void output_record(llist *l)
53 switch (report_format) {
61 output_interpreted(l);
66 fprintf(stderr, "Report format error");
71 /* This function will output the record as is */
72 static void output_raw(llist *l)
79 fprintf(stderr, "Error - no elements in record.");
83 printf("%s\n", n->message);
84 } while ((n=list_next(l)));
88 * This function will take the linked list and format it for output. No
89 * interpretation is performed. The output order is lifo for everything.
91 static void output_default(llist *l)
97 printf("----\ntime->%s", ctime(&l->e.sec));
99 fprintf(stderr, "Error - no elements in record.");
102 if (n->type >= AUDIT_DAEMON_START && n->type < AUDIT_SYSCALL)
103 printf("%s\n", n->message);
106 printf("%s\n", n->message);
107 } while ((n=list_prev(l)));
112 * This function will take the linked list and format it for output.
113 * Interpretation is performed to aid understanding of records. The output
114 * order is lifo for everything.
116 static void output_interpreted(llist *l)
124 fprintf(stderr, "Error - no elements in record.");
127 if (n->type >= AUDIT_DAEMON_START && n->type < AUDIT_SYSCALL)
128 output_interpreted_node(n, &(l->e));
131 output_interpreted_node(n, &(l->e));
132 } while ((n=list_prev(l)));
137 * This function will cycle through a single record and lookup each field's
138 * value that it finds.
140 static void output_interpreted_node(const lnode *n, const event *e)
142 char *ptr, *str = n->message;
143 int found, comma = 0;
148 // Reset these because each record could be different
152 /* Check and see if we start with a node
153 * If we do, and there is a space in the line
154 * move the pointer to the first character past
158 if ((ptr=strchr(str, ' ')) != NULL) {
163 // First locate time stamp.
164 ptr = strchr(str, '(');
166 fprintf(stderr, "can't find time stamp\n");
170 *ptr++ = 0; /* move to the start of the timestamp */
172 // print everything up to it.
175 bptr = audit_msg_type_to_name(num);
178 printf("node=%s ", e->node);
179 printf("type=%s msg=audit(", bptr);
184 printf("node=%s ", e->node);
188 str = strchr(ptr, ')');
192 btm = localtime(&e->sec);
193 strftime(tmp, sizeof(tmp), "%x %T", btm);
195 printf(".%03d:%lu) ", e->milli, e->serial);
197 if (n->type == AUDIT_SYSCALL) {
204 while (str && *str && (ptr = strchr(str, '='))) {
209 // look back to last space - this is name
211 while (*name != ' ' && name > str)
215 // print everything up to the '='
218 // Some user messages have msg='uid=500 in this case
219 // skip the msg= piece since the real stuff is the uid=
220 if (strcmp(name, "msg") == 0) {
225 // In the above case, after msg= we need to trim the ' from uid
229 // get string after = to the next space or end - this is value
230 if (*ptr == '\'' || *ptr == '"') {
231 str = strchr(ptr+1, *ptr);
238 str = strchr(ptr, ',');
239 val = strchr(ptr, ' ');
240 if (str && val && (str < val)) {
241 // Value side has commas and another field exists
242 // Known: LABEL_LEVEL_CHANGE banners=none,none
243 // Known: ROLL_ASSIGN new-role=r,r
244 // Known: any MAC LABEL can potentially have commas
245 int ftype = auparse_interp_adjust_type(n->type,
247 if (ftype == AUPARSE_TYPE_MAC_LABEL) {
254 } else if (str && (val == NULL)) {
255 // Goes all the way to the end. Done parsing
256 // Known: MCS context in PATH rec obj=u:r:t:s0:c2,c7
257 int ftype = auparse_interp_adjust_type(n->type,
259 if (ftype == AUPARSE_TYPE_MAC_LABEL)
266 // There is another field, point to next (normal path)
271 // val points to begin & str 1 past end
274 // print interpreted string
275 interpret(name, val, comma, n->type);
277 // If nothing found, just print out as is
278 if (!found && ptr == NULL && str)
280 // If last field had comma, output the rest
286 static void interpret(char *name, char *val, int comma, int rtype)
291 while (*name == ' '||*name == '(')
294 if (*name == 'a' && strcmp(name, "acct") == 0) {
295 // Remove trailing punctuation
296 int len = strlen(val);
297 if (val[len-1] == ':')
300 type = auparse_interp_adjust_type(rtype, name, val);
302 if (rtype == AUDIT_SYSCALL || rtype == AUDIT_SECCOMP) {
303 if (machine == (unsigned long)-1)
304 machine = audit_detect_machine();
305 if (*name == 'a' && strcmp(name, "arch") == 0) {
308 ival = strtoul(val, NULL, 16);
310 printf("arch conversion error(%s) ", val);
313 machine = audit_elf_to_machine(ival);
315 if (cur_syscall < 0 && *name == 's' &&
316 strcmp(name, "syscall") == 0) {
319 ival = strtoul(val, NULL, 10);
321 printf("syscall conversion error(%s) ", val);
326 id.syscall = cur_syscall;
329 id.machine = machine;
335 char *out = auparse_do_interpretation(type, &id);
336 if (type == AUPARSE_TYPE_UNCLASSIFIED)
337 printf("%s%c", val, comma ? ',' : ' ');
338 else if (name[0] == 'k' && strcmp(name, "key") == 0) {
339 char *str, *ptr = out;
341 while ((str = strchr(ptr, AUDIT_KEY_SEPARATOR))) {
347 printf(" key=%s", ptr);
353 printf(" key=%s ", ptr);
354 } else if (type == AUPARSE_TYPE_TTY_DATA)