Imported Upstream version 2.4.3
[platform/upstream/audit.git] / src / ausearch-lookup.c
1 /*
2 * ausearch-lookup.c - Lookup values to something more readable
3 * Copyright (c) 2005-06,2011-12 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 "config.h"
25 #include <stdio.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <stdlib.h>
29 #include <linux/net.h>
30 #include "ausearch-lookup.h"
31 #include "ausearch-options.h"
32 #include "ausearch-nvpair.h"
33
34 /* This is the name/value pair used by search tables */
35 struct nv_pair {
36         int        value;
37         const char *name;
38 };
39
40
41 /* The machine based on elf type */
42 static int machine = 0;
43 static const char *Q = "?";
44 static const char *results[3]= { "unset", "denied", "granted" };
45 static const char *success[3]= { "unset", "no", "yes" };
46 static const char *aulookup_socketcall(long sc);
47 static const char *aulookup_ipccall(long ic);
48
49 const char *aulookup_result(avc_t result)
50 {
51         return results[result];
52 }
53
54 const char *aulookup_success(int s)
55 {
56         switch (s)
57         {
58                 default:
59                         return success[0];
60                         break;
61                 case S_FAILED:
62                         return success[1];
63                         break;
64                 case S_SUCCESS:
65                         return success[2];
66                         break;
67         }
68 }
69
70 const char *aulookup_syscall(llist *l, char *buf, size_t size)
71 {
72         const char *sys;
73
74         if (report_format <= RPT_DEFAULT) {
75                 snprintf(buf, size, "%d", l->s.syscall);
76                 return buf;
77         }
78         machine = audit_elf_to_machine(l->s.arch);
79         if (machine < 0)
80                 return Q;
81         sys = audit_syscall_to_name(l->s.syscall, machine);
82         if (sys) {
83                 const char *func = NULL;
84                 if (strcmp(sys, "socketcall") == 0) {
85                         if (list_find_item(l, AUDIT_SYSCALL))
86                                 func = aulookup_socketcall((long)l->cur->a0);
87                 } else if (strcmp(sys, "ipc") == 0) {
88                         if(list_find_item(l, AUDIT_SYSCALL))
89                                 func = aulookup_ipccall((long)l->cur->a0);
90                 }
91                 if (func) {
92                         snprintf(buf, size, "%s(%s)", sys, func);
93                         return buf;
94                 }
95                 return sys;
96         }
97         snprintf(buf, size, "%d", l->s.syscall);
98         return buf;
99 }
100
101 // See include/linux/net.h
102 static struct nv_pair socktab[] = {
103         {SYS_SOCKET, "socket"},
104         {SYS_BIND, "bind"},
105         {SYS_CONNECT, "connect"},
106         {SYS_LISTEN, "listen"},
107         {SYS_ACCEPT, "accept"},
108         {SYS_GETSOCKNAME, "getsockname"},
109         {SYS_GETPEERNAME, "getpeername"},
110         {SYS_SOCKETPAIR, "socketpair"},
111         {SYS_SEND, "send"},
112         {SYS_RECV, "recv"},
113         {SYS_SENDTO, "sendto"},
114         {SYS_RECVFROM, "recvfrom"},
115         {SYS_SHUTDOWN, "shutdown"},
116         {SYS_SETSOCKOPT, "setsockopt"},
117         {SYS_GETSOCKOPT, "getsockopt"},
118         {SYS_SENDMSG, "sendmsg"},
119         {SYS_RECVMSG, "recvmsg"},
120         {SYS_ACCEPT4, "accept4"},
121         {19, "recvmmsg"},
122         {20, "sendmmsg"}
123 };
124 #define SOCK_NAMES (sizeof(socktab)/sizeof(socktab[0]))
125
126 static const char *aulookup_socketcall(long sc)
127 {
128         int i;
129
130         for (i = 0; i < SOCK_NAMES; i++)
131                 if (socktab[i].value == sc)
132                         return socktab[i].name;
133
134         return NULL;
135 }
136
137 /* This is from asm/ipc.h. Copying it for now as some platforms
138  * have broken headers. */
139 #define SEMOP            1
140 #define SEMGET           2
141 #define SEMCTL           3
142 #define SEMTIMEDOP       4
143 #define MSGSND          11
144 #define MSGRCV          12
145 #define MSGGET          13
146 #define MSGCTL          14
147 #define SHMAT           21
148 #define SHMDT           22
149 #define SHMGET          23
150 #define SHMCTL          24
151
152 /*
153  * This table maps ipc calls to their text name
154  */
155 static struct nv_pair ipctab[] = {
156         {SEMOP, "semop"},
157         {SEMGET, "semget"},
158         {SEMCTL, "semctl"},
159         {SEMTIMEDOP, "semtimedop"},
160         {MSGSND, "msgsnd"},
161         {MSGRCV, "msgrcv"},
162         {MSGGET, "msgget"},
163         {MSGCTL, "msgctl"},
164         {SHMAT, "shmat"},
165         {SHMDT, "shmdt"},
166         {SHMGET, "shmget"},
167         {SHMCTL, "shmctl"}
168 };
169 #define IPC_NAMES (sizeof(ipctab)/sizeof(ipctab[0]))
170
171 static const char *aulookup_ipccall(long ic)
172 {
173         int i;
174
175         for (i = 0; i < IPC_NAMES; i++)
176                 if (ipctab[i].value == ic)
177                         return ipctab[i].name;
178
179         return NULL;
180
181
182 static nvlist uid_nvl;
183 static int uid_list_created=0;
184 const char *aulookup_uid(uid_t uid, char *buf, size_t size)
185 {
186         char *name = NULL;
187         int rc;
188
189         if (report_format <= RPT_DEFAULT) {
190                 snprintf(buf, size, "%d", uid);
191                 return buf;
192         }
193         if (uid == -1) {
194                 snprintf(buf, size, "unset");
195                 return buf;
196         }
197
198         // Check the cache first
199         if (uid_list_created == 0) {
200                 nvlist_create(&uid_nvl);
201                 nvlist_clear(&uid_nvl);
202                 uid_list_created = 1;
203         }
204         rc = nvlist_find_val(&uid_nvl, uid);
205         if (rc) {
206                 name = uid_nvl.cur->name;
207         } else {
208                 // Add it to cache
209                 struct passwd *pw;
210                 pw = getpwuid(uid);
211                 if (pw) {
212                         nvnode nv;
213                         nv.name = strdup(pw->pw_name);
214                         nv.val = uid;
215                         nvlist_append(&uid_nvl, &nv);
216                         name = uid_nvl.cur->name;
217                 }
218         }
219         if (name != NULL)
220                 snprintf(buf, size, "%s", name);
221         else
222                 snprintf(buf, size, "unknown(%d)", uid);
223         return buf;
224 }
225
226 void aulookup_destroy_uid_list(void)
227 {
228         if (uid_list_created == 0)
229                 return;
230
231         nvlist_clear(&uid_nvl); 
232         uid_list_created = 0;
233 }
234
235 static nvlist gid_nvl;
236 static int gid_list_created=0;
237 const char *aulookup_gid(gid_t gid, char *buf, size_t size)
238 {
239         char *name = NULL;
240         int rc;
241
242         if (report_format <= RPT_DEFAULT) {
243                 snprintf(buf, size, "%d", gid);
244                 return buf;
245         }
246         if (gid == -1) {
247                 snprintf(buf, size, "unset");
248                 return buf;
249         }
250
251         // Check the cache first
252         if (gid_list_created == 0) {
253                 nvlist_create(&gid_nvl);
254                 nvlist_clear(&gid_nvl);
255                 gid_list_created = 1;
256         }
257         rc = nvlist_find_val(&gid_nvl, gid);
258         if (rc) {
259                 name = gid_nvl.cur->name;
260         } else {
261                 // Add it to cache
262                 struct group *gr;
263                 gr = getgrgid(gid);
264                 if (gr) {
265                         nvnode nv;
266                         nv.name = strdup(gr->gr_name);
267                         nv.val = gid;
268                         nvlist_append(&gid_nvl, &nv);
269                         name = gid_nvl.cur->name;
270                 }
271         }
272         if (name != NULL)
273                 snprintf(buf, size, "%s", name);
274         else
275                 snprintf(buf, size, "unknown(%d)", gid);
276         return buf;
277 }
278
279 void aulookup_destroy_gid_list(void)
280 {
281         if (gid_list_created == 0)
282                 return;
283
284         nvlist_clear(&gid_nvl); 
285         gid_list_created = 0;
286 }
287
288 int is_hex_string(const char *str)
289 {
290         int c=0;
291         while (*str) {
292                 if (!isxdigit(*str))
293                         return 0;
294                 str++;
295                 c++;
296         }
297         return 1;
298 }
299 /*
300  * This function will take a pointer to a 2 byte Ascii character buffer and 
301  * return the actual hex value.
302  */
303 static unsigned char x2c(unsigned char *buf)
304 {
305         static const char AsciiArray[17] = "0123456789ABCDEF";
306         char *ptr;
307         unsigned char total=0;
308
309         ptr = strchr(AsciiArray, (char)toupper(buf[0]));
310         if (ptr)
311                 total = (unsigned char)(((ptr-AsciiArray) & 0x0F)<<4);
312         ptr = strchr(AsciiArray, (char)toupper(buf[1]));
313         if (ptr)
314                 total += (unsigned char)((ptr-AsciiArray) & 0x0F);
315
316         return total;
317 }
318
319 /* returns a freshly malloc'ed and converted buffer */
320 char *unescape(const char *buf)
321 {
322         int len, i;
323         char *str, *strptr;
324         const char *ptr = buf;
325
326         /* Find the end of the name */
327         if (*ptr == '(') {
328                 ptr = strchr(ptr, ')');
329                 if (ptr == NULL)
330                         return NULL;
331                 else
332                         ptr++;
333         } else {
334                 while (isxdigit(*ptr))
335                         ptr++;
336         }
337         str = strndup(buf, ptr - buf);
338
339         if (*buf == '(')
340                 return str;
341
342         /* We can get away with this since the buffer is 2 times
343          * bigger than what we are putting there.
344          */
345         len = strlen(str);
346         if (len < 2) {
347                 free(str);
348                 return NULL;
349         }
350         strptr = str;
351         for (i=0; i<len; i+=2) {
352                 *strptr = x2c((unsigned char *)&str[i]);
353                 strptr++;
354         }
355         *strptr = 0;
356         return str;
357 }
358
359 /* Represent c as a character within a quoted string, and append it to buf. */
360 static void tty_printable_char(unsigned char c)
361 {
362         if (c < 0x20 || c > 0x7E) {
363                 putchar('\\');
364                 putchar('0' + ((c >> 6) & 07));
365                 putchar('0' + ((c >> 3) & 07));
366                 putchar('0' + (c & 07));
367         } else {
368                 if (c == '\\' || c ==  '"')
369                         putchar('\\');
370                 putchar(c);
371         }
372 }
373
374 /* Search for a name of a sequence of TTY bytes.
375  *  If found, return the name and advance *INPUT.
376  *  Return NULL otherwise. 
377  */
378 static const char *tty_find_named_key(unsigned char **input, size_t input_len)
379 {
380         /* NUL-terminated list of (sequence, NUL, name, NUL) entries.
381            First match wins, even if a longer match were possible later */
382         static const unsigned char named_keys[] =
383 #define E(SEQ, NAME) SEQ "\0" NAME "\0"
384 #include "auparse/tty_named_keys.h"
385 #undef E
386         "\0";
387
388         unsigned char *src;
389         const unsigned char *nk;
390
391         src = *input;
392         if (*src >= ' ' && (*src < 0x7F || *src >= 0xA0))
393                 return NULL; /* Fast path */
394         nk = named_keys;
395         do {
396                 const unsigned char *p;
397                 size_t nk_len;
398
399                 p = strchr((const char *)nk, '\0');
400                 nk_len = p - nk;
401                 if (nk_len <= input_len && memcmp(src, nk, nk_len) == 0) {
402                         *input += nk_len;
403                         return (const char *)(p + 1);
404                 }
405                 nk = strchr((const char *)p + 1, '\0') + 1;
406         } while (*nk != '\0');
407         return NULL;
408 }
409
410 void print_tty_data(const char *val)
411 {
412         int need_comma, in_printable = 0;
413         unsigned char *data, *data_pos, *data_end;
414
415         if (!is_hex_string(val)) {
416                 printf("%s", val);
417                 return;
418         }
419
420         if ((data = unescape((char *)val)) == NULL) {
421                 printf("conversion error(%s)", val);
422                 return;
423         }
424
425         data_end = data + strlen(val) / 2;
426         data_pos = data;
427         need_comma = 0;
428         while (data_pos < data_end) {
429                 /* FIXME: Unicode */
430                 const char *desc;
431
432                 desc = tty_find_named_key(&data_pos, data_end - data_pos);
433                 if (desc != NULL) {
434                         if (in_printable != 0) {
435                                 putchar('"');
436                                 in_printable = 0;
437                         }
438                         if (need_comma != 0)
439                                 putchar(',');
440                         printf("<%s>", desc);
441                 } else {
442                         if (in_printable == 0) {
443                                 if (need_comma != 0)
444                                         putchar(',');
445                                 putchar('"');
446                                 in_printable = 1;
447                         }
448                         tty_printable_char(*data_pos);
449                         data_pos++;
450                 }
451                 need_comma = 1;
452         }
453         if (in_printable != 0)
454                 putchar('"');
455         free(data);
456 }
457