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

bfbtester.c

/*
    BFBTester -- Brute Force Binary Tester
    Copyright (C) 2000 Mike Heffner <mheffner@vt.edu>

    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., 675 Mass Ave, Cambridge, MA 02139, USA.

      $Id: bfbtester.c,v 1.4.2.2 2001/01/22 05:31:12 fesnel Exp $
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/param.h>
#include <dirent.h>

#include "datatypes.h"
#include "data_stuff.h"
#include "main.h"
#include "breaker.h"
#include "utils.h"
#include "tempfiles.h"

#define MAX_SIMULTANEOUS_EXECS      250

static void
usage(char *progname);

static void
run_breaker(void);

static void
load_execs(char **av, ExecEntryStatus status, int flags, char *rejects);

THREAD_DATA *q;

FILE        *fp_msg = NULL;
int               debug_level;

extern int  optind;
extern char *optarg;

int
main( int ac, char ** av )
{
      char *progname, *rejects = NULL;
      int t_on = FALSE; /* tempfile monitoring */
      int   max_execs = MAX_SIMULTANEOUS_EXECS;
      int ch, flags = 0;

      if ((progname = strrchr(av[0], '/')) != NULL)
            progname++;
      else
            progname = av[0];

      while ((ch = getopt(ac, av, "ad:ehmo:r:stvx:")) != -1)
            switch (ch) {
            case 'a':
                  flags |= FLAGS_ALL;
                  break;
            case 'd':
                  debug_level = atoi(optarg);
                  break;
            case 'e':
                  flags |= FLAGS_ENV_TEST;
                  break;
            case 'h':
                  usage(progname);
                  break;
            case 'm':
                  flags |= FLAGS_MULTIPLE_ARG_TEST;
                  break;
            case 'o':
                  if ((fp_msg = fopen(optarg, "w")) == NULL) {
                        printf("Can't open output file: %s\n", optarg);
                        return -1;
                  }
                  break;
            case 'r':
                  rejects = optarg;
                  break;
            case 's':
                  flags |= FLAGS_SINGLE_ARG_TEST;
                  break;
            case 't':
                  t_on = TRUE;
                  break;
            case 'v':
                  printf("%s v. %s\n", IDSTR, VERSTR);
                  return 0;
                  /* NO FALL-THROUGH */
            case 'x':
                  max_execs = atoi(optarg);
                  break;
            default:
                  usage(progname);
                  /* NOTREACHED */
            }

      ac -= optind;
      av += optind;

      if (fp_msg == NULL)
            fp_msg = stdout;
      if (!flags || *av == NULL)
            usage(progname);

      q = xcalloc(1, sizeof(THREAD_DATA));
      q->max_execs = max_execs;
      q->mut = xmalloc(sizeof(pthread_mutex_t));

      if (pthread_mutex_init(q->mut, NULL) != 0)
            bfbt_message(MSG_TYPE_ERRNO_ABORT, "mutex init");

#ifdef SOLARIS
      {
            /*
             * On Solaris 2.5, threads are not timesliced so we
             * must increase the concurrency.
             */
            int ret;

            if (t_on)
                  ret = thr_setconcurrency(3);
            else
                  ret = thr_setconcurrency(2);
            if (ret != 0)
                  bfbt_message(MSG_TYPE_ERROR_ABORT, "Can't set thread concurrency");
      }
#endif /* SOLARIS */

      if (t_on)
            tempfile_start(q);

      load_execs(av, EXEC_ENTRY_STATUS_TEST, flags, rejects);
      run_breaker();

      return 0;

}

static void
usage(char *progname)
{
      printf("%s [-htv] [-d level ] [-r rejects] [-o out-file]\n"
               "%*s [-x max-execs] -asme file [file2 file3 ...]\n"
               "Must specify one or more of the following tests:\n"
               "    -s  Single Argument Test\n"
               "    -m  Multiple Argument Test\n"
               "    -e  Environment Variable Test\n"
               "    -a  Selects all tests\n"
               "Options:\n"
               "    -h  Print this message\n"
               "    -t  Enable tempfile monitoring\n"
               "    -v  Print version string\n"
               "    -d level     Set debug level (default = 0, max = 2)\n"
               "    -r rejects   Comma separated list of binaries to skip\n"
               "    -o out-file  Output to out-file rather than stdout\n"
               "    -x max-execs Set maximum executables to run in parallel (default = %d)\n"
               "file    Specific binary or a directory of binaries to test\n",
               progname, (int)strlen(progname), "", MAX_SIMULTANEOUS_EXECS);
      exit(2);
}

static void
add_exec(char *filename, ExecEntryStatus status, int flags, char *rejects)
{
      struct stat sb;
      /* Test if exec is to be rejected */
      if (rejects) {
            char *ptr, *ptr2;

            if((ptr=strstr(rejects, filename)))
                  if(ptr == rejects || *(ptr-1) == ' ' || *(ptr-1) == ',')
                        if(*(ptr+strlen(filename)) == '\0' || *(ptr+strlen(filename)) == ' ' ||
                           *(ptr+strlen(filename)) == ',')
                              return;
            if( (ptr2=strrchr(filename, '/')) && (ptr=strstr(rejects, ++ptr2)) )
                  if(ptr == rejects || *(ptr-1) == ' ' || *(ptr-1) == ',')
                        if(*(ptr+strlen(ptr2)) == '\0' || *(ptr+strlen(ptr2)) == ' ' ||
                           *(ptr+strlen(ptr2)) == ',')
                              return;
      }
      /* Test that executable file is valid and accessible */
      if (stat(filename, &sb) == 0 && S_ISREG(sb.st_mode)
            && access(filename, F_OK|X_OK) == 0)
            /* If we get to here we are safe to add it */
            ExecEntry_add(filename, &sb, status, flags);
}

/* XXX: This is somewhat of a mess */
static void
load_execs(char **av, ExecEntryStatus status, int flags, char *rejects)
{
      struct stat sb;
      char *filename;
      char *pwd = getenv("PWD");

      for (; *av; av++) {
            /* Executable selection is done in one of several ways:
             *
             * If the executable filename is specified with a leading
             * slash (an absolute path), no selection is used and the
             * supplied absolute filename is used.
             *
             * If there is no leading slash in the filename the selection
             * is made in one of two ways (in this order):
             *   1) Prepend file name with $PWD and test accesiblity
             *   2) Search through $PATH and find first accessible executable
             * The first one to succeed is the executable choosen.
             *
             * If the filename found is a directory, we walk the directory (one
             * level deep) looking for executable binaries.
             *
             * Symbolic links are followed.
             */

            /* already in full pathname form */
            if (*av[0] == '/')
                  filename = strdup(*av);
            /* test whether the executable is in the current directory */
            else if (pwd
                         && (filename = xmalloc(strlen(pwd) + strlen(*av) + 2))
                         && sprintf(filename, "%s%s%s", pwd, pwd[strlen(pwd)-1] == '/' ? "" : "/", *av)
                         && access(filename, F_OK|X_OK) == 0)
                  ;
            /* or in the user's PATH */
            else
                  filename = find_exec_in_path(*av);

            if (filename && stat(filename, &sb) == 0
                  && access(filename, F_OK|X_OK) == 0) {
                  
                  if (S_ISDIR(sb.st_mode)) {          /* Walk directory */
                        DIR *dir;
                        struct dirent entry, *result;
                        int ret;
                        char fname[MAXPATHLEN];
                        
                        if ((dir = opendir(filename)) == NULL) {
                              bfbt_message(MSG_TYPE_ERROR_WARN, "Can't open dir %s", 
                                                 filename);
                              free(filename);
                              continue;
                        }
                        ret = readdir_r(dir, &entry, &result);
                        while (ret == 0 && result != NULL) {
                              if (snprintf(fname, sizeof(fname), "%s%s%s", filename,
                                                 filename[strlen(filename)-1] == '/' ?
                                                 "" : "/", result->d_name) < sizeof(fname))
                                    add_exec(fname, status, flags, rejects);
                              ret = readdir_r(dir, &entry, &result);
                        }
                  } else                                          /* Treat as an executable */
                        add_exec(filename, status, flags, rejects);
            } else {
                  if (filename)
                        bfbt_message(MSG_TYPE_ERROR_WARN, "Can't access file: %s (%s)",
                                           filename, *av);
                  else
                        bfbt_message(MSG_TYPE_ERROR_WARN, "Can't find file: %s", *av);
            }
            if (filename)
                  free(filename);
      }
}

static void
run_breaker(void)
{
      if (!ExecEntry_isempty()) {
            breaker_start();
            breaker_wait();
      }
}

Generated by  Doxygen 1.6.0   Back to index