Imported Upstream version 2.4.3
[platform/upstream/audit.git] / auparse / ellist.c
1 /*
2 * ellist.c - Minimal linked list library
3 * Copyright (c) 2006-08,2014 Red Hat Inc., Durham, North Carolina.
4 * All Rights Reserved. 
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 *
20 * Authors:
21 *   Steve Grubb <sgrubb@redhat.com>
22 */
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include <libaudit.h>
29 #include "ellist.h"
30 #include "interpret.h"
31
32 static const char key_sep[2] = { AUDIT_KEY_SEPARATOR, 0 };
33
34 void aup_list_create(event_list_t *l)
35 {
36         l->head = NULL;
37         l->cur = NULL;
38         l->cnt = 0;
39         l->e.milli = 0L;       
40         l->e.sec = 0L;         
41         l->e.serial = 0L;
42         l->e.host = NULL;
43 }
44
45 static void aup_list_last(event_list_t *l)
46 {
47         register rnode* window;
48         
49         if (l->head == NULL)
50                 return;
51
52         window = l->head;
53         while (window->next)
54                 window = window->next;
55         l->cur = window;
56 }
57
58 rnode *aup_list_next(event_list_t *l)
59 {
60         if (l->cur)
61                 l->cur = l->cur->next;
62         return l->cur;
63 }
64
65 /*
66  *  * This function does encoding of "untrusted" names just like the kernel
67  *   */
68 static char *_audit_c2x(char *final, const char *buf, unsigned int size)
69 {
70         unsigned int i;
71         char *ptr = final;
72         const char *hex = "0123456789ABCDEF";
73
74         for (i=0; i<size; i++) {
75                 *ptr++ = hex[(buf[i] & 0xF0)>>4]; /* Upper nibble */
76                 *ptr++ = hex[buf[i] & 0x0F];      /* Lower nibble */
77         }
78         *ptr = 0;
79         return final;
80 }
81
82 static char *escape(const char *tmp)
83 {
84         char *name;
85         const unsigned char *p = (unsigned char *)tmp;
86         while (*p) {
87                 if (*p == '"' || *p < 0x21 || *p > 0x7e) {
88                         int len = strlen(tmp);
89                         name = malloc((2*len)+1);
90                         return _audit_c2x(name, tmp, len);
91                 }
92                 p++;
93         }
94         if (asprintf(&name, "\"%s\"", tmp) < 0)
95                 name = NULL;
96         return name;
97 }
98
99 /* This funtion does the heavy duty work of splitting a record into
100  * its little tiny pieces */
101 static int parse_up_record(rnode* r)
102 {
103         char *ptr, *buf, *saved=NULL;
104         int offset = 0;
105
106         buf = strdup(r->record);
107         ptr = audit_strsplit_r(buf, &saved);
108         if (ptr == NULL) {
109                 free(buf);
110                 return -1;
111         }
112
113         do {    // If there's an '=' sign, its a keeper
114                 nvnode n;
115                 char *val = strchr(ptr, '=');
116                 if (val) {
117                         int len;
118
119                         // If name is 'msg=audit' throw it away
120                         if (*ptr == 'm' && strncmp(ptr, "msg=", 4) == 0) {
121                                 if (ptr[4] == 'a')
122                                         continue;
123
124                                 // If name is 'msg='' chop off and see
125                                 // if there is still a = in the string.
126                                 else if (ptr[4] == '\'') {
127                                         ptr += 5;
128                                         val = strchr(ptr, '=');
129                                         if (val == NULL)
130                                                 continue;
131                                 }
132                         }
133
134                         // Split the string
135                         *val = 0;
136                         val++;
137
138                         // Remove beginning cruft of name
139                         if (*ptr == '(')
140                                 ptr++;
141                         n.name = strdup(ptr);
142                         n.val = strdup(val);
143                         // Remove trailing punctuation
144                         len = strlen(n.val);
145                         if (len && n.val[len-1] == ':') {
146                                 n.val[len-1] = 0;
147                                 len--;
148                         }
149                         if (len && n.val[len-1] == ',') {
150                                 n.val[len-1] = 0;
151                                 len--;
152                         }
153                         if (len && n.val[len-1] == '\'') {
154                                 n.val[len-1] = 0;
155                                 len--;
156                         }
157                         if (len && n.val[len-1] == ')') {
158                                 if (strcmp(n.val, "(none)") &&
159                                         strcmp(n.val, "(null)")) {
160                                         n.val[len-1] = 0;
161                                         len--;
162                                 }
163                         }
164                         // Make virtual keys or just store it
165                         if (strcmp(n.name, "key") == 0 && *n.val != '(') {
166                                 if (*n.val == '"')
167                                         nvlist_append(&r->nv, &n);
168                                 else {
169                                         char *key, *ptr, *saved2 = NULL;
170
171                                         key = (char *)au_unescape(n.val);
172                                         if (key == NULL) {
173                                                 // Malformed key - save as is
174                                                 nvlist_append(&r->nv, &n);
175                                                 continue;
176                                         }
177                                         ptr = strtok_r(key, key_sep, &saved2);
178                                         free(n.name);
179                                         free(n.val);
180                                         while (ptr) {
181                                                 n.name = strdup("key");
182                                                 n.val = escape(ptr);
183                                                 nvlist_append(&r->nv, &n);
184                                                 ptr = strtok_r(NULL,
185                                                         key_sep, &saved2);
186                                         }
187                                         free(key);
188                                 }
189                                 continue;
190                         } else
191                                 nvlist_append(&r->nv, &n);
192
193                         // Do some info gathering for use later
194                         if (r->nv.cnt == 1 && strcmp(n.name, "node") == 0)
195                                 offset = 1; // if node, some positions changes
196                         else if (r->nv.cnt == (1 + offset) &&
197                                         strcmp(n.name, "type") == 0) {
198                                 r->type = audit_name_to_msg_type(n.val);
199                         } else if (r->nv.cnt == (2 + offset) && 
200                                         strcmp(n.name, "arch")== 0){
201                                 unsigned int ival;
202                                 errno = 0;
203                                 ival = strtoul(n.val, NULL, 16);
204                                 if (errno)
205                                         r->machine = -2;
206                                 else
207                                         r->machine = audit_elf_to_machine(ival);
208                         } else if (r->nv.cnt == (3 + offset) &&
209                                         strcmp(n.name, "syscall") == 0){
210                                 errno = 0;
211                                 r->syscall = strtoul(n.val, NULL, 10);
212                                 if (errno)
213                                         r->syscall = -1;
214                         } else if (r->nv.cnt == (6 + offset) &&
215                                         strcmp(n.name, "a0") == 0){
216                                 errno = 0;
217                                 r->a0 = strtoull(n.val, NULL, 16);
218                                 if (errno)
219                                         r->a0 = -1LL;
220                         } else if (r->nv.cnt == (7 + offset) &&
221                                         strcmp(n.name, "a1") == 0){
222                                 errno = 0;
223                                 r->a1 = strtoull(n.val, NULL, 16);
224                                 if (errno)
225                                         r->a1 = -1LL;
226                         }
227                 } else if (r->type == AUDIT_AVC || r->type == AUDIT_USER_AVC) {
228                         // We special case these 2 fields because selinux
229                         // avc messages do not label these fields.
230                         n.name = NULL;
231                         if (nvlist_get_cnt(&r->nv) == (1 + offset)) {
232                                 // skip over 'avc:'
233                                 if (strncmp(ptr, "avc", 3) == 0)
234                                         continue;
235                                 n.name = strdup("seresult");
236                         } else if (nvlist_get_cnt(&r->nv) == (2 + offset)) {
237                                 // skip over open brace
238                                 if (*ptr == '{') {
239                                         int total = 0, len;
240                                         char tmpctx[256], *to;
241                                         tmpctx[0] = 0;
242                                         to = tmpctx;
243                                         ptr = audit_strsplit_r(NULL, &saved);
244                                         while (ptr && *ptr != '}') {
245                                                 len = strlen(ptr);
246                                                 if ((len+1) >= (256-total)) {
247                                                         free(buf);
248                                                         return -1;
249                                                 }
250                                                 if (tmpctx[0]) {
251                                                         to = stpcpy(to, ",");
252                                                         total++;
253                                                 }
254                                                 to = stpcpy(to, ptr);
255                                                 total += len;
256                                                 ptr = audit_strsplit_r(NULL,
257                                                                  &saved);
258                                         }
259                                         n.name = strdup("seperms");
260                                         n.val = strdup(tmpctx);
261                                         nvlist_append(&r->nv, &n);
262                                         continue;
263                                 }
264                         } else
265                                 continue;
266                         n.val = strdup(ptr);
267                         nvlist_append(&r->nv, &n);
268                 }
269                 // FIXME: There should be an else here to catch ancillary data
270         } while((ptr = audit_strsplit_r(NULL, &saved)));
271
272         free(buf);
273         r->nv.cur = r->nv.head; // reset to beginning
274         return 0;
275 }
276
277 int aup_list_append(event_list_t *l, char *record, int list_idx,
278         unsigned int line_number)
279 {
280         rnode* r;
281
282         if (record == NULL)
283                 return -1;
284
285         // First step is build rnode
286         r = malloc(sizeof(rnode));
287         if (r == NULL)
288                 return -1;
289
290         r->record = record;
291         r->type = 0;
292         r->a0 = 0LL;
293         r->a1 = 0LL;
294         r->machine = -1;
295         r->syscall = -1;
296         r->item = l->cnt; 
297         r->list_idx = list_idx;
298         r->line_number = line_number;
299         r->next = NULL;
300         nvlist_create(&r->nv);
301
302         // if we are at top, fix this up
303         if (l->head == NULL)
304                 l->head = r;
305         else {  // Otherwise add pointer to newnode
306                 aup_list_last(l);
307                 l->cur->next = r;
308         }
309
310         // make newnode current
311         l->cur = r;
312         l->cnt++;
313
314         // Then parse the record up into nvlist
315         return parse_up_record(r);      
316 }
317
318 void aup_list_clear(event_list_t* l)
319 {
320         rnode* nextnode;
321         register rnode* current;
322
323         if (l == NULL)
324                 return;
325
326         current = l->head;
327         while (current) {
328                 nextnode=current->next;
329                 nvlist_clear(&current->nv);
330                 free(current->record);
331                 free(current);
332                 current=nextnode;
333         }
334         l->head = NULL;
335         l->cur = NULL;
336         l->cnt = 0;
337         l->e.milli = 0L;       
338         l->e.sec = 0L;         
339         l->e.serial = 0L;
340         free((char *)l->e.host);
341         l->e.host = NULL;      
342 }
343
344 /*int aup_list_get_event(event_list_t* l, au_event_t *e)
345 {
346         if (l == NULL || e == NULL)
347                 return 0;
348
349         e->sec = l->e.sec;
350         e->milli = l->e.milli;
351         e->serial = l->e.serial;
352         if (l->e.host)
353                 e->host = strdup(l->e.host);
354         else
355                 e->host = NULL;
356         return 1;
357 } */
358
359 int aup_list_set_event(event_list_t* l, au_event_t *e)
360 {
361         if (l == NULL || e == NULL)
362                 return 0;
363
364         l->e.sec = e->sec;
365         l->e.milli = e->milli;
366         l->e.serial = e->serial;
367         l->e.host = e->host;    // Take custody of the memory
368         e->host = NULL;
369         return 1;
370 }
371
372 rnode *aup_list_find_rec(event_list_t *l, int i)
373 {
374         register rnode* window;
375                                                                                 
376         window = l->head;       /* start at the beginning */
377         while (window) {
378                 if (window->type == i) {
379                         l->cur = window;
380                         return window;
381                 } else
382                         window = window->next;
383         }
384         return NULL;
385 }
386
387 rnode *aup_list_goto_rec(event_list_t *l, int i)
388 {
389         register rnode* window;
390                                                                                 
391         window = l->head;       /* start at the beginning */
392         while (window) {
393                 if (window->item == i) {
394                         l->cur = window;
395                         return window;
396                 } else
397                         window = window->next;
398         }
399         return NULL;
400 }
401
402 rnode *aup_list_find_rec_range(event_list_t *l, int low, int high)
403 {
404         register rnode* window;
405
406         if (high <= low)
407                 return NULL;
408
409         window = l->head;       /* Start at the beginning */
410         while (window) {
411                 if (window->type >= low && window->type <= high) {
412                         l->cur = window;
413                         return window;
414                 } else
415                         window = window->next;
416         }
417         return NULL;
418 }
419
420 int aup_list_first_field(event_list_t *l)
421 {
422         if (l->cur) {
423                 nvlist_first(&l->cur->nv);
424                 return 1;
425         } else
426                 return 0;
427 }
428