Home | History | Annotate | Line # | Download | only in veriexecctl
veriexecctl.c revision 1.13
      1 /*	$NetBSD: veriexecctl.c,v 1.13 2005/06/01 18:29:16 elad Exp $	*/
      2 
      3 /*-
      4  * Copyright 2005 Elad Efrat <elad (at) bsd.org.il>
      5  * Copyright 2005 Brett Lymn <blymn (at) netbsd.org>
      6  *
      7  * All rights reserved.
      8  *
      9  * This code has been donated to The NetBSD Foundation by the Author.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. The name of the author may not be used to endorse or promote products
     17  *    derived from this software withough specific prior written permission
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  *
     30  *
     31  */
     32 
     33 #include <sys/ioctl.h>
     34 #include <sys/param.h>
     35 #include <sys/queue.h>
     36 #include <sys/verified_exec.h>
     37 
     38 #include <stdio.h>
     39 #include <stdlib.h>
     40 #include <string.h>
     41 #include <fcntl.h>
     42 #include <unistd.h>
     43 #include <err.h>
     44 #include <errno.h>
     45 
     46 #include "veriexecctl.h"
     47 
     48 #define	VERIEXEC_DEVICE	"/dev/veriexec"
     49 
     50 extern struct veriexec_params params; /* in veriexecctl_parse.y */
     51 extern char *filename; /* in veriexecctl_conf.l */
     52 int gfd, verbose = 0, phase;
     53 size_t line;
     54 
     55 /*
     56  * Prototypes
     57  */
     58 static FILE *openlock(const char *);
     59 static void phase1_preload(void);
     60 static int fingerprint_load(char*);
     61 static void usage(void) __attribute__((__noreturn__));
     62 
     63 
     64 static FILE *
     65 openlock(const char *path)
     66 {
     67 	int lfd;
     68 
     69 	if ((lfd = open(path, O_RDONLY|O_EXLOCK, 0)) == -1)
     70 		return NULL;
     71 
     72 	return fdopen(lfd, "r");
     73 }
     74 
     75 struct veriexec_up *
     76 dev_lookup(dev_t d)
     77 {
     78 	struct veriexec_up *p;
     79 
     80 	CIRCLEQ_FOREACH(p, &params_list, vu_list)
     81 		if (p->vu_param.dev == d)
     82 			return (p);
     83 
     84 	return NULL;
     85 }
     86 
     87 struct veriexec_up *
     88 dev_add(dev_t d)
     89 {
     90 	struct veriexec_up *up;
     91 
     92 	if ((up = calloc((size_t)1, sizeof(*up))) == NULL)
     93 		err(1, "No memory");
     94 
     95 	up->vu_param.dev = d;
     96 	up->vu_param.hash_size = 1;
     97 
     98 	CIRCLEQ_INSERT_TAIL(&params_list, up, vu_list);
     99 
    100 	return up;
    101 }
    102 
    103 /* Load all devices, get rid of the list. */
    104 static void
    105 phase1_preload(void)
    106 {
    107 	if (verbose)
    108 		printf("Phase 1: Calculating hash table sizes:\n");
    109 
    110 	while (!CIRCLEQ_EMPTY(&params_list)) {
    111 		struct veriexec_up *vup;
    112 
    113 		vup = CIRCLEQ_FIRST(&params_list);
    114 
    115 		if (ioctl(gfd, VERIEXEC_TABLESIZE, &(vup->vu_param)) == -1)
    116 			err(1, "Error in phase 1: Can't "
    117 			    "set hash table size for device %d",
    118 			    vup->vu_param.dev);
    119 
    120 		if (verbose) {
    121 			printf(" => Hash table sizing successful for device "
    122 			    "%d. (%zu entries)\n", vup->vu_param.dev,
    123 			    vup->vu_param.hash_size);
    124 		}
    125 
    126 		CIRCLEQ_REMOVE(&params_list, vup, vu_list);
    127 		free(vup);
    128 	}
    129 }
    130 
    131 /*
    132  * Load the fingerprint. Assumes that the fingerprint pseudo-device is
    133  * opened and the file handle is in gfd.
    134  */
    135 void
    136 phase2_load(void)
    137 {
    138 	if (ioctl(gfd, VERIEXEC_LOAD, &params) == -1)
    139 		warn("Cannot load params from `%s'", params.file);
    140 	free(params.fingerprint);
    141 }
    142 
    143 /*
    144  * Fingerprint load handling.
    145  */
    146 static int
    147 fingerprint_load(char *ifile)
    148 {
    149 	CIRCLEQ_INIT(&params_list);
    150 
    151 	if ((yyin = openlock(ifile)) == NULL)
    152 		err(1, "Cannot open `%s'", ifile);
    153 
    154 	/*
    155 	 * Phase 1: Scan all config files, creating the list of devices
    156 	 *	    we have fingerprinted files on, and the amount of
    157 	 *	    files per device. Lock all files to maintain sync.
    158 	 */
    159 	phase = 1;
    160 
    161 	if (verbose) {
    162 		(void)printf("Phase 1: Building hash table information:\n");
    163 		(void)printf("=> Parsing \"%s\"\n", ifile);
    164 	}
    165 
    166 	yyparse();
    167 
    168 	phase1_preload();
    169 
    170 	/*
    171 	 * Phase 2: After we have a circular queue containing all the
    172 	 * 	    devices we care about and the sizes for the hash
    173 	 *	    tables, do a rescan, this time actually loading the
    174 	 *	    file data.
    175 	 */
    176 	rewind(yyin);
    177 	phase = 2;
    178 	if (verbose) {
    179 		(void)printf("Phase 2: Loading per-file fingerprints.\n");
    180 		(void)printf("=> Parsing \"%s\"\n", ifile);
    181 	}
    182 
    183 	yyparse();
    184 
    185 	(void)fclose(yyin);
    186 
    187 	return 0;
    188 }
    189 
    190 static void
    191 usage(void)
    192 {
    193 	(void)fprintf(stderr, "Usage: %s [-v] [load <signature_file>]\n",
    194 	    getprogname());
    195 	exit(1);
    196 }
    197 
    198 int
    199 main(int argc, char **argv)
    200 {
    201 	int c;
    202 
    203 	setprogname(argv[0]);
    204 
    205 	while ((c = getopt(argc, argv, "v")) != -1)
    206 		switch (c) {
    207 		case 'v':
    208 			verbose = 1;
    209 			break;
    210 
    211 		default:
    212 			usage();
    213 		}
    214 
    215 	argc -= optind;
    216 	argv += optind;
    217 
    218 	if ((gfd = open(VERIEXEC_DEVICE, O_RDWR, 0)) == -1)
    219 		err(1, "Cannot open `%s'", VERIEXEC_DEVICE);
    220 
    221 	/*
    222 	 * Handle the different commands we can do.
    223 	 */
    224 	if (argc == 2 && strcasecmp(argv[0], "load") == 0) {
    225 		line = 0;
    226 		filename = argv[1];
    227 		fingerprint_load(argv[1]);
    228 	} else
    229 		usage();
    230 
    231 	(void)close(gfd);
    232 	return 0;
    233 }
    234