Imported Upstream version 2.4.3
[platform/upstream/audit.git] / src / ausearch-checkpt.c
1 /*
2  * ausearch-checkpt.c - ausearch checkpointing feature
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include "ausearch-checkpt.h"
25
26 #define DBG     0       /* set to non-zero for debug */
27
28 /* Remember why we failed */
29 unsigned checkpt_failure = 0;
30
31 /*
32  * Remember the file we were processing when we had incomplete events.
33  * We remember this via it's dev and inode
34  */
35 static dev_t checkpt_dev = (dev_t)NULL;
36 static ino_t checkpt_ino = (ino_t)NULL;
37
38 /* Remember the last event output */
39 static event last_event = {0, 0, 0, NULL, 0};
40
41 /* Loaded values from a given checkpoint file */
42 dev_t chkpt_input_dev = (dev_t)NULL;
43 ino_t chkpt_input_ino = (ino_t)NULL;
44 event chkpt_input_levent = {0, 0, 0, NULL, 0};
45
46 /*
47  * Record the dev_t and ino_t of the given file
48  *
49  * Returns:
50  * 1    Failed to get status
51  * 0    OK
52  */
53 int set_ChkPtFileDetails(const char *fn)
54 {
55         struct stat sbuf;
56
57         if (stat(fn, &sbuf) != 0) {
58                 fprintf(stderr, "Cannot stat audit file for checkpoint "
59                         "details - %s: %s\n", fn, strerror(errno));
60                 checkpt_failure |= CP_STATFAILED;
61                 return 1;
62         }
63         checkpt_dev = sbuf.st_dev;
64         checkpt_ino = sbuf.st_ino;
65
66         return 0;
67 }
68
69 /*
70  * Save the given event in the last_event record
71  * Returns:
72  * 1    no memory
73  * 0    OK
74  */
75 int set_ChkPtLastEvent(const event *e)
76 {
77         /* Set the event node if necessary */
78         if (e->node) {
79                 if (last_event.node) {
80                         if (strcmp(e->node, last_event.node) != 0) {
81                                 free((void *)last_event.node);
82                                 last_event.node = strdup(e->node);
83                         }
84                 } else
85                         last_event.node = strdup(e->node);
86                 if (last_event.node == NULL) {
87                         fprintf(stderr, "No memory to allocate "
88                                         "checkpoint last event node name\n");
89                         return 1;
90                 }
91         } else {
92                 if (last_event.node)
93                         free((void *)last_event.node);
94                 last_event.node = NULL;
95         }
96         last_event.sec = e->sec;
97         last_event.milli = e->milli;
98         last_event.serial = e->serial;
99         last_event.type = e->type;
100
101         return 0;
102 }
103
104 /* Free all checkpoint memory */
105 void free_ChkPtMemory(void)
106 {
107         if (last_event.node)
108                 (void)free((void *)last_event.node);
109         last_event.node = NULL;
110         if (chkpt_input_levent.node)
111                 (void)free((void *)chkpt_input_levent.node);
112         chkpt_input_levent.node = NULL;
113 }
114
115 /*
116  * Save the checkpoint to the given file
117  * Returns:
118  * 1    io error
119  * 0    OK
120  */
121 void save_ChkPt(const char *fn)
122 {
123         FILE *fd;
124
125         if ((fd = fopen(fn, "w")) == NULL) {
126                 fprintf(stderr, "Cannot open checkpoint file - %s: %s\n",
127                         fn, strerror(errno));
128                 checkpt_failure |= CP_STATUSIO;
129                 return;
130         }
131         fprintf(fd, "dev=0x%X\ninode=0x%X\n",
132                 (unsigned int)checkpt_dev, (unsigned int)checkpt_ino);
133         fprintf(fd, "output=%s %lu.%03u:%lu 0x%X\n",
134                 last_event.node ? last_event.node : "-",
135                 (long unsigned int)last_event.sec, last_event.milli,
136                 last_event.serial, last_event.type);
137         fclose(fd);
138 }
139
140 /*
141  * Parse a checkpoint file "output=" record
142  * Returns
143  * 1    failed to parse or no memory
144  * 0    parsed OK
145  */
146 static int parse_checkpt_event(char *lbuf, int ndix, event *e)
147 {
148         char *rest;
149
150         /*
151          * Find the space after the node, then make it '\0' so
152          * we terminate the node value. We leave 'rest' at the start
153          * of the event time/serial element
154          */
155         rest = strchr(&lbuf[ndix], ' ');
156         if (rest == NULL) {
157                 fprintf(stderr, "Malformed output/event checkpoint line "
158                                 "near node - [%s]\n", lbuf);
159                 checkpt_failure |= CP_STATUSBAD;
160                 return 1;
161         }
162         *rest++ = '\0';
163         
164         if (lbuf[ndix] == '-')
165                 e->node = NULL;
166         else {
167                 e->node = strdup(&lbuf[ndix]);
168                 if (e->node == NULL) {
169                         fprintf(stderr, "No memory for node when loading "
170                                         "checkpoint line - [%s]\n", lbuf);
171                         checkpt_failure |= CP_NOMEM;
172                         return 1;
173                 }
174         }
175         if (sscanf(rest, "%lu.%03u:%lu 0x%X", &e->sec, &e->milli,
176                                                 &e->serial, &e->type) != 4) {
177                 fprintf(stderr, "Malformed output/event checkpoint line "
178                         "after node - [%s]\n", lbuf);
179                 checkpt_failure |= CP_STATUSBAD;
180                 return 1;
181         }
182
183         return 0;
184 }
185
186 /*
187  * Load the checkpoint from the given file
188  * Returns:
189  *  < -1        error
190  * == -1        no file present
191  * == 0         loaded data
192  */
193 int load_ChkPt(const char *fn)
194 {
195 #define MAX_LN  1023
196         FILE *fd;
197         char lbuf[MAX_LN];
198
199         if ((fd = fopen(fn, "r")) == NULL) {
200                 if (errno == ENOENT)
201                         return -1;
202                 fprintf(stderr, "Cannot open checkpoint file - %s: %s\n",
203                         fn, strerror(errno));
204                 return -2;
205         }
206         while (fgets(lbuf, MAX_LN, fd) != NULL) {
207                 size_t len = strlen(lbuf);
208
209                 if (len && lbuf[len - 1] == '\n')       /* drop the newline */
210                         lbuf[len - 1] = '\0';
211
212                 if (strncmp(lbuf, "dev=", 4) == 0) {
213                         errno = 0;
214                         chkpt_input_dev = strtoul(&lbuf[4], NULL, 16);
215                         if (errno) {
216                                 fprintf(stderr, "Malformed dev checkpoint "
217                                                 "line - [%s]\n", lbuf);
218                                 checkpt_failure |= CP_STATUSBAD;
219                                 break;
220                         }
221                 } else if (strncmp(lbuf, "inode=", 6) == 0) {
222                         errno = 0;
223                         chkpt_input_ino = strtoul(&lbuf[6], NULL, 16);
224                         if (errno) {
225                                 fprintf(stderr, "Malformed inode checkpoint "
226                                                 "line - [%s]\n", lbuf);
227                                 checkpt_failure |= CP_STATUSBAD;
228                                 break;
229                         }
230                 } else if (strncmp(lbuf, "output=", 7) == 0) {
231                         if (parse_checkpt_event(lbuf, 7, &chkpt_input_levent))
232                                 break;
233                 } else {
234                         fprintf(stderr, "Unknown checkpoint line - [%s]\n",
235                                 lbuf);
236                         checkpt_failure |= CP_STATUSBAD;
237                         break;
238                 }
239         }
240         if (    (chkpt_input_ino == (ino_t)NULL) ||
241                 (chkpt_input_dev == (dev_t)NULL) ) {
242                 fprintf(stderr, "Missing dev/inode lines from checkpoint "
243                                 "file %s\n", fn);
244                 checkpt_failure |= CP_STATUSBAD;
245         }
246         fclose(fd);
247
248         if (checkpt_failure)
249                 return -3;
250
251 #if     DBG
252         {
253                 fprintf(stderr, "Loaded %s - dev: 0x%X, ino: 0x%X\n",
254                         fn, chkpt_input_dev, chkpt_input_ino);
255                 fprintf(stderr, "output:%s %d.%03d:%lu 0x%X\n",
256                         chkpt_input_levent.node ? chkpt_input_levent.node : "-",
257                         chkpt_input_levent.sec, chkpt_input_levent.milli,
258                         chkpt_input_levent.serial, chkpt_input_levent.type);
259         }
260 #endif  /* DBG */
261         return 0;
262 }
263