2016-01-21 23:40:00 +01:00

208 lines
5.2 KiB
C

/*-
* Copyright (c) 2013 Alistair Crooks <agc@NetBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "multigest.h"
#define MB(x) ((x) * 1024 * 1024)
/* read input into memory, and then multigest that */
static int
do_input(const char *alg, uint8_t *raw, const char *pat, const char *repl)
{
ssize_t rc;
size_t cc;
char *data;
if ((data = calloc(1, MB(4))) != NULL) {
for (cc = 0 ; cc < MB(4) ; cc += (size_t)rc) {
if ((rc = read(fileno(stdin), &data[cc], MB(4) - cc)) <= 0) {
break;
}
}
multigest_data(alg, data, cc, raw, pat, repl);
free(data);
return 1;
}
return 0;
}
/* get the substitution pattern from the arg */
static int
getsubst(const char *arg, char *from, size_t fromsize, char *to, size_t tosize)
{
const char *sep;
const char *sub;
size_t len;
for (sep = arg + 1 ; *sep && *sep != *arg ; sep++) {
if (*sep == '\\') {
sep += 1;
}
}
len = (size_t)(sep - arg) - 1;
len = MIN(fromsize - 1, len);
multigest_unpcstring(arg + 1, len, from, fromsize);
for (sub = ++sep ; *sep && *sep != *arg ; sep++) {
if (*sep == '\\') {
sep += 1;
}
}
len = (size_t)(sep - sub);
len = MIN(tosize - 1, len);
multigest_unpcstring(sub, len, to, tosize);
return 1;
}
/* verify contents of an existing dynamic digest file */
static int
read_check(const char *check)
{
struct stat st;
regmatch_t match[10];
regex_t r;
uint8_t raw[8192];
FILE *fp;
char *provided;
char calc[8192];
char from[128];
char to[128];
char *file;
char *subs;
char *alg;
char *in;
int ret;
regcomp(&r, "([^ ]+) \\(([^)]+)\\) \\((.*)\\) = ([0-9a-zA-Z]+)", REG_EXTENDED);
if ((fp = fopen(check, "r")) == NULL) {
fprintf(stderr, "can't check existing file '%s'\n", check);
return 0;
}
fstat(fileno(fp), &st);
if ((in = calloc(1, (size_t)(st.st_size + 1))) == NULL) {
fclose(fp);
return 0;
}
read(fileno(fp), in, (size_t)(st.st_size));
in[st.st_size] = 0x0;
fclose(fp);
if (regexec(&r, in, 10, match, 0) != 0) {
free(in);
return 0;
}
alg = &in[match[1].rm_so];
file = &in[match[2].rm_so];
subs = &in[match[3].rm_so];
provided = &in[match[4].rm_so];
in[match[1].rm_eo] = in[match[2].rm_eo] = in[match[3].rm_eo] = in[match[4].rm_eo] = 0x0;
getsubst(subs, from, sizeof(from), to, sizeof(to));
multigest_file(alg, file, raw, from, to);
multigest_format_hex(raw, alg, calc, sizeof(calc));
if ((ret = memcmp(calc, provided, (size_t)(match[4].rm_eo - match[4].rm_so))) != 0) {
fprintf(stderr, "multigest: provided digest: '%s', calculated digest: '%s'\n", provided, calc);
}
regfree(&r);
free(in);
return ret == 0;
}
int
main(int argc, char **argv)
{
const char *outname;
const char *format;
const char *check;
const char *alg;
const char *sub;
const char *sep;
uint8_t raw[8192];
char from[128];
char to[128];
int ok;
int i;
alg = "sha1";
format = "multigest";
sep = sub = outname = check = NULL;
from[0] = to[0] = 0x0;
while ((i = getopt(argc, argv, "F:S:a:c:o:rs:")) != -1) {
switch(i) {
case 'F':
format = optarg;
break;
case 'S':
sep = optarg;
break;
case 'a':
alg = optarg;
break;
case 'c':
check = optarg;
break;
case 'o':
outname = optarg;
break;
case 'r':
getsubst(sub = ",\\$(Id|NetBSD)[^\n]*\\$,\044NetBSD\044", from, sizeof(from), to, sizeof(to));
break;
case 's':
getsubst(sub = optarg, from, sizeof(from), to, sizeof(to));
break;
default:
break;
}
}
ok = 1;
if (check) {
if (!read_check(check)) {
ok = 0;
}
} else if (optind == argc) {
if (do_input(alg, raw, from, to)) {
multigest_print_hex(raw, alg, outname, NULL, sub, sep, format);
} else {
ok = 0;
}
} else {
for (i = optind ; i < argc ; i++) {
if (multigest_file(alg, argv[i], raw, from, to) == NULL) {
ok = 0;
} else {
multigest_print_hex(raw, alg, outname, argv[i], sub, sep, format);
}
}
}
exit((ok) ? EXIT_SUCCESS : EXIT_FAILURE);
}