286df29e7d
This has already been suggested by Evan Gates <evan.gates@gmail.com> and he's totally right about it. So, what's the problem? I wrote a testing program asshole.c with int main(void) { execl("/path/to/sbase/echo", "echo", "test"); return 0; } and checked the results with glibc and musl. Note that the sentinel NULL is missing from the end of the argument list. glibc calculates an argc of 5, musl 4 (instead of 2) and thus mess up things anyway. The powerful arg.h also focuses on argv instead of argc as well, but ignoring argc completely is also the wrong way to go. Instead, a more idiomatic approach is to check *argv only and decrement argc on the go. While at it, I rewrote yes(1) in an argv-centric way as well. All audited tools have been "fixed" and each following audited tool will receive the same treatment.
170 lines
3.3 KiB
C
170 lines
3.3 KiB
C
/* See LICENSE file for copyright and license details. */
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "../crypt.h"
|
|
#include "../text.h"
|
|
#include "../util.h"
|
|
|
|
static int
|
|
hexdec(int c)
|
|
{
|
|
if (c >= '0' && c <= '9')
|
|
return c - '0';
|
|
else if (c >= 'A' && c <= 'F')
|
|
return c - 'A' + 10;
|
|
else if (c >= 'a' && c <= 'f')
|
|
return c - 'a' + 10;
|
|
return -1; /* unknown character */
|
|
}
|
|
|
|
static int
|
|
mdcheckline(const char *s, uint8_t *md, size_t sz)
|
|
{
|
|
size_t i;
|
|
int b1, b2;
|
|
|
|
for (i = 0; i < sz; i++) {
|
|
if (!*s || (b1 = hexdec(*s++)) < 0)
|
|
return -1; /* invalid format */
|
|
if (!*s || (b2 = hexdec(*s++)) < 0)
|
|
return -1; /* invalid format */
|
|
if ((uint8_t)((b1 << 4) | b2) != md[i])
|
|
return 0; /* value mismatch */
|
|
}
|
|
return (i == sz) ? 1 : 0;
|
|
}
|
|
|
|
static void
|
|
mdchecklist(FILE *listfp, struct crypt_ops *ops, uint8_t *md, size_t sz,
|
|
int *formatsucks, int *noread, int *nonmatch) {
|
|
FILE *fp;
|
|
size_t bufsiz = 0;
|
|
int r;
|
|
char *line = NULL, *file, *p;
|
|
|
|
while (getline(&line, &bufsiz, listfp) != -1) {
|
|
if (!(file = strstr(line, " "))) {
|
|
(*formatsucks)++;
|
|
continue;
|
|
}
|
|
if ((file - line) / 2 != sz) {
|
|
(*formatsucks)++; /* checksum length mismatch */
|
|
continue;
|
|
}
|
|
*file = '\0';
|
|
file += 2;
|
|
for (p = file; *p && *p != '\n' && *p != '\r'; p++); /* strip newline */
|
|
*p = '\0';
|
|
if (!(fp = fopen(file, "r"))) {
|
|
weprintf("fopen %s:", file);
|
|
(*noread)++;
|
|
continue;
|
|
}
|
|
cryptsum(ops, fp, file, md);
|
|
r = mdcheckline(line, md, sz);
|
|
if (r == 1) {
|
|
printf("%s: OK\n", file);
|
|
} else if (r == 0) {
|
|
printf("%s: FAILED\n", file);
|
|
(*nonmatch)++;
|
|
} else {
|
|
(*formatsucks)++;
|
|
}
|
|
fclose(fp);
|
|
}
|
|
free(line);
|
|
}
|
|
|
|
int
|
|
cryptcheck(int argc, char *argv[], struct crypt_ops *ops, uint8_t *md, size_t sz)
|
|
{
|
|
FILE *fp;
|
|
int formatsucks = 0, noread = 0, nonmatch = 0, ret = 0;
|
|
|
|
if (argc == 0) {
|
|
mdchecklist(stdin, ops, md, sz, &formatsucks, &noread, &nonmatch);
|
|
} else {
|
|
for (; *argv; argc--, argv++) {
|
|
if (!(fp = fopen(*argv, "r"))) {
|
|
weprintf("fopen %s:", *argv);
|
|
ret = 1;
|
|
continue;
|
|
}
|
|
mdchecklist(fp, ops, md, sz, &formatsucks, &noread, &nonmatch);
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
if (formatsucks) {
|
|
weprintf("%d lines are improperly formatted\n", formatsucks);
|
|
ret = 1;
|
|
}
|
|
if (noread) {
|
|
weprintf("%d listed file could not be read\n", noread);
|
|
ret = 1;
|
|
}
|
|
if (nonmatch) {
|
|
weprintf("%d computed checksums did NOT match\n", nonmatch);
|
|
ret = 1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
cryptmain(int argc, char *argv[], struct crypt_ops *ops, uint8_t *md, size_t sz)
|
|
{
|
|
FILE *fp;
|
|
int ret = 0;
|
|
|
|
if (argc == 0) {
|
|
cryptsum(ops, stdin, "<stdin>", md);
|
|
mdprint(md, "<stdin>", sz);
|
|
} else {
|
|
for (; *argv; argc--, argv++) {
|
|
if (!(fp = fopen(*argv, "r"))) {
|
|
weprintf("fopen %s:", *argv);
|
|
ret = 1;
|
|
continue;
|
|
}
|
|
if (cryptsum(ops, fp, *argv, md) == 1)
|
|
ret = 1;
|
|
else
|
|
mdprint(md, *argv, sz);
|
|
fclose(fp);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
cryptsum(struct crypt_ops *ops, FILE *fp, const char *f,
|
|
uint8_t *md)
|
|
{
|
|
uint8_t buf[BUFSIZ];
|
|
size_t n;
|
|
|
|
ops->init(ops->s);
|
|
while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
|
|
ops->update(ops->s, buf, n);
|
|
if (ferror(fp)) {
|
|
weprintf("%s: read error:", f);
|
|
return 1;
|
|
}
|
|
ops->sum(ops->s, md);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
mdprint(const uint8_t *md, const char *f, size_t len)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < len; i++)
|
|
printf("%02x", md[i]);
|
|
printf(" %s\n", f);
|
|
}
|