/* * ausearch-checkpt.c - ausearch checkpointing feature * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include "ausearch-checkpt.h" #define DBG 0 /* set to non-zero for debug */ /* Remember why we failed */ unsigned checkpt_failure = 0; /* * Remember the file we were processing when we had incomplete events. * We remember this via it's dev and inode */ static dev_t checkpt_dev = (dev_t)NULL; static ino_t checkpt_ino = (ino_t)NULL; /* Remember the last event output */ static event last_event = {0, 0, 0, NULL, 0}; /* Loaded values from a given checkpoint file */ dev_t chkpt_input_dev = (dev_t)NULL; ino_t chkpt_input_ino = (ino_t)NULL; event chkpt_input_levent = {0, 0, 0, NULL, 0}; /* * Record the dev_t and ino_t of the given file * * Returns: * 1 Failed to get status * 0 OK */ int set_ChkPtFileDetails(const char *fn) { struct stat sbuf; if (stat(fn, &sbuf) != 0) { fprintf(stderr, "Cannot stat audit file for checkpoint " "details - %s: %s\n", fn, strerror(errno)); checkpt_failure |= CP_STATFAILED; return 1; } checkpt_dev = sbuf.st_dev; checkpt_ino = sbuf.st_ino; return 0; } /* * Save the given event in the last_event record * Returns: * 1 no memory * 0 OK */ int set_ChkPtLastEvent(const event *e) { /* Set the event node if necessary */ if (e->node) { if (last_event.node) { if (strcmp(e->node, last_event.node) != 0) { free((void *)last_event.node); last_event.node = strdup(e->node); } } else last_event.node = strdup(e->node); if (last_event.node == NULL) { fprintf(stderr, "No memory to allocate " "checkpoint last event node name\n"); return 1; } } else { if (last_event.node) free((void *)last_event.node); last_event.node = NULL; } last_event.sec = e->sec; last_event.milli = e->milli; last_event.serial = e->serial; last_event.type = e->type; return 0; } /* Free all checkpoint memory */ void free_ChkPtMemory(void) { if (last_event.node) (void)free((void *)last_event.node); last_event.node = NULL; if (chkpt_input_levent.node) (void)free((void *)chkpt_input_levent.node); chkpt_input_levent.node = NULL; } /* * Save the checkpoint to the given file * Returns: * 1 io error * 0 OK */ void save_ChkPt(const char *fn) { FILE *fd; if ((fd = fopen(fn, "w")) == NULL) { fprintf(stderr, "Cannot open checkpoint file - %s: %s\n", fn, strerror(errno)); checkpt_failure |= CP_STATUSIO; return; } fprintf(fd, "dev=0x%X\ninode=0x%X\n", (unsigned int)checkpt_dev, (unsigned int)checkpt_ino); fprintf(fd, "output=%s %lu.%03u:%lu 0x%X\n", last_event.node ? last_event.node : "-", (long unsigned int)last_event.sec, last_event.milli, last_event.serial, last_event.type); fclose(fd); } /* * Parse a checkpoint file "output=" record * Returns * 1 failed to parse or no memory * 0 parsed OK */ static int parse_checkpt_event(char *lbuf, int ndix, event *e) { char *rest; /* * Find the space after the node, then make it '\0' so * we terminate the node value. We leave 'rest' at the start * of the event time/serial element */ rest = strchr(&lbuf[ndix], ' '); if (rest == NULL) { fprintf(stderr, "Malformed output/event checkpoint line " "near node - [%s]\n", lbuf); checkpt_failure |= CP_STATUSBAD; return 1; } *rest++ = '\0'; if (lbuf[ndix] == '-') e->node = NULL; else { e->node = strdup(&lbuf[ndix]); if (e->node == NULL) { fprintf(stderr, "No memory for node when loading " "checkpoint line - [%s]\n", lbuf); checkpt_failure |= CP_NOMEM; return 1; } } if (sscanf(rest, "%lu.%03u:%lu 0x%X", &e->sec, &e->milli, &e->serial, &e->type) != 4) { fprintf(stderr, "Malformed output/event checkpoint line " "after node - [%s]\n", lbuf); checkpt_failure |= CP_STATUSBAD; return 1; } return 0; } /* * Load the checkpoint from the given file * Returns: * < -1 error * == -1 no file present * == 0 loaded data */ int load_ChkPt(const char *fn) { #define MAX_LN 1023 FILE *fd; char lbuf[MAX_LN]; if ((fd = fopen(fn, "r")) == NULL) { if (errno == ENOENT) return -1; fprintf(stderr, "Cannot open checkpoint file - %s: %s\n", fn, strerror(errno)); return -2; } while (fgets(lbuf, MAX_LN, fd) != NULL) { size_t len = strlen(lbuf); if (len && lbuf[len - 1] == '\n') /* drop the newline */ lbuf[len - 1] = '\0'; if (strncmp(lbuf, "dev=", 4) == 0) { errno = 0; chkpt_input_dev = strtoul(&lbuf[4], NULL, 16); if (errno) { fprintf(stderr, "Malformed dev checkpoint " "line - [%s]\n", lbuf); checkpt_failure |= CP_STATUSBAD; break; } } else if (strncmp(lbuf, "inode=", 6) == 0) { errno = 0; chkpt_input_ino = strtoul(&lbuf[6], NULL, 16); if (errno) { fprintf(stderr, "Malformed inode checkpoint " "line - [%s]\n", lbuf); checkpt_failure |= CP_STATUSBAD; break; } } else if (strncmp(lbuf, "output=", 7) == 0) { if (parse_checkpt_event(lbuf, 7, &chkpt_input_levent)) break; } else { fprintf(stderr, "Unknown checkpoint line - [%s]\n", lbuf); checkpt_failure |= CP_STATUSBAD; break; } } if ( (chkpt_input_ino == (ino_t)NULL) || (chkpt_input_dev == (dev_t)NULL) ) { fprintf(stderr, "Missing dev/inode lines from checkpoint " "file %s\n", fn); checkpt_failure |= CP_STATUSBAD; } fclose(fd); if (checkpt_failure) return -3; #if DBG { fprintf(stderr, "Loaded %s - dev: 0x%X, ino: 0x%X\n", fn, chkpt_input_dev, chkpt_input_ino); fprintf(stderr, "output:%s %d.%03d:%lu 0x%X\n", chkpt_input_levent.node ? chkpt_input_levent.node : "-", chkpt_input_levent.sec, chkpt_input_levent.milli, chkpt_input_levent.serial, chkpt_input_levent.type); } #endif /* DBG */ return 0; }