Imported Upstream version 2.4.3
[platform/upstream/audit.git] / src / aureport.c
1 /*
2  * aureport.c - main file for aureport utility 
3  * Copyright 2005-08, 2010,11,2013 Red Hat Inc., Durham, North Carolina.
4  * All Rights Reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any 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; 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 "config.h"
25 #include <stdio.h>
26 #include <stdio_ext.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <getopt.h>
30 #include <unistd.h>
31 #include <ctype.h>
32 #include <time.h>
33 #include <errno.h>
34 #include <sys/resource.h>
35 #include <sys/stat.h>
36 #include <locale.h>
37 #include <sys/param.h>
38 #include "libaudit.h"
39 #include "auditd-config.h"
40 #include "aureport-options.h"
41 #include "aureport-scan.h"
42 #include "ausearch-lol.h"
43 #include "ausearch-lookup.h"
44
45
46 event very_first_event, very_last_event;
47 static FILE *log_fd = NULL;
48 static lol lo;
49 static int found = 0;
50 static int files_to_process = 0; // Logs left when processing multiple
51 static int userfile_is_dir = 0;
52 static int process_logs(void);
53 static int process_log_fd(const char *filename);
54 static int process_stdin(void);
55 static int process_file(char *filename);
56 static int get_record(llist **);
57
58 extern char *user_file;
59 extern int force_logs;
60
61
62 static int is_pipe(int fd)
63 {
64         struct stat st;
65
66         if (fstat(fd, &st) == 0) {
67                 if (S_ISFIFO(st.st_mode))
68                         return 1;
69         }
70         return 0;
71 }
72
73 int main(int argc, char *argv[])
74 {
75         struct rlimit limit;
76         int rc;
77
78         /* Check params and build regexpr */
79         setlocale (LC_ALL, "");
80         if (check_params(argc, argv))
81                 return 1;
82
83         /* Raise the rlimits in case we're being started from a shell
84         * with restrictions. Not a fatal error.  */
85         limit.rlim_cur = RLIM_INFINITY;
86         limit.rlim_max = RLIM_INFINITY;
87         setrlimit(RLIMIT_FSIZE, &limit);
88         setrlimit(RLIMIT_CPU, &limit);
89         set_aumessage_mode(MSG_STDERR, DBG_NO);
90         (void) umask( umask( 077 ) | 027 );
91         very_first_event.sec = 0;
92         reset_counters();
93
94         print_title();
95         lol_create(&lo);
96         if (user_file) {
97                 struct stat sb;
98                 if (stat(user_file, &sb) == -1) {
99                         perror("stat");
100                         return 1;
101                 } else {
102                         switch (sb.st_mode & S_IFMT) {
103                                 case S_IFDIR: 
104                                         userfile_is_dir = 1;
105                                         rc = process_logs();
106                                         break;
107                                 case S_IFREG:
108                                 default:
109                                         rc = process_file(user_file);
110                                         break;
111                         }
112                 }
113         } else if (force_logs)
114                 rc = process_logs();
115         else if (is_pipe(0))
116                 rc = process_stdin();
117         else
118                 rc = process_logs();
119         lol_clear(&lo);
120         if (rc)
121                 return rc;
122
123         if (!found && report_detail == D_DETAILED && report_type != RPT_TIME) {
124                 printf("<no events of interest were found>\n\n");
125                 destroy_counters();
126                 aulookup_destroy_uid_list();
127                 aulookup_destroy_gid_list();
128                 return 1;
129         } else 
130                 print_wrap_up();
131         destroy_counters();
132         aulookup_destroy_uid_list();
133         aulookup_destroy_gid_list();
134         free(user_file);
135         return 0;
136 }
137
138 static int process_logs(void)
139 {
140         struct daemon_conf config;
141         char *filename;
142         int len, num = 0;
143
144         if (user_file && userfile_is_dir) {
145                 char dirname[MAXPATHLEN];
146                 clear_config (&config);
147
148                 strcpy(dirname, user_file);
149                 if (dirname[strlen(dirname)-1] != '/')
150                         strcat(dirname, "/");
151                 strcat (dirname, "audit.log");
152                 free((void *)config.log_file);
153                 config.log_file=strdup(dirname);
154                 fprintf(stderr, "NOTE - using logs in %s\n", config.log_file);
155         } else {
156                 /* Load config so we know where logs are */
157                 if (load_config(&config, TEST_SEARCH))
158                         fprintf(stderr, "NOTE - using built-in logs: %s\n",
159                                 config.log_file);
160         }
161
162         /* for each file */
163         len = strlen(config.log_file) + 16;
164         filename = malloc(len);
165         if (!filename) {
166                 fprintf(stderr, "No memory\n");
167                 free_config(&config);
168                 return 1;
169         }
170         /* Find oldest log file */
171         snprintf(filename, len, "%s", config.log_file);
172         do {
173                 if (access(filename, R_OK) != 0)
174                         break;
175 // FIXME: do a time check and put them on linked list for later
176                 num++;
177                 snprintf(filename, len, "%s.%d", config.log_file, num);
178         } while (1);
179         num--;
180         /*
181          * We note how many files we need to process
182          */
183         files_to_process = num;
184
185         /* Got it, now process logs from last to first */
186         if (num > 0)
187                 snprintf(filename, len, "%s.%d", config.log_file, num);
188         else
189                 snprintf(filename, len, "%s", config.log_file);
190         do {
191                 int ret;
192                 if ((ret = process_file(filename))) {
193                         free(filename);
194                         free_config(&config);
195                         return ret;
196                 }
197
198                 /* Get next log file */
199                 files_to_process--;     /* one less file to process */
200                 num--;
201                 if (num > 0)
202                         snprintf(filename, len, "%s.%d", config.log_file, num);
203                 else if (num == 0)
204                         snprintf(filename, len, "%s", config.log_file);
205                 else
206                         break;
207         } while (1);
208         free(filename);
209         free_config(&config);
210         return 0;
211 }
212
213 static int process_log_fd(const char *filename)
214 {
215         llist *entries; // entries in a record
216         int ret;
217         int first = 0;
218         event first_event, last_event;
219
220         last_event.sec = 0;
221         last_event.milli = 0;
222
223         /* For each record in file */
224         do {
225                 ret = get_record(&entries);
226                 if ((ret != 0)||(entries->cnt == 0))
227                         break;
228                 // If report is RPT_TIME or RPT_SUMMARY, get 
229                 if (report_type <= RPT_SUMMARY) {
230                         if (first == 0) {
231                                 list_get_event(entries, &first_event);
232                                 first = 1;
233                                 if (very_first_event.sec == 0)
234                                         list_get_event(entries,
235                                                         &very_first_event);
236                         }
237                         list_get_event(entries, &last_event);
238                 } 
239                 if (scan(entries)) {
240                         // This is the per entry action item
241                         if (per_event_processing(entries))
242                                 found = 1;
243                 }
244                 list_clear(entries);
245                 free(entries);
246         } while (ret == 0);
247         fclose(log_fd);
248         // This is the per file action items
249         very_last_event.sec = last_event.sec;
250         very_last_event.milli = last_event.milli;
251         if (report_type == RPT_TIME) {
252                 if (first == 0) {
253                         printf("%s: no records\n", filename);
254                 } else {
255                         struct tm *btm;
256                         char tmp[32];
257
258                         printf("%s: ", filename);
259                         btm = localtime(&first_event.sec);
260                         strftime(tmp, sizeof(tmp), "%x %T", btm);
261                         printf("%s.%03d - ", tmp, first_event.milli);
262                         btm = localtime(&last_event.sec);
263                         strftime(tmp, sizeof(tmp), "%x %T", btm);
264                         printf("%s.%03d\n", tmp, last_event.milli);
265                 }
266         }
267
268         return 0;
269 }
270
271 static int process_stdin(void)
272 {
273         log_fd = stdin;
274
275         return process_log_fd("stdin");
276 }
277
278 static int process_file(char *filename)
279 {
280         log_fd = fopen(filename, "rm");
281         if (log_fd == NULL) {
282                 fprintf(stderr, "Error opening %s (%s)\n", filename, 
283                         strerror(errno));
284                 return 1;
285         }
286
287         __fsetlocking(log_fd, FSETLOCKING_BYCALLER);
288         return process_log_fd(filename);
289 }
290
291 /*
292  * This function returns a malloc'd buffer of the next record in the audit
293  * logs. It returns 0 on success, 1 on eof, -1 on error. 
294  */
295 static int get_record(llist **l)
296 {
297         char *rc;
298         char *buff = NULL;
299
300         *l = get_ready_event(&lo);
301         if (*l)
302                 return 0;
303
304         while (1) {
305                 if (!buff) {
306                         buff = malloc(MAX_AUDIT_MESSAGE_LENGTH);
307                         if (!buff)
308                                 return -1;
309                 }
310                 rc = fgets_unlocked(buff, MAX_AUDIT_MESSAGE_LENGTH,
311                                         log_fd);
312                 if (rc) {
313                         if (lol_add_record(&lo, buff)) {
314                                 *l = get_ready_event(&lo);
315                                 if (*l)
316                                         break;
317                         }
318                 } else {
319                         free(buff);
320                         if (feof_unlocked(log_fd)) {
321                                 // Only mark all events complete if this is
322                                 // the last file.
323                                 if (files_to_process == 0) {
324                                         terminate_all_events(&lo);
325                                 }
326                                 *l = get_ready_event(&lo);
327                                 if (*l)
328                                         return 0;
329                                 else
330                                         return 1;
331                         } else 
332                                 return -1;
333                 }
334         }
335         free(buff);
336         return 0;
337 }
338