/*-
* Copyright (c) 2006 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Matt Fleming.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
/* this struct defines a hash algorithm */
typedef struct hash_t {
const char *hashname; /* algorithm name */
char *(*filefunc)(const char *, char *); /* function */
} hash_t;
/* this struct encapsulates various diverse options and arguments */
typedef struct veriexecgen_t {
int all_files; /* scan also for non-executable files */
int append_output; /* append output to existing sigs file */
char *dbfile; /* name of signatures database file */
int exit_on_error; /* exit if we can't create a hash */
char *prefix; /* any prefix to be discarded on output */
int recursive_scan;/* perform scan for files recursively */
int scan_system_dirs; /* just scan system directories */
int verbose; /* verbosity level */
int stamp; /* put a timestamp */
FILE *from_file; /* read from a file or stdin */
char *from_filename;
} veriexecgen_t;
/* this struct describes a directory entry to generate a hash for */
struct fentry {
char filename[MAXPATHLEN]; /* name of entry */
char *hash_val; /* its associated hash value */
int flags; /* any associated flags */
TAILQ_ENTRY(fentry) f; /* its place in the queue */
};
TAILQ_HEAD(, fentry) fehead;
static int make_immutable; /* set immutable flag on signatures file */
/* warn about a problem - exit if exit_on_error is set */
static void
gripe(veriexecgen_t *vp, const char *fmt, const char *filename)
{
warn(fmt, filename);
if (vp->exit_on_error) {
/* error out on problematic files */
exit(EXIT_FAILURE);
}
}
/* add a new entry to the list for `file' */
static void
add_new_path_entry(veriexecgen_t *vp, const char *file, hash_t *hash)
{
struct stat sb;
struct fentry *e;
if (stat(file, &sb) == -1) {
gripe(vp, "Cannot stat file `%s'", file);
return;
}
if (!vp->all_files && !IS_EXEC(sb.st_mode))
return;
/* add a new entry to the list for `file' */
static void
add_new_ftsent_entry(veriexecgen_t *vp, FTSENT *file, hash_t *hash)
{
struct fentry *e;
struct stat sb;
if (file->fts_info == FTS_SL) {
/* we have a symbolic link */
if (stat(file->fts_path, &sb) == -1) {
gripe(vp, "Cannot stat symlink `%s'", file->fts_path);
return;
}
} else
sb = *file->fts_statp;
if (!vp->all_files && !IS_EXEC(sb.st_mode))
return;
len = strlen(s);
if (len >= MAXPATHLEN)
return (NULL);
len *= 2;
q = p = calloc(1, len + 1);
while (*s) {
if (*s == ' ' || *s == '\t')
*p++ = '\\';
*p++ = *s++;
}
return (q);
}
/* store the list in the signatures file */
static void
store_entries(veriexecgen_t *vp, hash_t *hash)
{
FILE *fp;
int move = 1;
char old_dbfile[MAXPATHLEN];
time_t ct;
struct stat sb;
struct fentry *e;
int prefixc;
if (stat(vp->dbfile, &sb) != 0) {
if (errno == ENOENT)
move = 0;
else
err(EXIT_FAILURE, "could not stat %s", vp->dbfile);
}
if (move && !vp->append_output) {
if (vp->verbose)
(void)printf("\nBacking up existing fingerprint file "
"to \"%s.old\"\n\n", vp->dbfile);
if (snprintf(old_dbfile, sizeof(old_dbfile), "%s.old",
vp->dbfile) < strlen(vp->dbfile) + 4) {
err(EXIT_FAILURE, "%s", old_dbfile);
}
if (rename(vp->dbfile, old_dbfile) == -1)
err(EXIT_FAILURE, "could not rename file");
}
if (vp->verbose) {
(void)printf("\n\n"
"#############################################################\n"
" PLEASE VERIFY CONTENTS OF %s AND FINE-TUNE THE\n"
" FLAGS WHERE APPROPRIATE AFTER READING veriexecctl(8)\n"
"#############################################################\n",
vp->dbfile);
}
}
int
main(int argc, char **argv)
{
int ch, total = 0;
char **search_path = NULL;
hash_t *hash = NULL;
veriexecgen_t v;