Logo Search packages:      
Sourcecode: audit version File versions  Download package

autrace.c
/* autrace.c -- 
 * Copyright 2005-08 Red Hat Inc., Durham, North Carolina.
 * All Rights Reserved.
 *
 * 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
 *
 * Authors:
 *     Steve Grubb <sgrubb@redhat.com>
 */

#include "config.h"
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include "libaudit.h"
#include "private.h"

/*
 * This program will add the audit rules to trace a process similar
 * to strace. It will then execute the process.
 */
static int threat = 0;
static int count_rules(void);
static int count_em(int fd);
extern int delete_all_rules(int fd);

static void usage(void)
{
      fprintf(stderr, "usage: autrace [-r] program\n");
}

static int insert_rule(int audit_fd, const char *field)
{
      int rc;
      int flags = AUDIT_FILTER_ENTRY;
      int action = AUDIT_ALWAYS;
      struct audit_rule_data *rule = malloc(sizeof(struct audit_rule_data));

      if (rule == NULL)
            goto err;
      memset(rule, 0, sizeof(struct audit_rule_data));
      if (threat) {
            rc = 0;
            rc |= audit_rule_syscallbyname_data(rule, "open");
            rc |= audit_rule_syscallbyname_data(rule, "openat");
            rc |= audit_rule_syscallbyname_data(rule, "creat");
            rc |= audit_rule_syscallbyname_data(rule, "truncate");
            rc |= audit_rule_syscallbyname_data(rule, "rename");
            rc |= audit_rule_syscallbyname_data(rule, "renameat");
            rc |= audit_rule_syscallbyname_data(rule, "unlink");
            rc |= audit_rule_syscallbyname_data(rule, "unlinkat");
            rc |= audit_rule_syscallbyname_data(rule, "mknod");
            rc |= audit_rule_syscallbyname_data(rule, "mknodat");
            rc |= audit_rule_syscallbyname_data(rule, "mkdir");
            rc |= audit_rule_syscallbyname_data(rule, "mkdirat");
            rc |= audit_rule_syscallbyname_data(rule, "rmdir");
            rc |= audit_rule_syscallbyname_data(rule, "chdir");
            rc |= audit_rule_syscallbyname_data(rule, "chown");
            rc |= audit_rule_syscallbyname_data(rule, "lchown");
            rc |= audit_rule_syscallbyname_data(rule, "fchownat");
            rc |= audit_rule_syscallbyname_data(rule, "chmod");
            rc |= audit_rule_syscallbyname_data(rule, "fchmodat");
            rc |= audit_rule_syscallbyname_data(rule, "link");
            rc |= audit_rule_syscallbyname_data(rule, "linkat");
            rc |= audit_rule_syscallbyname_data(rule, "symlink");
            rc |= audit_rule_syscallbyname_data(rule, "symlinkat");
            rc |= audit_rule_syscallbyname_data(rule, "readlink");
            rc |= audit_rule_syscallbyname_data(rule, "readlinkat");
            rc |= audit_rule_syscallbyname_data(rule, "execve");
            rc |= audit_rule_syscallbyname_data(rule, "connect");
            rc |= audit_rule_syscallbyname_data(rule, "bind");
            rc |= audit_rule_syscallbyname_data(rule, "accept");
            rc |= audit_rule_syscallbyname_data(rule, "sendto");
            rc |= audit_rule_syscallbyname_data(rule, "recvfrom");
            rc |= audit_rule_syscallbyname_data(rule, "sendfile");
      } else
            rc = audit_rule_syscallbyname_data(rule, "all");
      if (rc < 0)
            goto err;
      rc = audit_rule_fieldpair_data(&rule, field, flags);
      if (rc < 0)
            goto err;
      rc = audit_add_rule_data(audit_fd, rule, flags, action);
      if (rc < 0)
            goto err;
      return 0;
err:
      fprintf(stderr, "Error inserting audit rule for %s\n", field);
      return 1;
}

int key_match(struct audit_reply *rep)
{
      return 1;
}

/*
 * Algorithm:
 * check that user is root
 * check to see if program exists
 * if so fork, child waits for parent
 * parent clears audit rules, loads audit all syscalls with child's pid
 * parent tells child to go & waits for sigchld
 * child exec's program
 * parent deletes rules after getting sigchld
 */
int main(int argc, char *argv[])
{
      int fd[2];
      int pid,cmd=1;
      char buf[2];

      if (argc < 2) {
            usage();
            return 1;
      }
      if (strcmp(argv[cmd], "-h") == 0) {
            usage();
            return 1;
      }
      if (strcmp(argv[cmd], "-r") == 0) {
            threat = 1;
            cmd++;
      }
      if (getuid() != 0) {
            fprintf(stderr, "You must be root to run this program.\n");
            return 1;
      }
      if (access(argv[cmd], X_OK)) {
            if (errno == ENOENT)
                  fprintf(stderr, "Error - can't find: %s\n", argv[cmd]); 
            else
                  fprintf(stderr, "Error checking %s (%s)\n", 
                        argv[cmd], strerror(errno));
            return 1;
      }
      set_aumessage_mode(MSG_STDERR, DBG_NO);
      switch (count_rules())
      {
            case -1:
                  if (errno == ECONNREFUSED)
                            fprintf(stderr,
                              "The audit system is disabled\n");
                  else
                        fprintf(stderr,
                              "Error - can't get rule count.\n");
                  return 1;
            case 0:
                  break;
            default:
                  fprintf(stderr, 
                  "autrace cannot be run with rules loaded.\n"
                  "Please delete all rules using 'auditctl -D' if you "
                  "really wanted to\nrun this command.\n");
                  return 1;
      }
      if (pipe(fd) != 0) {
            fprintf(stderr, "Error creating pipe.\n");
            return 1;
      }
      
      switch ((pid=fork()))
      {
            case -1:
                  fprintf(stderr, "Error forking.\n");
                  return 1;
            case 0: /* Child */
                  close(fd[1]);
                  printf("Waiting to execute: %s\n", argv[cmd]);
                  while (read(fd[0], buf, 1) == -1 && errno == EINTR)
                        /* blank */ ;
                  close(fd[0]);
                  execvp(argv[cmd], &argv[cmd]);
                  fprintf(stderr, "Failed to exec %s\n", argv[cmd]);
                  return 1;
            default: /* Parent */
                  close(fd[0]);
                  fcntl(fd[1], F_SETFD, FD_CLOEXEC);
                  {
                        char rule[16];
                        int audit_fd;
                        audit_fd = audit_open();
                        if (audit_fd < 0)
                              exit(1);
                        snprintf(rule, sizeof(rule), "pid=%d", pid);
                        if (insert_rule(audit_fd, rule)) {
                              kill(pid,SIGTERM);
                              (void)delete_all_rules(audit_fd);
                              exit(1);
                        }
                        snprintf(rule, sizeof(rule), "ppid=%d", pid);
                        if (insert_rule(audit_fd, rule)) {
                              kill(pid,SIGTERM);
                              (void)delete_all_rules(audit_fd);
                              exit(1);
                        }
                        sleep(1);
                        (void)write(fd[1],"1", 1);
                        waitpid(pid, NULL, 0);
                        close(fd[1]);
                        puts("Cleaning up...");
                        (void)delete_all_rules(audit_fd);
                        close(audit_fd);
                  }
                  printf("Trace complete. "
                        "You can locate the records with "
                        "\'ausearch -i -p %d\'\n",
                        pid);
                  break;
      }

      return 0;
}

static int count_rules(void)
{
      int fd, total, rc;

      fd = audit_open();
      if (fd < 0) 
            return -1;

      rc = audit_request_rules_list(fd);
      if (rc > 0) 
            total = count_em(fd);
      else 
            total = -1;

      close(fd); 
      return total;
}

static int count_em(int fd)
{
      int i, retval, count = 0;
      int timeout = 40; /* loop has delay of .1 - this is 4 seconds */
      struct audit_reply rep;
      fd_set read_mask;

      FD_ZERO(&read_mask);
      FD_SET(fd, &read_mask);

      for (i = 0; i < timeout; i++) {
            retval = audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
            if (retval > 0) {
                  struct timeval t;

                  if (rep.type == NLMSG_ERROR && 
                              rep.error->error == 0)
                        continue;
                  t.tv_sec  = 0;
                  t.tv_usec = 100000; /* .1 second */
                  do {
                        retval=select(fd+1, &read_mask, NULL, NULL, &t);
                  } while (retval < 0 && errno == EINTR);
                  switch (rep.type)
                  {
                        case NLMSG_DONE:
                              return count;
                        case AUDIT_LIST:
                              i = 0;
                              count++;
                              break;
                        case NLMSG_ERROR:
                              return -1;
                        default:
                              break;
                  }
            }
      }
      return count;
}


Generated by  Doxygen 1.6.0   Back to index