15fff9558SSimon J. Gerraty /*- 25fff9558SSimon J. Gerraty * Copyright (c) 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 __FBSDID("$FreeBSD$"); 275fff9558SSimon J. Gerraty 285fff9558SSimon J. Gerraty #ifndef _STANDALONE 295fff9558SSimon J. Gerraty /* Avoid unwanted userlandish components */ 305fff9558SSimon J. Gerraty #define _KERNEL 315fff9558SSimon J. Gerraty #include <sys/errno.h> 325fff9558SSimon J. Gerraty #undef _KERNEL 335fff9558SSimon J. Gerraty #endif 345fff9558SSimon J. Gerraty 355fff9558SSimon J. Gerraty #include "libsecureboot-priv.h" 36*afc571b1SSimon J. Gerraty #include <verify_file.h> 375fff9558SSimon J. Gerraty 385fff9558SSimon J. Gerraty /** 395fff9558SSimon J. Gerraty * @file vectx.c 405fff9558SSimon J. Gerraty * @brief api to verify file while reading 415fff9558SSimon J. Gerraty * 425fff9558SSimon J. Gerraty * This API allows the hash of a file to be computed as it is read. 435fff9558SSimon J. Gerraty * Key to this is seeking by reading. 445fff9558SSimon J. Gerraty * 455fff9558SSimon J. Gerraty * On close an indication of the verification result is returned. 465fff9558SSimon J. Gerraty */ 475fff9558SSimon J. Gerraty 485fff9558SSimon J. Gerraty struct vectx { 495fff9558SSimon J. Gerraty br_hash_compat_context vec_ctx; /* hash ctx */ 505fff9558SSimon J. Gerraty const br_hash_class *vec_md; /* hash method */ 515fff9558SSimon J. Gerraty const char *vec_path; /* path we are verifying */ 525fff9558SSimon J. Gerraty const char *vec_want; /* hash value we want */ 535fff9558SSimon J. Gerraty off_t vec_off; /* current offset */ 54*afc571b1SSimon J. Gerraty off_t vec_hashed; /* where we have hashed to */ 555fff9558SSimon J. Gerraty size_t vec_size; /* size of path */ 565fff9558SSimon J. Gerraty size_t vec_hashsz; /* size of hash */ 575fff9558SSimon J. Gerraty int vec_fd; /* file descriptor */ 585fff9558SSimon J. Gerraty int vec_status; /* verification status */ 595fff9558SSimon J. Gerraty }; 605fff9558SSimon J. Gerraty 61*afc571b1SSimon J. Gerraty 625fff9558SSimon J. Gerraty /** 635fff9558SSimon J. Gerraty * @brief 645fff9558SSimon J. Gerraty * verify an open file as we read it 655fff9558SSimon J. Gerraty * 665fff9558SSimon J. Gerraty * If the file has no fingerprint to match, we will still return a 675fff9558SSimon J. Gerraty * verification context containing little more than the file 685fff9558SSimon J. Gerraty * descriptor, and an error code in @c error. 695fff9558SSimon J. Gerraty * 705fff9558SSimon J. Gerraty * @param[in] fd 715fff9558SSimon J. Gerraty * open descriptor 725fff9558SSimon J. Gerraty * 735fff9558SSimon J. Gerraty * @param[in] path 745fff9558SSimon J. Gerraty * pathname to open 755fff9558SSimon J. Gerraty * 765fff9558SSimon J. Gerraty * @param[in] off 775fff9558SSimon J. Gerraty * current offset 785fff9558SSimon J. Gerraty * 795fff9558SSimon J. Gerraty * @param[in] stp 805fff9558SSimon J. Gerraty * pointer to struct stat 815fff9558SSimon J. Gerraty * 825fff9558SSimon J. Gerraty * @param[out] error 835fff9558SSimon J. Gerraty * @li 0 all is good 845fff9558SSimon J. Gerraty * @li ENOMEM out of memory 855fff9558SSimon J. Gerraty * @li VE_FINGERPRINT_NONE no entry found 865fff9558SSimon J. Gerraty * @li VE_FINGERPRINT_UNKNOWN no fingerprint in entry 875fff9558SSimon J. Gerraty * 885fff9558SSimon J. Gerraty * @return ctx or NULL on error. 895fff9558SSimon J. Gerraty * NULL is only returned for non-files or out-of-memory. 905fff9558SSimon J. Gerraty */ 915fff9558SSimon J. Gerraty struct vectx * 92*afc571b1SSimon J. Gerraty vectx_open(int fd, const char *path, off_t off, struct stat *stp, 93*afc571b1SSimon J. Gerraty int *error, const char *caller) 945fff9558SSimon J. Gerraty { 955fff9558SSimon J. Gerraty struct vectx *ctx; 965fff9558SSimon J. Gerraty struct stat st; 975fff9558SSimon J. Gerraty size_t hashsz; 985fff9558SSimon J. Gerraty char *cp; 99*afc571b1SSimon J. Gerraty int rc; 1005fff9558SSimon J. Gerraty 101*afc571b1SSimon J. Gerraty if (!stp) 1025fff9558SSimon J. Gerraty stp = &st; 1035fff9558SSimon J. Gerraty 104*afc571b1SSimon J. Gerraty rc = verify_prep(fd, path, off, stp, __func__); 105*afc571b1SSimon J. Gerraty 106*afc571b1SSimon J. Gerraty DEBUG_PRINTF(2, 107*afc571b1SSimon J. Gerraty ("vectx_open: caller=%s,name='%s',prep_rc=%d\n", 108*afc571b1SSimon J. Gerraty caller,path, rc)); 109*afc571b1SSimon J. Gerraty 110*afc571b1SSimon J. Gerraty switch (rc) { 111*afc571b1SSimon J. Gerraty case VE_FINGERPRINT_NONE: 112*afc571b1SSimon J. Gerraty case VE_FINGERPRINT_UNKNOWN: 113*afc571b1SSimon J. Gerraty case VE_FINGERPRINT_WRONG: 114*afc571b1SSimon J. Gerraty *error = rc; 1155fff9558SSimon J. Gerraty return (NULL); 1165fff9558SSimon J. Gerraty } 1175fff9558SSimon J. Gerraty ctx = malloc(sizeof(struct vectx)); 1185fff9558SSimon J. Gerraty if (!ctx) 1195fff9558SSimon J. Gerraty goto enomem; 1205fff9558SSimon J. Gerraty ctx->vec_fd = fd; 1215fff9558SSimon J. Gerraty ctx->vec_path = path; 1225fff9558SSimon J. Gerraty ctx->vec_size = stp->st_size; 1235fff9558SSimon J. Gerraty ctx->vec_off = 0; 124*afc571b1SSimon J. Gerraty ctx->vec_hashed = 0; 1255fff9558SSimon J. Gerraty ctx->vec_want = NULL; 1265fff9558SSimon J. Gerraty ctx->vec_status = 0; 127*afc571b1SSimon J. Gerraty ctx->vec_hashsz = hashsz = 0; 1285fff9558SSimon J. Gerraty 129*afc571b1SSimon J. Gerraty if (rc == 0) { 130*afc571b1SSimon J. Gerraty /* we are not verifying this */ 131*afc571b1SSimon J. Gerraty *error = 0; 132*afc571b1SSimon J. Gerraty return (ctx); 133*afc571b1SSimon J. Gerraty } 1345fff9558SSimon J. Gerraty cp = fingerprint_info_lookup(fd, path); 1355fff9558SSimon J. Gerraty if (!cp) { 1365fff9558SSimon J. Gerraty ctx->vec_status = VE_FINGERPRINT_NONE; 1375fff9558SSimon J. Gerraty ve_error_set("%s: no entry", path); 1385fff9558SSimon J. Gerraty } else { 13964ca9a7fSSimon J. Gerraty if (strncmp(cp, "no_hash", 7) == 0) { 14064ca9a7fSSimon J. Gerraty ctx->vec_status = VE_FINGERPRINT_IGNORE; 14164ca9a7fSSimon J. Gerraty hashsz = 0; 14264ca9a7fSSimon J. Gerraty } else if (strncmp(cp, "sha256=", 7) == 0) { 1435fff9558SSimon J. Gerraty ctx->vec_md = &br_sha256_vtable; 1445fff9558SSimon J. Gerraty hashsz = br_sha256_SIZE; 1455fff9558SSimon J. Gerraty cp += 7; 1465fff9558SSimon J. Gerraty #ifdef VE_SHA1_SUPPORT 1475fff9558SSimon J. Gerraty } else if (strncmp(cp, "sha1=", 5) == 0) { 1485fff9558SSimon J. Gerraty ctx->vec_md = &br_sha1_vtable; 1495fff9558SSimon J. Gerraty hashsz = br_sha1_SIZE; 1505fff9558SSimon J. Gerraty cp += 5; 1515fff9558SSimon J. Gerraty #endif 1525fff9558SSimon J. Gerraty #ifdef VE_SHA384_SUPPORT 1535fff9558SSimon J. Gerraty } else if (strncmp(cp, "sha384=", 7) == 0) { 1545fff9558SSimon J. Gerraty ctx->vec_md = &br_sha384_vtable; 1555fff9558SSimon J. Gerraty hashsz = br_sha384_SIZE; 1565fff9558SSimon J. Gerraty cp += 7; 1575fff9558SSimon J. Gerraty #endif 1585fff9558SSimon J. Gerraty #ifdef VE_SHA512_SUPPORT 1595fff9558SSimon J. Gerraty } else if (strncmp(cp, "sha512=", 7) == 0) { 1605fff9558SSimon J. Gerraty ctx->vec_md = &br_sha512_vtable; 1615fff9558SSimon J. Gerraty hashsz = br_sha512_SIZE; 1625fff9558SSimon J. Gerraty cp += 7; 1635fff9558SSimon J. Gerraty #endif 1645fff9558SSimon J. Gerraty } else { 1655fff9558SSimon J. Gerraty ctx->vec_status = VE_FINGERPRINT_UNKNOWN; 1665fff9558SSimon J. Gerraty ve_error_set("%s: no supported fingerprint", path); 1675fff9558SSimon J. Gerraty } 1685fff9558SSimon J. Gerraty } 1695fff9558SSimon J. Gerraty *error = ctx->vec_status; 1705fff9558SSimon J. Gerraty ctx->vec_hashsz = hashsz; 1715fff9558SSimon J. Gerraty ctx->vec_want = cp; 17264ca9a7fSSimon J. Gerraty if (hashsz > 0) { 1735fff9558SSimon J. Gerraty ctx->vec_md->init(&ctx->vec_ctx.vtable); 1745fff9558SSimon J. Gerraty 17564ca9a7fSSimon J. Gerraty if (off > 0) { 1765fff9558SSimon J. Gerraty lseek(fd, 0, SEEK_SET); 1775fff9558SSimon J. Gerraty vectx_lseek(ctx, off, SEEK_SET); 1785fff9558SSimon J. Gerraty } 17964ca9a7fSSimon J. Gerraty } 180*afc571b1SSimon J. Gerraty DEBUG_PRINTF(2, 181*afc571b1SSimon J. Gerraty ("vectx_open: caller=%s,name='%s',hashsz=%lu,status=%d\n", 182*afc571b1SSimon J. Gerraty caller, path, (unsigned long)ctx->vec_hashsz, 183*afc571b1SSimon J. Gerraty ctx->vec_status)); 1845fff9558SSimon J. Gerraty return (ctx); 1855fff9558SSimon J. Gerraty 1865fff9558SSimon J. Gerraty enomem: /* unlikely */ 1875fff9558SSimon J. Gerraty *error = ENOMEM; 1885fff9558SSimon J. Gerraty free(ctx); 1895fff9558SSimon J. Gerraty return (NULL); 1905fff9558SSimon J. Gerraty } 1915fff9558SSimon J. Gerraty 1925fff9558SSimon J. Gerraty /** 1935fff9558SSimon J. Gerraty * @brief 1945fff9558SSimon J. Gerraty * read bytes from file and update hash 1955fff9558SSimon J. Gerraty * 1965fff9558SSimon J. Gerraty * It is critical that all file I/O comes through here. 1975fff9558SSimon J. Gerraty * We keep track of current offset. 198*afc571b1SSimon J. Gerraty * We also track what offset we have hashed to, 199*afc571b1SSimon J. Gerraty * so we won't replay data if we seek backwards. 2005fff9558SSimon J. Gerraty * 2015fff9558SSimon J. Gerraty * @param[in] pctx 2025fff9558SSimon J. Gerraty * pointer to ctx 2035fff9558SSimon J. Gerraty * 2045fff9558SSimon J. Gerraty * @param[in] buf 2055fff9558SSimon J. Gerraty * 2065fff9558SSimon J. Gerraty * @param[in] nbytes 2075fff9558SSimon J. Gerraty * 2085fff9558SSimon J. Gerraty * @return bytes read or error. 2095fff9558SSimon J. Gerraty */ 2105fff9558SSimon J. Gerraty ssize_t 2115fff9558SSimon J. Gerraty vectx_read(struct vectx *ctx, void *buf, size_t nbytes) 2125fff9558SSimon J. Gerraty { 2135fff9558SSimon J. Gerraty unsigned char *bp = buf; 2145fff9558SSimon J. Gerraty int n; 215*afc571b1SSimon J. Gerraty int delta; 216*afc571b1SSimon J. Gerraty int x; 2175fff9558SSimon J. Gerraty size_t off; 2185fff9558SSimon J. Gerraty 2195fff9558SSimon J. Gerraty if (ctx->vec_hashsz == 0) /* nothing to do */ 2205fff9558SSimon J. Gerraty return (read(ctx->vec_fd, buf, nbytes)); 2215fff9558SSimon J. Gerraty 2225fff9558SSimon J. Gerraty off = 0; 2235fff9558SSimon J. Gerraty do { 2245fff9558SSimon J. Gerraty n = read(ctx->vec_fd, &bp[off], nbytes - off); 2255fff9558SSimon J. Gerraty if (n < 0) 2265fff9558SSimon J. Gerraty return (n); 2275fff9558SSimon J. Gerraty if (n > 0) { 228*afc571b1SSimon J. Gerraty /* we may have seeked backwards! */ 229*afc571b1SSimon J. Gerraty delta = ctx->vec_hashed - ctx->vec_off; 230*afc571b1SSimon J. Gerraty if (delta > 0) { 231*afc571b1SSimon J. Gerraty x = MIN(delta, n); 232*afc571b1SSimon J. Gerraty off += x; 233*afc571b1SSimon J. Gerraty n -= x; 234*afc571b1SSimon J. Gerraty ctx->vec_off += x; 235*afc571b1SSimon J. Gerraty } 236*afc571b1SSimon J. Gerraty if (n > 0) { 2375fff9558SSimon J. Gerraty ctx->vec_md->update(&ctx->vec_ctx.vtable, &bp[off], n); 2385fff9558SSimon J. Gerraty off += n; 2395fff9558SSimon J. Gerraty ctx->vec_off += n; 240*afc571b1SSimon J. Gerraty ctx->vec_hashed += n; 241*afc571b1SSimon J. Gerraty } 2425fff9558SSimon J. Gerraty } 2435fff9558SSimon J. Gerraty } while (n > 0 && off < nbytes); 2445fff9558SSimon J. Gerraty return (off); 2455fff9558SSimon J. Gerraty } 2465fff9558SSimon J. Gerraty 2475fff9558SSimon J. Gerraty /** 2485fff9558SSimon J. Gerraty * @brief 2495fff9558SSimon J. Gerraty * vectx equivalent of lseek 2505fff9558SSimon J. Gerraty * 251*afc571b1SSimon J. Gerraty * When seeking forwards we actually call vectx_read 2525fff9558SSimon J. Gerraty * to reach the desired offset. 2535fff9558SSimon J. Gerraty * 254*afc571b1SSimon J. Gerraty * We support seeking backwards. 2555fff9558SSimon J. Gerraty * 2565fff9558SSimon J. Gerraty * @param[in] pctx 2575fff9558SSimon J. Gerraty * pointer to ctx 2585fff9558SSimon J. Gerraty * 2595fff9558SSimon J. Gerraty * @param[in] off 2605fff9558SSimon J. Gerraty * desired offset 2615fff9558SSimon J. Gerraty * 2625fff9558SSimon J. Gerraty * @param[in] whence 263*afc571b1SSimon J. Gerraty * We try to convert whence to ``SEEK_SET``. 264*afc571b1SSimon J. Gerraty * We do not support ``SEEK_DATA`` or ``SEEK_HOLE``. 2655fff9558SSimon J. Gerraty * 2665fff9558SSimon J. Gerraty * @return offset or error. 2675fff9558SSimon J. Gerraty */ 2685fff9558SSimon J. Gerraty off_t 2695fff9558SSimon J. Gerraty vectx_lseek(struct vectx *ctx, off_t off, int whence) 2705fff9558SSimon J. Gerraty { 2715fff9558SSimon J. Gerraty unsigned char buf[PAGE_SIZE]; 2725fff9558SSimon J. Gerraty size_t delta; 2735fff9558SSimon J. Gerraty ssize_t n; 2745fff9558SSimon J. Gerraty 2755fff9558SSimon J. Gerraty if (ctx->vec_hashsz == 0) /* nothing to do */ 2765fff9558SSimon J. Gerraty return (lseek(ctx->vec_fd, off, whence)); 2775fff9558SSimon J. Gerraty 2785fff9558SSimon J. Gerraty /* 279*afc571b1SSimon J. Gerraty * Convert whence to SEEK_SET 2805fff9558SSimon J. Gerraty */ 2815fff9558SSimon J. Gerraty if (whence == SEEK_END && off <= 0) { 2825fff9558SSimon J. Gerraty whence = SEEK_SET; 2835fff9558SSimon J. Gerraty off += ctx->vec_size; 284*afc571b1SSimon J. Gerraty } else if (whence == SEEK_CUR) { 2855fff9558SSimon J. Gerraty whence = SEEK_SET; 2865fff9558SSimon J. Gerraty off += ctx->vec_off; 2875fff9558SSimon J. Gerraty } 288*afc571b1SSimon J. Gerraty if (whence != SEEK_SET || 2895fff9558SSimon J. Gerraty (size_t)off > ctx->vec_size) { 290*afc571b1SSimon J. Gerraty printf("ERROR: %s: unsupported operation: whence=%d off=%lld -> %lld\n", 291*afc571b1SSimon J. Gerraty __func__, whence, (long long)ctx->vec_off, (long long)off); 2925fff9558SSimon J. Gerraty return (-1); 2935fff9558SSimon J. Gerraty } 294*afc571b1SSimon J. Gerraty if (off < ctx->vec_hashed) { 295*afc571b1SSimon J. Gerraty /* seeking backwards! just do it */ 296*afc571b1SSimon J. Gerraty ctx->vec_off = lseek(ctx->vec_fd, off, whence); 297*afc571b1SSimon J. Gerraty return (ctx->vec_off); 298*afc571b1SSimon J. Gerraty } 2995fff9558SSimon J. Gerraty n = 0; 3005fff9558SSimon J. Gerraty do { 3015fff9558SSimon J. Gerraty delta = off - ctx->vec_off; 3025fff9558SSimon J. Gerraty if (delta > 0) { 3035fff9558SSimon J. Gerraty delta = MIN(PAGE_SIZE, delta); 3045fff9558SSimon J. Gerraty n = vectx_read(ctx, buf, delta); 3055fff9558SSimon J. Gerraty if (n < 0) 3065fff9558SSimon J. Gerraty return (n); 3075fff9558SSimon J. Gerraty } 3085fff9558SSimon J. Gerraty } while (ctx->vec_off < off && n > 0); 3095fff9558SSimon J. Gerraty return (ctx->vec_off); 3105fff9558SSimon J. Gerraty } 3115fff9558SSimon J. Gerraty 3125fff9558SSimon J. Gerraty /** 3135fff9558SSimon J. Gerraty * @brief 3145fff9558SSimon J. Gerraty * check that hashes match and cleanup 3155fff9558SSimon J. Gerraty * 3165fff9558SSimon J. Gerraty * We have finished reading file, compare the hash with what 3175fff9558SSimon J. Gerraty * we wanted. 3185fff9558SSimon J. Gerraty * 3195fff9558SSimon J. Gerraty * @param[in] pctx 3205fff9558SSimon J. Gerraty * pointer to ctx 3215fff9558SSimon J. Gerraty * 3225fff9558SSimon J. Gerraty * @return 0 or an error. 3235fff9558SSimon J. Gerraty */ 3245fff9558SSimon J. Gerraty int 325*afc571b1SSimon J. Gerraty vectx_close(struct vectx *ctx, int severity, const char *caller) 3265fff9558SSimon J. Gerraty { 3275fff9558SSimon J. Gerraty int rc; 3285fff9558SSimon J. Gerraty 3295fff9558SSimon J. Gerraty if (ctx->vec_hashsz == 0) { 3305fff9558SSimon J. Gerraty rc = ctx->vec_status; 3315fff9558SSimon J. Gerraty } else { 332*afc571b1SSimon J. Gerraty #ifdef VE_PCR_SUPPORT 333*afc571b1SSimon J. Gerraty /* 334*afc571b1SSimon J. Gerraty * Only update pcr with things that must verify 335*afc571b1SSimon J. Gerraty * these tend to be processed in a more deterministic 336*afc571b1SSimon J. Gerraty * order, which makes our pseudo pcr more useful. 337*afc571b1SSimon J. Gerraty */ 338*afc571b1SSimon J. Gerraty ve_pcr_updating_set((severity == VE_MUST)); 339*afc571b1SSimon J. Gerraty #endif 3405fff9558SSimon J. Gerraty rc = ve_check_hash(&ctx->vec_ctx, ctx->vec_md, 3415fff9558SSimon J. Gerraty ctx->vec_path, ctx->vec_want, ctx->vec_hashsz); 3425fff9558SSimon J. Gerraty } 343*afc571b1SSimon J. Gerraty DEBUG_PRINTF(2, 344*afc571b1SSimon J. Gerraty ("vectx_close: caller=%s,name='%s',rc=%d,severity=%d\n", 345*afc571b1SSimon J. Gerraty caller,ctx->vec_path, rc, severity)); 346*afc571b1SSimon J. Gerraty if (severity > VE_WANT || rc == VE_FINGERPRINT_WRONG) 347*afc571b1SSimon J. Gerraty printf("%serified %s\n", (rc <= 0) ? "Unv" : "V", 348*afc571b1SSimon J. Gerraty ctx->vec_path); 349*afc571b1SSimon J. Gerraty #if !defined(UNIT_TEST) && !defined(DEBUG_VECTX) 350*afc571b1SSimon J. Gerraty /* we are generally called with VE_MUST */ 351*afc571b1SSimon J. Gerraty if (severity > VE_WANT && rc == VE_FINGERPRINT_WRONG) 352*afc571b1SSimon J. Gerraty panic("cannot continue"); 353*afc571b1SSimon J. Gerraty #endif 3545fff9558SSimon J. Gerraty free(ctx); 3555fff9558SSimon J. Gerraty return ((rc < 0) ? rc : 0); 3565fff9558SSimon J. Gerraty } 357