xref: /freebsd/lib/libsecureboot/veopen.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
15fff9558SSimon J. Gerraty /*-
25fff9558SSimon J. Gerraty  * Copyright (c) 2017-2018, Juniper Networks, Inc.
35fff9558SSimon J. Gerraty  *
45fff9558SSimon J. Gerraty  * Redistribution and use in source and binary forms, with or without
55fff9558SSimon J. Gerraty  * modification, are permitted provided that the following conditions
65fff9558SSimon J. Gerraty  * are met:
75fff9558SSimon J. Gerraty  * 1. Redistributions of source code must retain the above copyright
85fff9558SSimon J. Gerraty  *    notice, this list of conditions and the following disclaimer.
95fff9558SSimon J. Gerraty  * 2. Redistributions in binary form must reproduce the above copyright
105fff9558SSimon J. Gerraty  *    notice, this list of conditions and the following disclaimer in the
115fff9558SSimon J. Gerraty  *    documentation and/or other materials provided with the distribution.
125fff9558SSimon J. Gerraty  *
135fff9558SSimon J. Gerraty  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
145fff9558SSimon J. Gerraty  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
155fff9558SSimon J. Gerraty  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
165fff9558SSimon J. Gerraty  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
175fff9558SSimon J. Gerraty  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
185fff9558SSimon J. Gerraty  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
195fff9558SSimon J. Gerraty  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
205fff9558SSimon J. Gerraty  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
215fff9558SSimon J. Gerraty  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
225fff9558SSimon J. Gerraty  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
235fff9558SSimon J. Gerraty  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
245fff9558SSimon J. Gerraty  */
255fff9558SSimon J. Gerraty #include <sys/cdefs.h>
265fff9558SSimon J. Gerraty #include <sys/queue.h>
275fff9558SSimon J. Gerraty 
285fff9558SSimon J. Gerraty #include "libsecureboot-priv.h"
295fff9558SSimon J. Gerraty 
305fff9558SSimon J. Gerraty 
315fff9558SSimon J. Gerraty struct fingerprint_info {
325fff9558SSimon J. Gerraty 	char		*fi_prefix;	/**< manifest entries relative to */
335fff9558SSimon J. Gerraty 	char		*fi_skip;	/**< manifest entries prefixed with  */
345fff9558SSimon J. Gerraty 	const char 	*fi_data;	/**< manifest data */
355fff9558SSimon J. Gerraty 	size_t		fi_prefix_len;	/**< length of prefix */
365fff9558SSimon J. Gerraty 	size_t		fi_skip_len;	/**< length of skip */
375fff9558SSimon J. Gerraty 	dev_t		fi_dev;		/**< device id  */
385fff9558SSimon J. Gerraty 	LIST_ENTRY(fingerprint_info) entries;
395fff9558SSimon J. Gerraty };
405fff9558SSimon J. Gerraty 
415fff9558SSimon J. Gerraty static LIST_HEAD(, fingerprint_info) fi_list;
425fff9558SSimon J. Gerraty 
435fff9558SSimon J. Gerraty static void
fingerprint_info_init(void)445fff9558SSimon J. Gerraty fingerprint_info_init(void)
455fff9558SSimon J. Gerraty {
465fff9558SSimon J. Gerraty 	static int once;
475fff9558SSimon J. Gerraty 
485fff9558SSimon J. Gerraty 	if (once)
495fff9558SSimon J. Gerraty 		return;
505fff9558SSimon J. Gerraty 	LIST_INIT(&fi_list);
515fff9558SSimon J. Gerraty 	once = 1;
525fff9558SSimon J. Gerraty }
535fff9558SSimon J. Gerraty 
545fff9558SSimon J. Gerraty /**
555fff9558SSimon J. Gerraty  * @brief
565fff9558SSimon J. Gerraty  * add manifest data to list
575fff9558SSimon J. Gerraty  *
585fff9558SSimon J. Gerraty  * list is kept sorted by longest prefix.
595fff9558SSimon J. Gerraty  *
605fff9558SSimon J. Gerraty  * @param[in] prefix
615fff9558SSimon J. Gerraty  *	path that all manifest entries are resolved via
625fff9558SSimon J. Gerraty  *
635fff9558SSimon J. Gerraty  * @param[in] skip
645fff9558SSimon J. Gerraty  *	optional prefix within manifest entries which should be skipped
655fff9558SSimon J. Gerraty  *
665fff9558SSimon J. Gerraty  * @param[in] data
675fff9558SSimon J. Gerraty  *	manifest data
685fff9558SSimon J. Gerraty  */
695fff9558SSimon J. Gerraty void
fingerprint_info_add(const char * filename,const char * prefix,const char * skip,const char * data,struct stat * stp)705fff9558SSimon J. Gerraty fingerprint_info_add(const char *filename, const char *prefix,
715fff9558SSimon J. Gerraty     const char *skip, const char *data, struct stat *stp)
725fff9558SSimon J. Gerraty {
735fff9558SSimon J. Gerraty 	struct fingerprint_info *fip, *nfip, *lfip;
745fff9558SSimon J. Gerraty 	char *cp;
755fff9558SSimon J. Gerraty 	int n;
765fff9558SSimon J. Gerraty 
775fff9558SSimon J. Gerraty 	fingerprint_info_init();
785fff9558SSimon J. Gerraty 	nfip = malloc(sizeof(struct fingerprint_info));
79*66655411SSimon J. Gerraty 	if (nfip == NULL) {
80*66655411SSimon J. Gerraty #ifdef _STANDALONE
81*66655411SSimon J. Gerraty 		printf("%s: out of memory! %lu\n", __func__,
82*66655411SSimon J. Gerraty 		    (unsigned long)sizeof(struct fingerprint_info));
83*66655411SSimon J. Gerraty #endif
84*66655411SSimon J. Gerraty 		return;
85*66655411SSimon J. Gerraty 	}
865fff9558SSimon J. Gerraty 	if (prefix) {
875fff9558SSimon J. Gerraty 		nfip->fi_prefix = strdup(prefix);
885fff9558SSimon J. Gerraty 	} else {
895fff9558SSimon J. Gerraty 		if (!filename) {
905fff9558SSimon J. Gerraty 			free(nfip);
915fff9558SSimon J. Gerraty 			return;
925fff9558SSimon J. Gerraty 		}
935fff9558SSimon J. Gerraty 		nfip->fi_prefix = strdup(filename);
945fff9558SSimon J. Gerraty 		cp = strrchr(nfip->fi_prefix, '/');
9553f151f9SSimon J. Gerraty 		if (cp == nfip->fi_prefix) {
9653f151f9SSimon J. Gerraty 			cp[1] = '\0';
9753f151f9SSimon J. Gerraty 		} else if (cp) {
985fff9558SSimon J. Gerraty 			*cp = '\0';
9953f151f9SSimon J. Gerraty 		} else {
1005fff9558SSimon J. Gerraty 			free(nfip->fi_prefix);
1015fff9558SSimon J. Gerraty 			free(nfip);
1025fff9558SSimon J. Gerraty 			return;
1035fff9558SSimon J. Gerraty 		}
1045fff9558SSimon J. Gerraty 	}
1055fff9558SSimon J. Gerraty 	/* collapse any trailing ..[/] */
1065fff9558SSimon J. Gerraty 	n = 0;
10753f151f9SSimon J. Gerraty 	while ((cp = strrchr(nfip->fi_prefix, '/')) > nfip->fi_prefix) {
1085fff9558SSimon J. Gerraty 		if (cp[1] == '\0') {	/* trailing "/" */
1095fff9558SSimon J. Gerraty 			*cp = '\0';
1105fff9558SSimon J. Gerraty 			continue;
1115fff9558SSimon J. Gerraty 		}
1125fff9558SSimon J. Gerraty 		if (strcmp(&cp[1], "..") == 0) {
1135fff9558SSimon J. Gerraty 			n++;
1145fff9558SSimon J. Gerraty 			*cp = '\0';
1155fff9558SSimon J. Gerraty 			continue;
1165fff9558SSimon J. Gerraty 		}
1175fff9558SSimon J. Gerraty 		if (n > 0) {
1185fff9558SSimon J. Gerraty 			n--;
1195fff9558SSimon J. Gerraty 			*cp = '\0';
1205fff9558SSimon J. Gerraty 		}
1215fff9558SSimon J. Gerraty 		if (n == 0)
1225fff9558SSimon J. Gerraty 			break;
1235fff9558SSimon J. Gerraty 	}
124*66655411SSimon J. Gerraty 	nfip->fi_dev = stp->st_dev;
1255fff9558SSimon J. Gerraty #ifdef UNIT_TEST
1265fff9558SSimon J. Gerraty 	nfip->fi_dev = 0;
1275fff9558SSimon J. Gerraty #endif
1285fff9558SSimon J. Gerraty 	nfip->fi_data = data;
1295fff9558SSimon J. Gerraty 	nfip->fi_prefix_len = strlen(nfip->fi_prefix);
1305fff9558SSimon J. Gerraty 	if (skip) {
1315fff9558SSimon J. Gerraty 		nfip->fi_skip_len = strlen(skip);
1325fff9558SSimon J. Gerraty 		if (nfip->fi_skip_len)
1335fff9558SSimon J. Gerraty 			nfip->fi_skip = strdup(skip);
1345fff9558SSimon J. Gerraty 		else
1355fff9558SSimon J. Gerraty 			nfip->fi_skip = NULL;
1365fff9558SSimon J. Gerraty 	} else {
1375fff9558SSimon J. Gerraty 		nfip->fi_skip = NULL;
1385fff9558SSimon J. Gerraty 		nfip->fi_skip_len = 0;
1395fff9558SSimon J. Gerraty 	}
1405fff9558SSimon J. Gerraty 
1415fff9558SSimon J. Gerraty 	if (LIST_EMPTY(&fi_list)) {
1425fff9558SSimon J. Gerraty 		LIST_INSERT_HEAD(&fi_list, nfip, entries);
1435fff9558SSimon J. Gerraty 		DEBUG_PRINTF(4, ("inserted %zu %s at head\n",
1445fff9558SSimon J. Gerraty 			nfip->fi_prefix_len, nfip->fi_prefix));
1455fff9558SSimon J. Gerraty 		return;
1465fff9558SSimon J. Gerraty 	}
1475fff9558SSimon J. Gerraty 	LIST_FOREACH(fip, &fi_list, entries) {
1485fff9558SSimon J. Gerraty 		if (nfip->fi_prefix_len >= fip->fi_prefix_len) {
1495fff9558SSimon J. Gerraty 			LIST_INSERT_BEFORE(fip, nfip, entries);
1505fff9558SSimon J. Gerraty 			DEBUG_PRINTF(4, ("inserted %zu %s before %zu %s\n",
1515fff9558SSimon J. Gerraty 				nfip->fi_prefix_len, nfip->fi_prefix,
1525fff9558SSimon J. Gerraty 				fip->fi_prefix_len, fip->fi_prefix));
1535fff9558SSimon J. Gerraty 			return;
1545fff9558SSimon J. Gerraty 		}
1555fff9558SSimon J. Gerraty 		lfip = fip;
1565fff9558SSimon J. Gerraty 	}
1575fff9558SSimon J. Gerraty 	LIST_INSERT_AFTER(lfip, nfip, entries);
1585fff9558SSimon J. Gerraty 	DEBUG_PRINTF(4, ("inserted %zu %s after %zu %s\n",
1595fff9558SSimon J. Gerraty 		nfip->fi_prefix_len, nfip->fi_prefix,
1605fff9558SSimon J. Gerraty 		lfip->fi_prefix_len, lfip->fi_prefix));
1615fff9558SSimon J. Gerraty }
1625fff9558SSimon J. Gerraty 
1635fff9558SSimon J. Gerraty #ifdef MANIFEST_SKIP_MAYBE
1645fff9558SSimon J. Gerraty /*
1655fff9558SSimon J. Gerraty  * Deal with old incompatible boot/manifest
1665fff9558SSimon J. Gerraty  * if fp[-1] is '/' and start of entry matches
1675fff9558SSimon J. Gerraty  * MANIFEST_SKIP_MAYBE, we want it.
1685fff9558SSimon J. Gerraty  */
1695fff9558SSimon J. Gerraty static char *
maybe_skip(char * fp,struct fingerprint_info * fip,size_t * nplenp)1705fff9558SSimon J. Gerraty maybe_skip(char *fp, struct fingerprint_info *fip, size_t *nplenp)
1715fff9558SSimon J. Gerraty {
1725fff9558SSimon J. Gerraty 	char *tp;
1735fff9558SSimon J. Gerraty 
1745fff9558SSimon J. Gerraty 	tp = fp - sizeof(MANIFEST_SKIP_MAYBE);
1755fff9558SSimon J. Gerraty 
1765fff9558SSimon J. Gerraty 	if (tp >= fip->fi_data) {
1775fff9558SSimon J. Gerraty 		DEBUG_PRINTF(3, ("maybe: %.48s\n", tp));
1785fff9558SSimon J. Gerraty 		if ((tp == fip->fi_data || tp[-1] == '\n') &&
1795fff9558SSimon J. Gerraty 		    strncmp(tp, MANIFEST_SKIP_MAYBE,
1805fff9558SSimon J. Gerraty 			sizeof(MANIFEST_SKIP_MAYBE) - 1) == 0) {
1815fff9558SSimon J. Gerraty 			fp = tp;
1825fff9558SSimon J. Gerraty 			*nplenp += sizeof(MANIFEST_SKIP_MAYBE);
1835fff9558SSimon J. Gerraty 		}
1845fff9558SSimon J. Gerraty 	}
1855fff9558SSimon J. Gerraty 	return (fp);
1865fff9558SSimon J. Gerraty }
1875fff9558SSimon J. Gerraty #endif
1885fff9558SSimon J. Gerraty 
1895fff9558SSimon J. Gerraty char *
fingerprint_info_lookup(int fd,const char * path)1905fff9558SSimon J. Gerraty fingerprint_info_lookup(int fd, const char *path)
1915fff9558SSimon J. Gerraty {
1925fff9558SSimon J. Gerraty 	char pbuf[MAXPATHLEN+1];
1935fff9558SSimon J. Gerraty 	char nbuf[MAXPATHLEN+1];
1945fff9558SSimon J. Gerraty 	struct stat st;
1955fff9558SSimon J. Gerraty 	struct fingerprint_info *fip;
1965fff9558SSimon J. Gerraty 	char *cp, *ep, *fp, *np;
1975fff9558SSimon J. Gerraty 	const char *prefix;
1985fff9558SSimon J. Gerraty 	size_t n, plen, nlen, nplen;
1995fff9558SSimon J. Gerraty 	dev_t dev = 0;
2005fff9558SSimon J. Gerraty 
2015fff9558SSimon J. Gerraty 	fingerprint_info_init();
2025fff9558SSimon J. Gerraty 
2035fff9558SSimon J. Gerraty 	n = strlcpy(pbuf, path, sizeof(pbuf));
2045fff9558SSimon J. Gerraty 	if (n >= sizeof(pbuf))
2055fff9558SSimon J. Gerraty 		return (NULL);
2065fff9558SSimon J. Gerraty 	if (fstat(fd, &st) == 0)
2075fff9558SSimon J. Gerraty 		dev = st.st_dev;
208*66655411SSimon J. Gerraty #ifdef UNIT_TEST
209*66655411SSimon J. Gerraty 	dev = 0;
2105fff9558SSimon J. Gerraty #endif
2115fff9558SSimon J. Gerraty 	/*
2125fff9558SSimon J. Gerraty 	 * get the first entry - it will have longest prefix
2135fff9558SSimon J. Gerraty 	 * so we can can work out how to initially split path
2145fff9558SSimon J. Gerraty 	 */
2155fff9558SSimon J. Gerraty 	fip = LIST_FIRST(&fi_list);
2165fff9558SSimon J. Gerraty 	if (!fip)
2175fff9558SSimon J. Gerraty 		return (NULL);
2185fff9558SSimon J. Gerraty 	prefix = pbuf;
2195fff9558SSimon J. Gerraty 	ep = NULL;
2205fff9558SSimon J. Gerraty 	cp = &pbuf[fip->fi_prefix_len];
2215fff9558SSimon J. Gerraty 	do {
2225fff9558SSimon J. Gerraty 		if (ep) {
2235fff9558SSimon J. Gerraty 			*ep = '/';
2245fff9558SSimon J. Gerraty 			cp -= 2;
2255fff9558SSimon J. Gerraty 			if (cp < pbuf)
2265fff9558SSimon J. Gerraty 				break;
2275fff9558SSimon J. Gerraty 		}
2285fff9558SSimon J. Gerraty 		nlen = plen = 0;	/* keep gcc quiet */
2295fff9558SSimon J. Gerraty 		if (cp > pbuf) {
2305fff9558SSimon J. Gerraty 			for ( ; cp >= pbuf && *cp != '/'; cp--)
2315fff9558SSimon J. Gerraty 				;	/* nothing */
2325fff9558SSimon J. Gerraty 			if (cp > pbuf) {
2335fff9558SSimon J. Gerraty 				ep = cp++;
2345fff9558SSimon J. Gerraty 				*ep = '\0';
2355fff9558SSimon J. Gerraty 			} else {
2365fff9558SSimon J. Gerraty 				cp = pbuf;
2375fff9558SSimon J. Gerraty 			}
2385fff9558SSimon J. Gerraty 			if (ep) {
2395fff9558SSimon J. Gerraty 				plen = ep - pbuf;
2405fff9558SSimon J. Gerraty 				nlen = n - plen - 1;
2415fff9558SSimon J. Gerraty 			}
2425fff9558SSimon J. Gerraty 		}
2435fff9558SSimon J. Gerraty 		if (cp == pbuf) {
2445fff9558SSimon J. Gerraty 			prefix = "/";
2455fff9558SSimon J. Gerraty 			plen = 1;
2465fff9558SSimon J. Gerraty 			if (*cp == '/') {
2475fff9558SSimon J. Gerraty 				nlen = n - 1;
2485fff9558SSimon J. Gerraty 				cp++;
2495fff9558SSimon J. Gerraty 			} else
2505fff9558SSimon J. Gerraty 				nlen = n;
2515fff9558SSimon J. Gerraty 			ep = NULL;
2525fff9558SSimon J. Gerraty 		}
2535fff9558SSimon J. Gerraty 
2545fff9558SSimon J. Gerraty 		DEBUG_PRINTF(2, ("looking for %s %zu %s\n", prefix, plen, cp));
2555fff9558SSimon J. Gerraty 
2565fff9558SSimon J. Gerraty 		LIST_FOREACH(fip, &fi_list, entries) {
2575fff9558SSimon J. Gerraty 			DEBUG_PRINTF(4, ("at %zu %s\n",
2585fff9558SSimon J. Gerraty 				fip->fi_prefix_len, fip->fi_prefix));
2595fff9558SSimon J. Gerraty 
2605fff9558SSimon J. Gerraty 			if (fip->fi_prefix_len < plen) {
2615fff9558SSimon J. Gerraty 				DEBUG_PRINTF(3, ("skipping prefix=%s %zu %zu\n",
2625fff9558SSimon J. Gerraty 					fip->fi_prefix, fip->fi_prefix_len,
2635fff9558SSimon J. Gerraty 					plen));
2645fff9558SSimon J. Gerraty 				break;
2655fff9558SSimon J. Gerraty 			}
2665fff9558SSimon J. Gerraty 			if (fip->fi_prefix_len == plen) {
2675fff9558SSimon J. Gerraty 				if (fip->fi_dev != 0 && fip->fi_dev != dev) {
2685fff9558SSimon J. Gerraty 					DEBUG_PRINTF(3, (
2695fff9558SSimon J. Gerraty 						"skipping dev=%ld != %ld\n",
2705fff9558SSimon J. Gerraty 						(long)fip->fi_dev,
2715fff9558SSimon J. Gerraty 						(long)dev));
2725fff9558SSimon J. Gerraty 					continue;
2735fff9558SSimon J. Gerraty 				}
2745fff9558SSimon J. Gerraty 				if (strcmp(prefix, fip->fi_prefix)) {
2755fff9558SSimon J. Gerraty 					DEBUG_PRINTF(3, (
2765fff9558SSimon J. Gerraty 						"skipping prefix=%s\n",
2775fff9558SSimon J. Gerraty 						fip->fi_prefix));
2785fff9558SSimon J. Gerraty 					continue;
2795fff9558SSimon J. Gerraty 				}
2805fff9558SSimon J. Gerraty 				DEBUG_PRINTF(3, ("checking prefix=%s\n",
2815fff9558SSimon J. Gerraty 					fip->fi_prefix));
2825fff9558SSimon J. Gerraty 				if (fip->fi_skip_len) {
2835fff9558SSimon J. Gerraty 					np = nbuf;
2845fff9558SSimon J. Gerraty 					nplen = snprintf(nbuf, sizeof(nbuf),
2855fff9558SSimon J. Gerraty 					    "%s/%s",
2865fff9558SSimon J. Gerraty 					    fip->fi_skip, cp);
2875fff9558SSimon J. Gerraty 					nplen = MIN(nplen, sizeof(nbuf) - 1);
2885fff9558SSimon J. Gerraty 				} else {
2895fff9558SSimon J. Gerraty 					np = cp;
2905fff9558SSimon J. Gerraty 					nplen = nlen;
2915fff9558SSimon J. Gerraty 				}
2925fff9558SSimon J. Gerraty 				DEBUG_PRINTF(3, ("lookup: '%s'\n", np));
2935fff9558SSimon J. Gerraty 				if (!(fp = strstr(fip->fi_data, np)))
2945fff9558SSimon J. Gerraty 					continue;
2955fff9558SSimon J. Gerraty #ifdef MANIFEST_SKIP_MAYBE
2965fff9558SSimon J. Gerraty 				if (fip->fi_skip_len == 0 &&
2975fff9558SSimon J. Gerraty 				    fp > fip->fi_data && fp[-1] == '/') {
2985fff9558SSimon J. Gerraty 					fp = maybe_skip(fp, fip, &nplen);
2995fff9558SSimon J. Gerraty 				}
3005fff9558SSimon J. Gerraty #endif
3015fff9558SSimon J. Gerraty 				/*
3025fff9558SSimon J. Gerraty 				 * when we find a match:
3035fff9558SSimon J. Gerraty 				 * fp[nplen] will be space and
3045fff9558SSimon J. Gerraty 				 * fp will be fip->fi_data or
3055fff9558SSimon J. Gerraty 				 * fp[-1] will be \n
3065fff9558SSimon J. Gerraty 				 */
3075fff9558SSimon J. Gerraty 				if (!((fp == fip->fi_data || fp[-1] == '\n') &&
3085fff9558SSimon J. Gerraty 					fp[nplen] == ' ')) {
3095fff9558SSimon J. Gerraty 					do {
3105fff9558SSimon J. Gerraty 						fp++;
3115fff9558SSimon J. Gerraty 						fp = strstr(fp, np);
3125fff9558SSimon J. Gerraty 						if (fp) {
3135fff9558SSimon J. Gerraty #ifdef MANIFEST_SKIP_MAYBE
3145fff9558SSimon J. Gerraty 							if (fip->fi_skip_len == 0 &&
3155fff9558SSimon J. Gerraty 							    fp > fip->fi_data &&
3165fff9558SSimon J. Gerraty 							    fp[-1] == '/') {
3175fff9558SSimon J. Gerraty 								fp = maybe_skip(fp, fip, &nplen);
3185fff9558SSimon J. Gerraty 							}
3195fff9558SSimon J. Gerraty #endif
3205fff9558SSimon J. Gerraty 							DEBUG_PRINTF(3,
3215fff9558SSimon J. Gerraty 							    ("fp[-1]=%#x fp[%zu]=%#x fp=%.78s\n",
3225fff9558SSimon J. Gerraty 								fp[-1], nplen,
3235fff9558SSimon J. Gerraty 								fp[nplen],
3245fff9558SSimon J. Gerraty 								fp));
3255fff9558SSimon J. Gerraty 						}
3265fff9558SSimon J. Gerraty 					} while (fp != NULL &&
3275fff9558SSimon J. Gerraty 					    !(fp[-1] == '\n' &&
3285fff9558SSimon J. Gerraty 						fp[nplen] == ' '));
3295fff9558SSimon J. Gerraty 					if (!fp)
3305fff9558SSimon J. Gerraty 						continue;
3315fff9558SSimon J. Gerraty 				}
3325fff9558SSimon J. Gerraty 				DEBUG_PRINTF(2, ("found %.78s\n", fp));
3335fff9558SSimon J. Gerraty 				/* we have a match! */
3345fff9558SSimon J. Gerraty 				for (cp = &fp[nplen]; *cp == ' '; cp++)
3355fff9558SSimon J. Gerraty 					; /* nothing */
3365fff9558SSimon J. Gerraty 				return (cp);
3375fff9558SSimon J. Gerraty 			} else {
3385fff9558SSimon J. Gerraty 				DEBUG_PRINTF(3,
3395fff9558SSimon J. Gerraty 				    ("Ignoring prefix=%s\n", fip->fi_prefix));
3405fff9558SSimon J. Gerraty 			}
3415fff9558SSimon J. Gerraty 		}
3425fff9558SSimon J. Gerraty 	} while (cp > &pbuf[1]);
3435fff9558SSimon J. Gerraty 
3445fff9558SSimon J. Gerraty 	return (NULL);
3455fff9558SSimon J. Gerraty }
3465fff9558SSimon J. Gerraty 
3475fff9558SSimon J. Gerraty static int
verify_fingerprint(int fd,const char * path,const char * cp,off_t off)3485fff9558SSimon J. Gerraty verify_fingerprint(int fd, const char *path, const char *cp, off_t off)
3495fff9558SSimon J. Gerraty {
3505fff9558SSimon J. Gerraty 	unsigned char buf[PAGE_SIZE];
3515fff9558SSimon J. Gerraty 	const br_hash_class *md;
3525fff9558SSimon J. Gerraty 	br_hash_compat_context mctx;
3535fff9558SSimon J. Gerraty 	size_t hlen;
3545fff9558SSimon J. Gerraty 	int n;
3555fff9558SSimon J. Gerraty 
35664ca9a7fSSimon J. Gerraty 	if (strncmp(cp, "no_hash", 7) == 0) {
35764ca9a7fSSimon J. Gerraty 		return (VE_FINGERPRINT_IGNORE);
35864ca9a7fSSimon J. Gerraty 	} else if (strncmp(cp, "sha256=", 7) == 0) {
3595fff9558SSimon J. Gerraty 		md = &br_sha256_vtable;
3605fff9558SSimon J. Gerraty 		hlen = br_sha256_SIZE;
3615fff9558SSimon J. Gerraty 		cp += 7;
3625fff9558SSimon J. Gerraty #ifdef VE_SHA1_SUPPORT
3635fff9558SSimon J. Gerraty 	} else if (strncmp(cp, "sha1=", 5) == 0) {
3645fff9558SSimon J. Gerraty 		md = &br_sha1_vtable;
3655fff9558SSimon J. Gerraty 		hlen = br_sha1_SIZE;
3665fff9558SSimon J. Gerraty 		cp += 5;
3675fff9558SSimon J. Gerraty #endif
3685fff9558SSimon J. Gerraty #ifdef VE_SHA384_SUPPORT
3695fff9558SSimon J. Gerraty 	} else if (strncmp(cp, "sha384=", 7) == 0) {
3705fff9558SSimon J. Gerraty 		md = &br_sha384_vtable;
3715fff9558SSimon J. Gerraty 		hlen = br_sha384_SIZE;
3725fff9558SSimon J. Gerraty 		cp += 7;
3735fff9558SSimon J. Gerraty #endif
3745fff9558SSimon J. Gerraty #ifdef VE_SHA512_SUPPORT
3755fff9558SSimon J. Gerraty 	} else if (strncmp(cp, "sha512=", 7) == 0) {
3765fff9558SSimon J. Gerraty 		md = &br_sha512_vtable;
3775fff9558SSimon J. Gerraty 		hlen = br_sha512_SIZE;
3785fff9558SSimon J. Gerraty 		cp += 7;
3795fff9558SSimon J. Gerraty #endif
3805fff9558SSimon J. Gerraty 	} else {
3815fff9558SSimon J. Gerraty 		ve_error_set("%s: no supported fingerprint", path);
3825fff9558SSimon J. Gerraty 		return (VE_FINGERPRINT_UNKNOWN);
3835fff9558SSimon J. Gerraty 	}
3845fff9558SSimon J. Gerraty 
3855fff9558SSimon J. Gerraty 	md->init(&mctx.vtable);
3865fff9558SSimon J. Gerraty 	if (off)
3875fff9558SSimon J. Gerraty 		lseek(fd, 0, SEEK_SET);
3885fff9558SSimon J. Gerraty 	do {
3895fff9558SSimon J. Gerraty 		n = read(fd, buf, sizeof(buf));
3905fff9558SSimon J. Gerraty 		if (n < 0)
3915fff9558SSimon J. Gerraty 			return (n);
3925fff9558SSimon J. Gerraty 		if (n > 0)
3935fff9558SSimon J. Gerraty 			md->update(&mctx.vtable, buf, n);
3945fff9558SSimon J. Gerraty 	} while (n > 0);
3955fff9558SSimon J. Gerraty 	lseek(fd, off, SEEK_SET);
3965fff9558SSimon J. Gerraty 	return (ve_check_hash(&mctx, md, path, cp, hlen));
3975fff9558SSimon J. Gerraty }
3985fff9558SSimon J. Gerraty 
3995fff9558SSimon J. Gerraty 
4005fff9558SSimon J. Gerraty /**
4015fff9558SSimon J. Gerraty  * @brief
4025fff9558SSimon J. Gerraty  * verify an open file
4035fff9558SSimon J. Gerraty  *
4045fff9558SSimon J. Gerraty  * @param[in] fd
4055fff9558SSimon J. Gerraty  *	open descriptor
4065fff9558SSimon J. Gerraty  *
4075fff9558SSimon J. Gerraty  * @param[in] path
4085fff9558SSimon J. Gerraty  *	pathname to open
4095fff9558SSimon J. Gerraty  *
4105fff9558SSimon J. Gerraty  * @param[in] off
4115fff9558SSimon J. Gerraty  *	current offset
4125fff9558SSimon J. Gerraty  *
4135fff9558SSimon J. Gerraty  * @return 0, VE_FINGERPRINT_OK or VE_FINGERPRINT_NONE, VE_FINGERPRINT_WRONG
4145fff9558SSimon J. Gerraty  */
4155fff9558SSimon J. Gerraty int
verify_fd(int fd,const char * path,off_t off,struct stat * stp)4165fff9558SSimon J. Gerraty verify_fd(int fd, const char *path, off_t off, struct stat *stp)
4175fff9558SSimon J. Gerraty {
4185fff9558SSimon J. Gerraty 	struct stat st;
4195fff9558SSimon J. Gerraty 	char *cp;
4205fff9558SSimon J. Gerraty 	int rc;
4215fff9558SSimon J. Gerraty 
4225fff9558SSimon J. Gerraty 	if (!stp) {
4235fff9558SSimon J. Gerraty 		if (fstat(fd, &st) == 0)
4245fff9558SSimon J. Gerraty 			stp = &st;
4255fff9558SSimon J. Gerraty 	}
4265fff9558SSimon J. Gerraty 	if (stp && !S_ISREG(stp->st_mode))
4275fff9558SSimon J. Gerraty 		return (0);		/* not relevant */
4285fff9558SSimon J. Gerraty 	cp = fingerprint_info_lookup(fd, path);
4295fff9558SSimon J. Gerraty 	if (!cp) {
4305fff9558SSimon J. Gerraty 		ve_error_set("%s: no entry", path);
4315fff9558SSimon J. Gerraty 		return (VE_FINGERPRINT_NONE);
4325fff9558SSimon J. Gerraty 	}
4335fff9558SSimon J. Gerraty 	rc = verify_fingerprint(fd, path, cp, off);
4345fff9558SSimon J. Gerraty 	switch (rc) {
4355fff9558SSimon J. Gerraty 	case VE_FINGERPRINT_OK:
43664ca9a7fSSimon J. Gerraty 	case VE_FINGERPRINT_IGNORE:
4375fff9558SSimon J. Gerraty 	case VE_FINGERPRINT_UNKNOWN:
4385fff9558SSimon J. Gerraty 		return (rc);
4395fff9558SSimon J. Gerraty 	default:
4405fff9558SSimon J. Gerraty 		return (VE_FINGERPRINT_WRONG);
4415fff9558SSimon J. Gerraty 	}
4425fff9558SSimon J. Gerraty }
4435fff9558SSimon J. Gerraty 
4445fff9558SSimon J. Gerraty /**
4455fff9558SSimon J. Gerraty  * @brief
4465fff9558SSimon J. Gerraty  * open a file if it can be verified
4475fff9558SSimon J. Gerraty  *
4485fff9558SSimon J. Gerraty  * @param[in] path
4495fff9558SSimon J. Gerraty  *	pathname to open
4505fff9558SSimon J. Gerraty  *
4515fff9558SSimon J. Gerraty  * @param[in] flags
4525fff9558SSimon J. Gerraty  *	flags for open
4535fff9558SSimon J. Gerraty  *
4545fff9558SSimon J. Gerraty  * @return fd or VE_FINGERPRINT_NONE, VE_FINGERPRINT_WRONG
4555fff9558SSimon J. Gerraty  */
4565fff9558SSimon J. Gerraty int
verify_open(const char * path,int flags)4575fff9558SSimon J. Gerraty verify_open(const char *path, int flags)
4585fff9558SSimon J. Gerraty {
4595fff9558SSimon J. Gerraty 	int fd;
4605fff9558SSimon J. Gerraty 	int rc;
4615fff9558SSimon J. Gerraty 
4625fff9558SSimon J. Gerraty 	if ((fd = open(path, flags)) >= 0) {
4635fff9558SSimon J. Gerraty 		if ((rc = verify_fd(fd, path, 0, NULL)) < 0) {
4645fff9558SSimon J. Gerraty 			close(fd);
4655fff9558SSimon J. Gerraty 			fd = rc;
4665fff9558SSimon J. Gerraty 		}
4675fff9558SSimon J. Gerraty 	}
4685fff9558SSimon J. Gerraty 	return (fd);
4695fff9558SSimon J. Gerraty }
470