Imported Upstream version 2.4.3
[platform/upstream/audit.git] / src / ausearch-lol.c
1 /*
2 * ausearch-lol.c - linked list of linked lists library
3 * Copyright (c) 2008,2010,2014 Red Hat Inc., Durham, North Carolina.
4 * All Rights Reserved. 
5 *
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
9 * later version.
10 *
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.
15 *
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.
19 *
20 * Authors:
21 *   Steve Grubb <sgrubb@redhat.com>
22 */
23
24 #include "ausearch-lol.h"
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include "ausearch-common.h"
30 #include "private.h"
31
32 #define ARRAY_LIMIT 80
33 static int ready = 0;
34
35 void lol_create(lol *lo)
36 {
37         int size = ARRAY_LIMIT * sizeof(lolnode);
38
39         lo->maxi = -1;
40         lo->limit = ARRAY_LIMIT;
41         lo->array = (lolnode *)malloc(size);
42         memset(lo->array, 0, size);
43 }
44
45 void lol_clear(lol *lo)
46 {
47         int i;
48
49         for (i=0; i<=lo->maxi; i++) {
50                 if (lo->array[i].status) {
51                         list_clear(lo->array[i].l);
52                         free(lo->array[i].l);
53                 }
54         }
55         free(lo->array);
56         lo->array = NULL;
57         lo->maxi = -1;
58 }
59
60 static void lol_append(lol *lo, llist *l)
61 {
62         int i;
63         size_t new_size;
64         lolnode *ptr;
65
66         for(i=0; i<lo->limit; i++) {
67                 lolnode *cur = &lo->array[i];
68                 if (cur->status == L_EMPTY) {
69                         cur->l = l;
70                         cur->status = L_BUILDING;
71                         if (i > lo->maxi)
72                                 lo->maxi = i;
73                         return;
74                 }
75         }
76         // Overran the array...lets make it bigger
77         new_size = sizeof(lolnode) * (lo->limit + ARRAY_LIMIT);
78         ptr = realloc(lo->array, new_size);
79         if (ptr) {
80                 lo->array = ptr;
81                 memset(&lo->array[lo->limit], 0, sizeof(lolnode) * ARRAY_LIMIT);
82                 lo->array[i].l = l;
83                 lo->array[i].status = L_BUILDING;
84                 lo->maxi = i;
85                 lo->limit += ARRAY_LIMIT;
86         }
87 }
88
89 static int str2event(char *s, event *e)
90 {
91         char *ptr;
92
93         errno = 0;
94         ptr = strchr(s+10, ':');
95         if (ptr) {
96                 e->serial = strtoul(ptr+1, NULL, 10);
97                 *ptr = 0;
98                 if (errno)
99                         return -1;
100         } else
101                 e->serial = 0;
102         ptr = strchr(s, '.');
103         if (ptr) {
104                 e->milli = strtoul(ptr+1, NULL, 10);
105                 *ptr = 0;
106                 if (errno)
107                         return -1;
108         } else
109                 e->milli = 0;
110         e->sec = strtoul(s, NULL, 10);
111         if (errno)
112                 return -1;
113         return 0;
114 }
115
116 static int inline events_are_equal(event *e1, event *e2)
117 {
118         if (!(e1->serial == e2->serial && e1->milli == e2->milli &&
119                                         e1->sec == e2->sec))
120                 return 0;
121         if (e1->node && e2->node) {
122                 if (strcmp(e1->node, e2->node))
123                         return 0;
124         } else if (e1->node || e2->node)
125                 return 0;
126         return 1;
127 }
128
129 /*
130  * This function will look at the line and pick out pieces of it.
131  */
132 static int extract_timestamp(const char *b, event *e)
133 {
134         char *ptr, *tmp, *tnode, *ttype;
135
136         e->node = NULL;
137         if (*b == 'n')
138                 tmp = strndupa(b, 340);
139         else
140                 tmp = strndupa(b, 80);
141         ptr = audit_strsplit(tmp);
142         if (ptr) {
143                 // Check to see if this is the node info
144                 if (*ptr == 'n') {
145                         tnode = ptr+5;
146                         ptr = audit_strsplit(NULL);
147                 } else
148                         tnode = NULL;
149
150                 // at this point we have type=
151                 ttype = ptr+5;
152
153                 // Now should be pointing to msg=
154                 ptr = audit_strsplit(NULL);
155                 if (ptr) {
156                         if (*(ptr+9) == '(')
157                                 ptr+=9;
158                         else
159                                 ptr = strchr(ptr, '(');
160                         if (ptr) {
161                         // now we should be pointed at the timestamp
162                                 char *eptr;
163                                 ptr++;
164                                 eptr = strchr(ptr, ')');
165                                 if (eptr)
166                                         *eptr = 0;
167                                 if (str2event(ptr, e)) {
168                                         fprintf(stderr,
169                                           "Error extracting time stamp (%s)\n",
170                                                 ptr);
171                                         return 0;
172                                 } else if ((start_time && e->sec < start_time)
173                                         || (end_time && e->sec > end_time))
174                                         return 0;
175                                 else {
176                                         if (tnode)
177                                                 e->node = strdup(tnode);
178                                         e->type = audit_name_to_msg_type(ttype);
179                                 }
180                                 return 1;
181                         }
182                         // else we have a bad line
183                 }
184                 // else we have a bad line
185         }
186         // else we have a bad line
187         return 0;
188 }
189
190 // This function will check events to see if they are complete 
191 // FIXME: Can we think of other ways to determine if the event is done?
192 static void check_events(lol *lo, time_t sec)
193 {
194         int i;
195
196         for(i=0;i<=lo->maxi; i++) {
197                 lolnode *cur = &lo->array[i];
198                 if (cur->status == L_BUILDING) {
199                         // If 2 seconds have elapsed, we are done
200                         if (cur->l->e.sec + 2 < sec) { 
201                                 cur->status = L_COMPLETE;
202                                 ready++;
203                         } else if (cur->l->e.type < AUDIT_FIRST_EVENT ||
204                                     cur->l->e.type >= AUDIT_FIRST_ANOM_MSG) {
205                                 // If known to be 1 record event, we are done
206                                 cur->status = L_COMPLETE;
207                                 ready++;
208                         } 
209                 }
210         }
211 }
212
213 // This function adds a new record to an existing linked list
214 // or creates a new one if its a new event
215 int lol_add_record(lol *lo, char *buff)
216 {
217         int i;
218         lnode n;
219         event e;
220         char *ptr;
221         llist *l;
222
223         // Short circuit if event is not of interest
224         if (extract_timestamp(buff, &e) == 0)
225                 return 0;
226
227         ptr = strrchr(buff, 0x0a);
228         if (ptr)
229                 *ptr = 0;
230         n.message=strdup(buff);
231         n.type = e.type;
232
233         // Now see where this belongs
234         for (i=0; i<=lo->maxi; i++) {
235                 if (lo->array[i].status == L_BUILDING) {
236                         l = lo->array[i].l;
237                         if (events_are_equal(&l->e, &e)) {
238                                 free((char *)e.node);
239                                 list_append(l, &n);
240                                 return 1;
241                         }
242                 }
243         }
244         // Create new event and fill it in
245         l = malloc(sizeof(llist));
246         list_create(l);
247         l->e.milli = e.milli;
248         l->e.sec = e.sec;
249         l->e.serial = e.serial;
250         l->e.node = e.node;
251         l->e.type = e.type;
252         list_append(l, &n);
253         lol_append(lo, l);
254         check_events(lo,  e.sec);
255         return 1;
256 }
257
258 // This function will mark all events as "done"
259 void terminate_all_events(lol *lo)
260 {
261         int i;
262
263         for (i=0; i<=lo->maxi; i++) {
264                 lolnode *cur = &lo->array[i];
265                 if (cur->status == L_BUILDING) {
266                         cur->status = L_COMPLETE;
267                         ready++;
268                 }
269         }
270 //printf("maxi = %d\n",lo->maxi);
271 }
272
273 /* Search the list for any event that is ready to go. The caller
274  * takes custody of the memory */
275 llist* get_ready_event(lol *lo)
276 {
277         int i;
278
279         if (ready == 0)
280                 return NULL;
281
282         for (i=0; i<=lo->maxi; i++) {
283                 lolnode *cur = &lo->array[i];
284                 if (cur->status == L_COMPLETE) {
285                         cur->status = L_EMPTY;
286                         ready--;
287                         return cur->l;
288                 }
289         }
290
291         return NULL;
292 }
293