xref: /src/lib/libsecureboot/verify_file.c (revision 35bbdfad28626255c63360d98c45e41f2c692ef0)
1 /*-
2  * Copyright (c) 2017-2020, Juniper Networks, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 /*
26  * Routines to verify files loaded.
27  */
28 
29 #include <sys/param.h>
30 #include <string.h>
31 #include <sys/queue.h>
32 #include <sys/kenv.h>
33 
34 #include "libsecureboot.h"
35 #include <verify_file.h>
36 #include <manifests.h>
37 
38 #ifdef UNIT_TEST
39 # include <err.h>
40 # define panic warn
41 /*
42  * define MANIFEST_SKIP to Skip - in tests/tvo.c so that
43  * tvo can control the value we use in find_manifest()
44  */
45 extern char *Destdir;
46 extern size_t DestdirLen;
47 extern char *Skip;
48 # undef MANIFEST_SKIP
49 # define MANIFEST_SKIP Skip
50 # undef VE_DEBUG_LEVEL
51 #endif
52 
53 /*
54  * We sometimes need to know if input is verified or not.
55  * The extra slot is for tracking most recently opened.
56  */
57 #ifndef SOPEN_MAX
58 #define SOPEN_MAX       64
59 #endif
60 static int ve_status[SOPEN_MAX+1];
61 static int ve_status_state;
62 struct verify_status;
63 static struct verify_status *verified_files = NULL;
64 static int loaded_manifests = 0;	/* have we loaded anything? */
65 
66 enum {
67 	VE_VERBOSE_SILENT,		/* only report errors */
68 	VE_VERBOSE_UNVERIFIED,		/* all unverified files */
69 	VE_VERBOSE_MUST,		/* report VE_MUST */
70 	VE_VERBOSE_ALL,			/* report all */
71 	VE_VERBOSE_DEBUG,		/* extra noise */
72 };
73 
74 #ifndef VE_VERBOSE_DEFAULT
75 # define VE_VERBOSE_DEFAULT VE_VERBOSE_MUST
76 #endif
77 static int Verbose = VE_VERBOSE_DEFAULT;
78 
79 #define VE_STATUS_NONE	1
80 #define VE_STATUS_VALID	2
81 
82 /**
83  * @brief set ve status for fd
84  */
85 void
ve_status_set(int fd,int ves)86 ve_status_set(int fd, int ves)
87 {
88 	if (fd >= 0 && fd < SOPEN_MAX) {
89 		ve_status[fd] = ves;
90 		ve_status_state = VE_STATUS_VALID;
91 	}
92 	ve_status[SOPEN_MAX] = ves;
93 }
94 
95 /**
96  * @brief get ve status of fd
97  *
98  * What we return depends on ve_status_state.
99  *
100  * @return
101  *	@li ve_status[fd] if ve_status_state is valid
102  *	@li ve_status[SOPEN_MAX] if ve_status_state is none
103  *	@li VE_NOT_CHECKED if ve_status_state uninitialized
104  */
105 int
ve_status_get(int fd)106 ve_status_get(int fd)
107 {
108 	if (!ve_status_state) {
109 		return (VE_NOT_CHECKED);
110 	}
111 	if (ve_status_state == VE_STATUS_VALID &&
112 		fd >= 0 && fd < SOPEN_MAX)
113 		return (ve_status[fd]);
114 	return (ve_status[SOPEN_MAX]);	/* most recent */
115 }
116 
117 /**
118  * @brief track verify status
119  *
120  * occasionally loader will make multiple calls
121  * for the same file, we need only check it once.
122  */
123 struct verify_status {
124 	dev_t	vs_dev;
125 	ino_t	vs_ino;
126 	int	vs_status;
127 	struct verify_status *vs_next;
128 };
129 
130 int
is_verified(struct stat * stp)131 is_verified(struct stat *stp)
132 {
133 	struct verify_status *vsp;
134 	int rc = VE_NOT_CHECKED;
135 
136 	if (stp->st_ino > 0) {
137 		for (vsp = verified_files; vsp != NULL; vsp = vsp->vs_next) {
138 			if (stp->st_dev == vsp->vs_dev &&
139 			    stp->st_ino == vsp->vs_ino) {
140 				rc = vsp->vs_status;
141 				break;
142 			}
143 		}
144 	}
145 	DEBUG_PRINTF(4, ("%s: dev=%lld,ino=%llu,status=%d\n",
146 		__func__, (long long)stp->st_dev,
147 		(unsigned long long)stp->st_ino, rc));
148 	return (rc);
149 }
150 
151 /* most recent first, since most likely to see repeated calls. */
152 void
add_verify_status(struct stat * stp,int status)153 add_verify_status(struct stat *stp, int status)
154 {
155 	struct verify_status *vsp;
156 
157 	vsp = malloc(sizeof(struct verify_status));
158 	if (vsp) {
159 		vsp->vs_next = verified_files;
160 		vsp->vs_dev = stp->st_dev;
161 		vsp->vs_ino = stp->st_ino;
162 		vsp->vs_status = status;
163 		verified_files = vsp;
164 	}
165 	DEBUG_PRINTF(4, ("%s: dev=%lld,ino=%llu,status=%d\n",
166 		__func__, (long long)stp->st_dev,
167 		(unsigned long long)stp->st_ino, status));
168 }
169 
170 
171 /**
172  * @brief
173  * load specified manifest if verified
174  */
175 int
load_manifest(const char * name,const char * prefix,const char * skip,struct stat * stp)176 load_manifest(const char *name, const char *prefix,
177     const char *skip, struct stat *stp)
178 {
179 	struct stat st;
180 	size_t n;
181 	int rc;
182 	char *content;
183 
184 	rc = VE_FINGERPRINT_NONE;
185 	n = strlen(name);
186 	if (n > 4) {
187 		if (!stp) {
188 			stp = &st;
189 			if (stat(name, &st) < 0 || !S_ISREG(st.st_mode))
190 				return (rc);
191 		}
192 		rc = is_verified(stp);
193 		if (rc != VE_NOT_CHECKED) {
194 			return (rc);
195 		}
196 		/* loader has no sense of time */
197 		ve_utc_set(stp->st_mtime);
198 		content = (char *)verify_signed(name, VerifyFlags);
199 		if (content) {
200 #ifdef UNIT_TEST
201 			if (DestdirLen > 0 &&
202 			    strncmp(name, Destdir, DestdirLen) == 0) {
203 				name += DestdirLen;
204 				if (prefix &&
205 				    strncmp(prefix, Destdir, DestdirLen) == 0)
206 					prefix += DestdirLen;
207 			}
208 #endif
209 			fingerprint_info_add(name, prefix, skip, content, stp);
210 			add_verify_status(stp, VE_VERIFIED);
211 			loaded_manifests = 1; /* we are verifying! */
212 			DEBUG_PRINTF(3, ("loaded: %s %s %s\n",
213 				name, prefix, skip));
214 			rc = VE_VERIFIED;
215 		} else {
216 			rc = VE_FINGERPRINT_WRONG;
217 			add_verify_status(stp, rc);	/* remember */
218 		}
219 	}
220 	return (rc);
221 }
222 
223 static int
find_manifest(const char * name)224 find_manifest(const char *name)
225 {
226 	struct stat st;
227 	char buf[MAXPATHLEN];
228 	char *prefix;
229 	char *skip;
230 	const char **tp;
231 	int rc;
232 
233 	strncpy(buf, name, MAXPATHLEN - 1);
234 	if (!(prefix = strrchr(buf, '/')))
235 		return (-1);
236 	*prefix = '\0';
237 	prefix = strdup(buf);
238 	rc = VE_FINGERPRINT_NONE;
239 	for (tp = manifest_names; *tp; tp++) {
240 		snprintf(buf, sizeof(buf), "%s/%s", prefix, *tp);
241 		if (*tp[0] == '.') {
242 			/* skip /../ */
243 			if (prefix[0] == '\0' || prefix[1] == '\0')
244 				continue;
245 		}
246 		DEBUG_PRINTF(5, ("looking for %s\n", buf));
247 		if (stat(buf, &st) == 0 && st.st_size > 0) {
248 #ifdef MANIFEST_SKIP_ALWAYS		/* very unlikely */
249 			skip = MANIFEST_SKIP_ALWAYS;
250 #else
251 #ifdef MANIFEST_SKIP			/* rare */
252 			if (*tp[0] == '.') {
253 				skip = MANIFEST_SKIP;
254 			} else
255 #endif
256 				skip = NULL;
257 #endif
258 			rc = load_manifest(buf, skip ? prefix : NULL,
259 			    skip, &st);
260 			break;
261 		}
262 	}
263 	free(prefix);
264 	return (rc);
265 }
266 
267 
268 #ifdef LOADER_VERIEXEC_TESTING
269 # define ACCEPT_NO_FP_DEFAULT	VE_MUST + 1
270 #else
271 # define ACCEPT_NO_FP_DEFAULT	VE_MUST
272 #endif
273 
274 int
severity_guess(const char * filename)275 severity_guess(const char *filename)
276 {
277 	const char *cp;
278 
279 	/*
280 	 * Some files like *.conf and *.hints may be unsigned,
281 	 * a *.tgz is expected to have its own signed manifest.
282 	 * We allow *.conf to get VE_WANT, but files we expect
283 	 * to always be unverified get VE_TRY and we will not
284 	 * report them.
285 	 */
286 	if ((cp = strrchr(filename, '.'))) {
287 		if (strcmp(cp, ".cookie") == 0 ||
288 		    strcmp(cp, ".dof") == 0 ||
289 		    strcmp(cp, ".hints") == 0 ||
290 		    strcmp(cp, ".order") == 0 ||
291 		    strcmp(cp, ".tgz") == 0)
292 			return (VE_TRY);
293 		if (strcmp(cp, ".4th") == 0 ||
294 		    strcmp(cp, ".lua") == 0 ||
295 		    strcmp(cp, ".rc") == 0)
296 			return (VE_MUST);
297 	}
298 	return (VE_WANT);
299 }
300 
301 static int Verifying = -1;		/* 0 if not verifying */
302 
303 static void
verify_tweak(int fd,off_t off,struct stat * stp,char * tweak,int * accept_no_fp)304 verify_tweak(int fd, off_t off, struct stat *stp,
305     char *tweak, int *accept_no_fp)
306 {
307 	if (strcmp(tweak, "off") == 0) {
308 		Verifying = 0;
309 	} else if (strcmp(tweak, "strict") == 0) {
310 		/* anything caller wants verified must be */
311 		*accept_no_fp = VE_WANT;
312 		Verbose = VE_VERBOSE_ALL;
313 		/* treat self test failure as fatal */
314 		if (!ve_self_tests()) {
315 			panic("verify self tests failed");
316 		}
317 	} else if (strcmp(tweak, "modules") == 0) {
318 		/* modules/kernel must be verified */
319 		*accept_no_fp = VE_MUST;
320 	} else if (strcmp(tweak, "try") == 0) {
321 		/* best effort: always accept no fp */
322 		*accept_no_fp = VE_MUST + 1;
323 	} else if (strcmp(tweak, "verbose") == 0) {
324 		Verbose = VE_VERBOSE_ALL;
325 	} else if (strcmp(tweak, "quiet") == 0) {
326 		Verbose = VE_VERBOSE_UNVERIFIED;
327 		VerifyFlags = 0;
328 	} else if (strcmp(tweak, "silent") == 0) {
329 		Verbose = VE_VERBOSE_SILENT;
330 		VerifyFlags = 0;
331 	} else if (strncmp(tweak, "trust", 5) == 0) {
332 		/* content is trust anchor to add or revoke */
333 		unsigned char *ucp;
334 		size_t num;
335 
336 		if (off > 0)
337 			lseek(fd, 0, SEEK_SET);
338 		ucp = read_fd(fd, stp->st_size);
339 		if (ucp == NULL)
340 			return;
341 		if (strstr(tweak, "revoke")) {
342 			num = ve_trust_anchors_revoke(ucp, stp->st_size);
343 			DEBUG_PRINTF(3, ("revoked %d trust anchors\n",
344 				(int) num));
345 		} else {
346 			num = ve_trust_anchors_add_buf(ucp, stp->st_size);
347 			DEBUG_PRINTF(3, ("added %d trust anchors\n",
348 				(int) num));
349 		}
350 	}
351 }
352 
353 #ifndef VE_DEBUG_LEVEL
354 # define VE_DEBUG_LEVEL 0
355 #endif
356 
357 static int
getenv_int(const char * var,int def)358 getenv_int(const char *var, int def)
359 {
360 	const char *cp;
361 	char *ep;
362 	long val;
363 
364 	val = def;
365 	cp = getenv(var);
366 	if (cp && *cp) {
367 		val = strtol(cp, &ep, 0);
368 		if ((ep && *ep) || val != (int)val) {
369 			val = def;
370 		}
371 	}
372 	return (int)val;
373 }
374 
375 
376 /**
377  * @brief report verification status
378  *
379  * @param[in] path
380  *	path we attempted to verify
381  *
382  * @param[in] severity
383  * 	indicator of how to handle case of missing fingerprint
384  *
385  * @param[in] status
386  *	result of verification
387  *	0 not a file to be verified, > 0 success, < 0 error
388  *
389  * @param[in] stp
390  *	pointer to struct stat, used in extra info to be output
391  *
392  * The output is dictated by combinations of the above and the setting
393  * of Verbose:
394  *
395  * VE_VERBOSE_SILENT
396  * 	report only failure to verify if severity is VE_WANT or higher.
397  *
398  * VE_VERBOSE_UNVERIFIED
399  * 	report any unverified file.
400  *
401  * VE_VERBOSE_MUST
402  * 	report verified only if severity is VE_MUST or higher.
403  *
404  * VE_VERBOSE_ALL
405  * 	report all verified files.
406  *
407  * VE_VERBOSE_DEBUG
408  * 	if stp is not NULL report dev,inode for path
409  */
410 void
verify_report(const char * path,int severity,int status,struct stat * stp)411 verify_report(const char *path, int severity, int status, struct stat *stp)
412 {
413 	if (status < 0 || status == VE_FINGERPRINT_IGNORE) {
414 		if (Verbose < VE_VERBOSE_ALL && severity < VE_WANT)
415 			return;
416 		if (Verbose >= VE_VERBOSE_UNVERIFIED || severity > VE_TRY ||
417 		    status <= VE_FINGERPRINT_WRONG) {
418 			if (Verbose == VE_VERBOSE_DEBUG && stp != NULL)
419 				printf("Unverified %s %llu,%llu\n",
420 				    ve_error_get(),
421 				    (long long)stp->st_dev,
422 				    (long long)stp->st_ino);
423 			else
424 				printf("Unverified %s\n", ve_error_get());
425 		}
426 	} else if (status > 0 && Verbose >= VE_VERBOSE_MUST) {
427 		if (severity >= VE_MUST || Verbose >= VE_VERBOSE_ALL) {
428 			if (Verbose == VE_VERBOSE_DEBUG && stp != NULL)
429 				printf("Unverified %s %llu,%llu\n",
430 				    path,
431 				    (long long)stp->st_dev,
432 				    (long long)stp->st_ino);
433 			else
434 				printf("Verified %s\n", path);
435 		}
436 	}
437 }
438 
439 
440 /**
441  * @brief prepare to verify an open file
442  *
443  * @param[in] fd
444  * 	open descriptor
445  *
446  * @param[in] filename
447  * 	path we opened and will use to lookup fingerprint
448  *
449  * @param[in] stp
450  *	stat pointer so we can check file type
451  */
452 int
verify_prep(int fd,const char * filename,off_t off,struct stat * stp,const char * caller)453 verify_prep(int fd, const char *filename, off_t off, struct stat *stp,
454     const char *caller)
455 {
456 	int rc;
457 
458 	if (Verifying < 0) {
459 		Verifying = ve_trust_init();
460 		/* initialize ve_status with default result */
461 		rc = Verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING;
462 		ve_status_set(0, rc);
463 		ve_status_state = VE_STATUS_NONE;
464 		if (Verifying) {
465 			ve_self_tests();
466 			ve_anchor_verbose_set(1);
467 		}
468 	}
469 	if (!Verifying || fd < 0)
470 		return (0);
471 	if (stp) {
472 		if (fstat(fd, stp) < 0 || !S_ISREG(stp->st_mode))
473 			return (0);
474 	}
475 	DEBUG_PRINTF(2,
476 	    ("verify_prep: caller=%s,fd=%d,name='%s',off=%lld,dev=%lld,ino=%llu\n",
477 		caller, fd, filename, (long long)off, (long long)stp->st_dev,
478 		(unsigned long long)stp->st_ino));
479 	rc = is_verified(stp);
480 	if (rc == VE_NOT_CHECKED) {
481 		rc = find_manifest(filename);
482 		if (rc == VE_VERIFIED)
483 			rc = VE_NOT_CHECKED;
484 	} else {
485 		ve_status_set(fd, rc);
486 	}
487 	return (rc);
488 }
489 
490 /**
491  * @brief verify an open file
492  *
493  * @param[in] fd
494  * 	open descriptor
495  *
496  * @param[in] filename
497  * 	path we opened and will use to lookup fingerprint
498  *
499  * @param[in] off
500  * 	current offset in fd, must be restored on return
501  *
502  * @param[in] severity
503  * 	indicator of how to handle case of missing fingerprint
504  *
505  * We look for a signed manifest relative to the filename
506  * just opened and verify/load it if needed.
507  *
508  * We then use verify_fd() in libve to actually verify that hash for
509  * open file.  If it returns < 0 we look at the severity arg to decide
510  * what to do about it.
511  *
512  * If verify_fd() returns VE_FINGERPRINT_NONE we accept it if severity
513  * is < accept_no_fp.
514  *
515  * @return >= 0 on success < 0 on failure
516  */
517 int
verify_file(int fd,const char * filename,off_t off,int severity,const char * caller)518 verify_file(int fd, const char *filename, off_t off, int severity,
519     const char *caller)
520 {
521 	static int check_verbose = 1;
522 	static int accept_no_fp = ACCEPT_NO_FP_DEFAULT;
523 	struct stat st;
524 	char *cp;
525 	int rc;
526 
527 	if (check_verbose) {
528 		check_verbose = 0;
529 		Verbose = getenv_int("VE_VERBOSE", VE_VERBOSE_DEFAULT);
530 		VerifyFlags = getenv_int("VE_VERIFY_FLAGS",
531 		    Verbose ? VEF_VERBOSE : 0);
532 #ifndef UNIT_TEST
533 		ve_debug_set(getenv_int("VE_DEBUG_LEVEL", VE_DEBUG_LEVEL));
534 #endif
535 	}
536 
537 	rc = verify_prep(fd, filename, off, &st, caller);
538 
539 	if (!rc)
540 		return (0);
541 
542 	if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) {
543 		if (rc != VE_NOT_CHECKED && rc != VE_FINGERPRINT_NONE)
544 			return (rc);
545 
546 		if (severity <= VE_GUESS)
547 			severity = severity_guess(filename);
548 #ifdef VE_PCR_SUPPORT
549 		/*
550 		 * Only update pcr with things that must verify
551 		 * these tend to be processed in a more deterministic
552 		 * order, which makes our pseudo pcr more useful.
553 		 */
554 		ve_pcr_updating_set((severity == VE_MUST));
555 #endif
556 #ifdef UNIT_TEST
557 		if (DestdirLen > 0 &&
558 		    strncmp(filename, Destdir, DestdirLen) == 0) {
559 			filename += DestdirLen;
560 		}
561 #endif
562 		rc = verify_fd(fd, filename, off, &st);
563 		verify_report(filename, severity, rc, &st);
564 		if (rc >= 0) {
565 			if (severity < VE_MUST) { /* not a kernel or module */
566 				if ((cp = strrchr(filename, '/'))) {
567 					cp++;
568 					if (strncmp(cp, "loader.ve.", 10) == 0) {
569 						cp += 10;
570 						verify_tweak(fd, off, &st, cp,
571 						    &accept_no_fp);
572 					}
573 				}
574 			}
575 			add_verify_status(&st, rc);
576 			ve_status_set(fd, rc);
577 			return (rc);
578 		}
579 		if (rc == VE_FINGERPRINT_UNKNOWN && severity < VE_MUST)
580 			rc = VE_UNVERIFIED_OK;
581 		else if (rc == VE_FINGERPRINT_NONE && severity < accept_no_fp)
582 			rc = VE_UNVERIFIED_OK;
583 
584 		add_verify_status(&st, rc);
585 
586 		/* recheck debug/verbose level next time we are called */
587 		if (rc == VE_UNVERIFIED_OK) {
588 			check_verbose = 1;
589 		}
590 	}
591 #ifdef LOADER_VERIEXEC_TESTING
592 	else if (rc != VE_FINGERPRINT_WRONG) {
593 		/*
594 		 * We have not loaded any manifest and
595 		 * not because of verication failure.
596 		 * Most likely reason is we have none.
597 		 * Allow boot to proceed if we are just testing.
598 		 */
599 		return (VE_UNVERIFIED_OK);
600 	}
601 #endif
602 	if (rc == VE_FINGERPRINT_WRONG && severity > accept_no_fp)
603 		panic("cannot continue");
604 	ve_status_set(fd, rc);
605 	return (rc);
606 }
607 
608 /**
609  * @brief get hex string for pcr value and export
610  *
611  * In case we are doing measured boot, provide
612  * value of the "pcr" data we have accumulated.
613  */
614 void
verify_pcr_export(void)615 verify_pcr_export(void)
616 {
617 #ifdef VE_PCR_SUPPORT
618 	char hexbuf[br_sha256_SIZE * 2 + 2];
619 	unsigned char hbuf[br_sha256_SIZE];
620 	char *hinfo;
621 	char *hex;
622 	ssize_t hlen;
623 
624 	hlen = ve_pcr_get(hbuf, sizeof(hbuf));
625 	if (hlen > 0) {
626 		hex = hexdigest(hexbuf, sizeof(hexbuf), hbuf, hlen);
627 		if (hex) {
628 			hex[hlen*2] = '\0'; /* clobber newline */
629 			setenv("loader.ve.pcr", hex, 1);
630 			DEBUG_PRINTF(1,
631 			    ("%s: setenv(loader.ve.pcr, %s\n", __func__,
632 				hex));
633 			hinfo = ve_pcr_hashed_get(1);
634 			if (hinfo) {
635 				setenv("loader.ve.hashed", hinfo, 1);
636 				DEBUG_PRINTF(1,
637 				    ("%s: setenv(loader.ve.hashed, %s\n",
638 					__func__, hinfo));
639 				if ((hlen = strlen(hinfo)) > KENV_MVALLEN) {
640 					/*
641 					 * bump kenv_mvallen
642 					 * roundup to multiple of KENV_MVALLEN
643 					 */
644 					char mvallen[16];
645 
646 					hlen += KENV_MVALLEN -
647 					    (hlen % KENV_MVALLEN);
648 					if (snprintf(mvallen, sizeof(mvallen),
649 						"%d", (int) hlen) < (int)sizeof(mvallen))
650 						setenv("kenv_mvallen", mvallen, 1);
651 				}
652 				free(hinfo);
653 			}
654 		}
655 	}
656 #endif
657 }
658 
659 /*
660  * For tftp and http we need to hash pathname
661  * to be able to fake stat(2) data.
662  */
663 int
hash_string(char * s,size_t n,char * buf,size_t bufsz)664 hash_string(char *s, size_t n, char *buf, size_t bufsz)
665 {
666 	br_hash_compat_context mctx;
667 	const br_hash_class *md;
668 
669 	switch (bufsz) {
670 	case br_sha1_SIZE:
671 		md = &br_sha1_vtable;
672 		break;
673 	case br_sha256_SIZE:
674 		md = &br_sha256_vtable;
675 		break;
676 	default:
677 		if (bufsz < br_sha1_SIZE)
678 			return -1;
679 		md = &br_sha1_vtable;
680 		bufsz = br_sha1_SIZE;
681 		break;
682 	}
683 	if (n == 0)
684 		n = strlen(s);
685 	md->init(&mctx.vtable);
686 	md->update(&mctx.vtable, s, n);
687 	md->out(&mctx.vtable, buf);
688 	return bufsz;
689 }
690 
691 
692