static void feed_auparse(llist *l, auparse_callback_ptr callback) { const lnode *n; list_first(l); n = list_get_cur(l); if (!n) { fprintf(stderr, "Error - no elements in record."); return; } au = auparse_init(AUSOURCE_FEED, 0); auparse_set_escape_mode(au, escape_mode); auparse_add_callback(au, callback, NULL, NULL); do { // Records need to be terminated by a newline // Temporarily replace it. if (l->fmt == LF_ENRICHED) n->message[n->mlen] = AUDIT_INTERP_SEPARATOR; n->message[n->tlen] = 0x0a; auparse_feed(au, n->message, n->tlen+1); if (l->fmt == LF_ENRICHED) n->message[n->mlen] = 0; n->message[n->tlen] = 0; } while ((n=list_next(l))); auparse_flush_feed(au); auparse_destroy(au); }
static ssize_t tail_pipe(struct file_struct *f) { ssize_t rc; char *buf = emalloc(f->blksize); if (verbose) write_header(f->name); /* We will just tail everything here */ while ((rc = read(f->fd, buf, f->blksize)) > 0) { auparse_feed(au, buf, rc); } free(buf); return rc; }
int main(int argc, char *argv[]) { char tmp[MAX_AUDIT_MESSAGE_LENGTH+1]; struct sigaction sa; /* Register sighandlers */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); /* Set handler for the ones we care about */ sa.sa_handler = term_handler; sigaction(SIGTERM, &sa, NULL); sa.sa_handler = hup_handler; sigaction(SIGHUP, &sa, NULL); /* Initialize the auparse library */ au = auparse_init(AUSOURCE_FEED, 0); if (au == NULL) { printf("audisp-example is exiting due to auparse init errors"); return -1; } auparse_add_callback(au, handle_event, NULL, NULL); do { /* Load configuration */ if (hup) { reload_config(); } /* Now the event loop */ while (fgets_unlocked(tmp, MAX_AUDIT_MESSAGE_LENGTH, stdin) && hup==0 && stop==0) { auparse_feed(au, tmp, strnlen(tmp, MAX_AUDIT_MESSAGE_LENGTH)); } if (feof(stdin)) break; } while (stop == 0); /* Flush any accumulated events from queue */ auparse_flush_feed(au); auparse_destroy(au); if (stop) printf("audisp-example is exiting on stop request\n"); else printf("audisp-example is exiting on stdin EOF\n"); return 0; }
int main(int argc, char *argv[]) { char tmp[MAX_AUDIT_MESSAGE_LENGTH+1]; struct sigaction sa; /* Register sighandlers */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); /* Set handler for the ones we care about */ sa.sa_handler = term_handler; sigaction(SIGTERM, &sa, NULL); sa.sa_handler = hup_handler; sigaction(SIGHUP, &sa, NULL); /* Initialize the auparse library */ au = auparse_init(AUSOURCE_FEED, 0); if (au == NULL) { printf("audisp-example is exiting due to auparse init errors"); return -1; } auparse_add_callback(au, handle_event, NULL, NULL); do { fd_set read_mask; struct timeval tv; int retval; /* Load configuration */ if (hup) { reload_config(); } do { tv.tv_sec = 5; tv.tv_usec = 0; FD_ZERO(&read_mask); FD_SET(0, &read_mask); if (auparse_feed_has_data(au)) retval= select(1, &read_mask, NULL, NULL, &tv); else retval= select(1, &read_mask, NULL, NULL, NULL); } while (retval == -1 && errno == EINTR && !hup && !stop); /* Now the event loop */ if (!stop && !hup && retval > 0) { if (fgets_unlocked(tmp, MAX_AUDIT_MESSAGE_LENGTH, stdin)) { auparse_feed(au, tmp, strnlen(tmp, MAX_AUDIT_MESSAGE_LENGTH)); } } else if (retval == 0) auparse_flush_feed(au); if (feof(stdin)) break; } while (stop == 0); /* Flush any accumulated events from queue */ auparse_flush_feed(au); auparse_destroy(au); if (stop) printf("audisp-example is exiting on stop request\n"); else printf("audisp-example is exiting on stdin EOF\n"); return 0; }
static int handle_inotify_event(struct inotify_event *inev, struct file_struct *f) { int ret = 0; if (inev->mask & IN_MODIFY) { char *fbuf; ssize_t rc; struct stat finfo; if (verbose) write_header(f->name); /* Seek to old file size */ if (lseek(f->fd, f->size, SEEK_SET) == (off_t) -1) { fprintf(stderr, "Error: Could not seek in file '%s' (%s)\n", f->name, strerror(errno)); ret = -1; goto ignore; } fbuf = emalloc(f->blksize); while ((rc = read(f->fd, fbuf, f->blksize)) != 0) { auparse_feed(au,fbuf, rc); } if (fstat(f->fd, &finfo) < 0) { fprintf(stderr, "Error: Could not stat file '%s' (%s)\n", f->name, strerror(errno)); ret = -1; free(fbuf); goto ignore; } f->size = finfo.st_size; free(fbuf); return ret; } else if (inev->mask & IN_DELETE_SELF) { fprintf(stderr, "File '%s' deleted.\n", f->name); } else if (inev->mask & IN_MOVE_SELF) { fprintf(stderr, "File '%s' moved.\n", f->name); // SCOTT close(f->fd); free(files); struct file_struct *new_files = NULL; new_files = emalloc( sizeof(struct file_struct) ); new_files[0].name = "/var/log/audit/audit.log"; setup_file(&new_files[0]); // Take a sec here to let the new file get // set up by the OS - there are problems with this // asking just a bit too soon. sleep(1); tail_file(new_files, DEFAULT_N_LINES, M_LINES, 1); watch_files(new_files, 1); return 0; } else if (inev->mask & IN_UNMOUNT) { fprintf(stderr, "Device containing file '%s' unmounted.\n", f->name); } ignore: ignore_file(f); return ret; }
static int tail_file(struct file_struct *f, unsigned long n_units, char mode, char forever) { ssize_t bytes_read = 0; off_t offset = 0; char *buf; struct stat finfo; if (strcmp(f->name, "-") == 0) f->fd = STDIN_FILENO; else { f->fd = open(f->name, O_RDONLY); if (unlikely(f->fd < 0)) { fprintf(stderr, "Error: Could not open file '%s' (%s)\n", f->name, strerror(errno)); ignore_file(f); return -1; } } if (fstat(f->fd, &finfo) < 0) { fprintf(stderr, "Error: Could not stat file '%s' (%s)\n", f->name, strerror(errno)); ignore_file(f); return -1; } if (!IS_TAILABLE(finfo.st_mode)) { fprintf(stderr, "Error: '%s' of unsupported file type (%s)\n", f->name, strerror(errno)); ignore_file(f); return -1; } /* Cannot seek on these */ if (IS_PIPELIKE(finfo.st_mode) || f->fd == STDIN_FILENO) return tail_pipe(f); f->size = finfo.st_size; f->blksize = finfo.st_blksize; /* TODO: Can this value be 0? */ if (mode == M_LINES) offset = lines_to_offset(f, n_units); else offset = bytes_to_offset(f, n_units); /* We only get negative offsets on errors */ if (unlikely(offset < 0)) { ignore_file(f); return -1; } if (verbose) write_header(f->name); if (lseek(f->fd, offset, SEEK_SET) == (off_t) -1) { fprintf(stderr, "Error: Could not seek in file '%s' (%s)\n", f->name, strerror(errno)); return -1; } buf = emalloc(f->blksize); while ((bytes_read = read(f->fd, buf, f->blksize)) > 0) { auparse_feed(au,buf, bytes_read); } if (!forever) { if (close(f->fd) < 0) { fprintf(stderr, "Error: Could not close file '%s' (%s)\n", f->name, strerror(errno)); free(buf); return -1; } } /* Let the fd open otherwise, we'll need it */ free(buf); return 0; }
int main(int argc, char *argv[]) { int rc; const char *cpath; char buf[1024]; struct sigaction sa; sigset_t ss; auparse_state_t *au; ssize_t len; mypid = getpid(); log_info("starting with pid=%d", mypid); /* * install signal handlers */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sa.sa_handler = term_handler; sigaction(SIGTERM, &sa, NULL); sa.sa_handler = hup_handler; sigaction(SIGHUP, &sa, NULL); sa.sa_handler = alarm_handler; sigaction(SIGALRM, &sa, NULL); /* * the main program accepts a single (optional) argument: * it's configuration file (this is NOT the plugin configuration * usually located at /etc/audisp/plugin.d) * We use the default (def_config_file) if no arguments are given */ if (argc == 1) { cpath = def_config_file; log_warn("No configuration file specified - using default (%s)", cpath); } else if (argc == 2) { cpath = argv[1]; log_info("Using configuration file: %s", cpath); } else { log_err("Error - invalid number of parameters passed. Aborting"); return 1; } /* initialize record counter */ conf.counter = 1; /* initialize configuration with default values */ plugin_clear_config(&conf); /* initialize the submission queue */ if (init_queue(conf.q_depth) != 0) { log_err("Error - Can't initialize event queue. Aborting"); return -1; } /* set stdin to O_NONBLOCK */ if (fcntl(0, F_SETFL, O_NONBLOCK) == -1) { log_err("Error - Can't set input to Non-blocking mode: %s. Aborting", strerror(errno)); return -1; } do { hup = 0; /* don't flush unless hup == 1 */ /* * initialization is done in 4 steps: */ /* * load configuration and * increase queue depth if needed */ rc = plugin_load_config(&conf, cpath); if (rc != 0) { log_err("Error - Can't load configuration. Aborting"); return -1; } increase_queue_depth(conf.q_depth); /* 1 */ /* initialize auparse */ au = auparse_init(AUSOURCE_FEED, 0); /* 2 */ /* * Block signals for everyone, * Initialize submission thread, and * Unblock signals for this thread */ sigfillset(&ss); pthread_sigmask(SIG_BLOCK, &ss, NULL); pthread_create(&submission_thread, NULL, submission_thread_main, NULL); pthread_sigmask(SIG_UNBLOCK, &ss, NULL); /* 3 */ /* add our event consumer callback */ auparse_add_callback(au, push_event, NULL, NULL); /* 4 */ /* main loop */ while (hup == 0 && stop == 0) { fd_set rfds; struct timeval tv; FD_ZERO(&rfds); FD_SET(0, &rfds); tv.tv_sec = 5; tv.tv_usec = 0; rc = select(1, &rfds, NULL, NULL, &tv); if (rc == -1) { if (errno == EINTR) { log_debug("Select call interrupted"); continue; } else { log_err("Error - Fatal error while monitoring input: %s. Aborting", strerror(errno)); stop = 1; } } else if (rc) { len = read(0, buf, 1024); if (len > 0) /* let our callback know of the new data */ auparse_feed(au, buf, len); else if (len == 0) { log_debug("End of input - Exiting"); stop = 1; } else { /* ignore interrupted call or empty pipe */ if (errno != EINTR && errno != EAGAIN) { log_err("Error - Fatal error while reading input: %s. Aborting", strerror(errno)); stop = 1; } else { log_debug("Ignoring read interruption: %s", strerror(errno)); } } } } /* flush everything, in order */ auparse_flush_feed(au); /* 4 */ alarm(10); /* 10 seconds to clear the queue */ pthread_join(submission_thread, NULL); /* 3 */ alarm(0); /* cancel any pending alarm */ auparse_destroy(au); /* 2 */ plugin_free_config(&conf); /* 1 */ } while (hup && stop == 0); /* destroy queue before leaving */ destroy_queue(); log_info("Exiting"); return 0; }
int main(int argc, char **argv) { char *filename = NULL; auparse_esc_t em; FILE *fd; #define BUFSZ 2048 char buf[BUFSZ]; size_t len; int *event_cnt = NULL; auparse_state_t *au; int i; /* Argument parsing */ while (1) { int option_index = 0; int c; static struct option long_options[] = { { "verbose", no_argument, 0, 'v'}, { "file", required_argument, 0, 'f'}, { "stdin", no_argument, 0, 's'}, { "check", no_argument, 0, 'c'}, { "escape", required_argument, 0, 'e'}, { 0, 0, 0, 0} }; c = getopt_long(argc, argv, "cvf:e:s", long_options, &option_index); if (c == -1) break; switch (c) { case 'e': /* escape mode */ switch (*optarg) { case 'R': case 'r': em = AUPARSE_ESC_RAW; break; case 'T': case 't': em = AUPARSE_ESC_TTY; break; case 'S': case 's': em = AUPARSE_ESC_SHELL; break; case 'Q': case 'q': em = AUPARSE_ESC_SHELL_QUOTE; break; default: fprintf(stderr, "%s: Unknown escape character 0x%2.2X\n", argv[0], *optarg); usage(); return 1; } auparse_set_escape_mode(NULL, em); break; case 'c': /* check */ flags |= F_CHECK; break; case 'v': /* verbose */ flags |= F_VERBOSE; break; case 's': /* stdin */ flags |= F_USESTDIN; break; case 'f': /* file */ filename = optarg; break; case '?': default: fprintf(stderr, "%s: Unknown option 0x%2.2X\n", argv[0], c); usage(); return 1; } } if ((flags & F_USESTDIN) && filename != NULL) { fprintf(stderr, "%s: --stdin cannot be used with file argument\n", argv[0]); usage(); return 1; } if (!(flags & F_USESTDIN) && filename == NULL) { fprintf(stderr, "%s: Missing --stdin or -f file argument\n", argv[0]); usage(); return 1; } if ((event_cnt = malloc(sizeof(int))) == NULL) { fprintf(stderr, "%s: No memory to allocate %lu bytes\n", argv[0], sizeof(int)); return 1; } if (flags & F_USESTDIN) { fd = stdin; } else { if ((fd = fopen(filename, "r")) == NULL) { fprintf(stderr, "could not open ā%sā, %s\n", filename, strerror(errno)); (void) free(event_cnt); return 1; } } au = auparse_init(AUSOURCE_FEED, NULL); *event_cnt = 1; auparse_add_callback(au, auparse_callback, event_cnt, free); i = 0; while ((len = fread(buf, 1, sizeof(buf), fd))) { auparse_feed(au, buf, len); i++; } auparse_flush_feed(au); auparse_destroy(au); /* this also free's event_cnt */ if (!(flags & F_USESTDIN)) fclose(fd); return 0; }