veriexecctl.c revision 1.7 1 /* $NetBSD: veriexecctl.c,v 1.7 2005/04/21 11:21:58 he 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 #define usage(code) errx(code, "Usage: %s [-v] [load <signature_file>] " \
51 "[fingerprints]", \
52 getprogname())
53
54 extern struct veriexec_params params; /* in veriexecctl_parse.y */
55 extern char *filename; /* in veriexecctl_conf.l */
56 int gfd, verbose = 0, no_mem = 0, phase;
57 unsigned line;
58
59 /*
60 * Prototypes
61 */
62 int fingerprint_load(char*);
63
64
65 FILE *
66 openlock(const char *path)
67 {
68 int lfd;
69
70 lfd = open(path, O_RDONLY|O_EXLOCK, 0);
71 if (lfd < 0)
72 return (NULL);
73
74 return (fdopen(lfd, "r"));
75 }
76
77 struct vexec_up *
78 dev_lookup(dev_t d)
79 {
80 struct vexec_up *p;
81
82 CIRCLEQ_FOREACH(p, ¶ms_list, vu_list) {
83 if (p->vu_param.dev == d)
84 return (p);
85 }
86
87 return (NULL);
88 }
89
90 struct vexec_up *
91 dev_add(dev_t d)
92 {
93 struct vexec_up *up;
94
95 up = calloc(1, sizeof(*up));
96 if (up == NULL)
97 err(1, "No memory");
98
99 up->vu_param.dev = d;
100 up->vu_param.hash_size = 1;
101
102 CIRCLEQ_INSERT_TAIL(¶ms_list, up, vu_list);
103
104 return (up);
105 }
106
107 /* Load all devices, get rid of the list. */
108 int
109 phase1_preload(void)
110 {
111 if (verbose)
112 printf("Phase 1: Calculating hash table sizes:\n");
113
114 while (!CIRCLEQ_EMPTY(¶ms_list)) {
115 struct vexec_up *vup;
116
117 vup = CIRCLEQ_FIRST(¶ms_list);
118
119 if (ioctl(gfd, VERIEXEC_TABLESIZE, &(vup->vu_param)) < 0) {
120 (void) fprintf(stderr, "Error in phase 1: Can't "
121 "set hash table size for device %d: %s.\n",
122 vup->vu_param.dev, strerror(errno));
123
124 return (-1);
125 }
126
127 if (verbose) {
128 printf(" => Hash table sizing successful for device "
129 "%d. (%zu entries)\n", vup->vu_param.dev,
130 vup->vu_param.hash_size);
131 }
132
133 CIRCLEQ_REMOVE(¶ms_list, vup, vu_list);
134 free(vup);
135 }
136
137 return (0);
138 }
139
140 /*
141 * Load the fingerprint. Assumes that the fingerprint pseudo-device is
142 * opened and the file handle is in gfd.
143 */
144 void
145 phase2_load(void)
146 {
147 if (ioctl(gfd, VERIEXEC_LOAD, ¶ms) < 0) {
148 (void) fprintf(stderr, "%s: %s\n", params.file,
149 strerror(errno));
150 }
151 free(params.fingerprint);
152 }
153
154 /*
155 * Fingerprint load handling.
156 */
157 int
158 fingerprint_load(char *ifile)
159 {
160 CIRCLEQ_INIT(¶ms_list);
161
162 if ((yyin = openlock(ifile)) == NULL) {
163 err(1, "Failed to open %s", ifile);
164 }
165
166 /*
167 * Phase 1: Scan all config files, creating the list of devices
168 * we have fingerprinted files on, and the amount of
169 * files per device. Lock all files to maintain sync.
170 */
171 phase = 1;
172
173 if (verbose) {
174 (void) fprintf(stderr, "Phase 1: Building hash table information:\n");
175 (void) fprintf(stderr, "=> Parsing \"%s\"\n", ifile);
176 }
177
178 yyparse();
179
180 if (phase1_preload() < 0)
181 exit(1);
182
183 /*
184 * Phase 2: After we have a circular queue containing all the
185 * devices we care about and the sizes for the hash
186 * tables, do a rescan, this time actually loading the
187 * file data.
188 */
189 rewind(yyin);
190 phase = 2;
191 if (verbose) {
192 (void) fprintf(stderr, "Phase 2: Loading per-file "
193 "fingerprints.\n");
194 (void) fprintf(stderr, "=> Parsing \"%s\"\n", ifile);
195 }
196
197 yyparse();
198
199 (void) fclose(yyin);
200
201 return(0);
202 }
203
204 int
205 main(int argc, char **argv)
206 {
207 char *newp;
208 int c;
209 unsigned size;
210 struct veriexec_fp_report report;
211
212 if ((argc < 2) || (argc > 4)) {
213 usage(1);
214 }
215
216 while ((c = getopt(argc, argv, "v")) != -1) {
217 switch (c) {
218 case 'v':
219 verbose = 1;
220 break;
221
222 default:
223 usage(1);
224 }
225 }
226
227 argc -= optind;
228 argv += optind;
229
230 gfd = open(VERIEXEC_DEVICE, O_RDWR, 0);
231 if (gfd == -1) {
232 err(1, "Failed to open pseudo-device");
233 }
234
235 /*
236 * Handle the different commands we can do.
237 */
238 if (strcasecmp(argv[0], "load") == 0) {
239 line = 0;
240 filename = argv[1];
241 fingerprint_load(argv[1]);
242 } else if (strcasecmp(argv[0], "fingerprints") == 0) {
243 size = report.size = 100;
244 if ((report.fingerprints = malloc(report.size)) == NULL) {
245 fprintf(stderr, "fingerprints: malloc failed.\n");
246 exit(1);
247 }
248
249 if (ioctl(gfd, VERIEXEC_FINGERPRINTS, &report) == 0) {
250 if (size != report.size) {
251 if (verbose)
252 fprintf(stderr, "fingerprints: "
253 "buffer insufficient, "
254 "reallocating to %d bytes.\n",
255 report.size);
256
257 /* fingerprint store was not large enough
258 make more room and try again. */
259 if ((newp = realloc(report.fingerprints,
260 report.size)) == NULL) {
261 fprintf(stderr, "fingerprints: "
262 "realloc failed\n");
263 exit(1);
264 }
265 if (ioctl(gfd, VERIEXEC_FINGERPRINTS,
266 &report) < 0) {
267 fprintf(stderr,
268 "fingerprints ioctl: %s\n",
269 strerror(errno));
270 exit(1);
271 }
272 }
273 } else {
274 (void) fprintf(stderr,
275 "fingerprints ioctl: %s\n",
276 strerror(errno));
277 exit(1);
278 }
279
280 printf("Supported fingerprints: %s\n", report.fingerprints);
281 } else {
282 usage(1);
283 }
284
285 (void) close(gfd);
286 return (0);
287 }
288