1/* See LICENSE file for copyright and license details. */
2#include <fcntl.h>
3#include <stdint.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <unistd.h>
8
9#include "../crypt.h"
10#include "../text.h"
11#include "../util.h"
12
13static int
14hexdec(int c)
15{
16 if (c >= '0' && c <= '9')
17 return c - '0';
18 else if (c >= 'A' && c <= 'F')
19 return c - 'A' + 10;
20 else if (c >= 'a' && c <= 'f')
21 return c - 'a' + 10;
22 return -1; /* unknown character */
23}
24
25static int
26mdcheckline(const char *s, uint8_t *md, size_t sz)
27{
28 size_t i;
29 int b1, b2;
30
31 for (i = 0; i < sz; i++) {
32 if (!*s || (b1 = hexdec(*s++)) < 0)
33 return -1; /* invalid format */
34 if (!*s || (b2 = hexdec(*s++)) < 0)
35 return -1; /* invalid format */
36 if ((uint8_t)((b1 << 4) | b2) != md[i])
37 return 1; /* value mismatch */
38 }
39 return (i == sz) ? 0 : 1;
40}
41
42static void
43mdchecklist(
44 FILE *listfp,
45 struct crypt_ops *ops,
46 uint8_t *md,
47 size_t sz,
48 int *formatsucks,
49 int *noread,
50 int *nonmatch
51)
52{
53 int fd;
54 size_t bufsiz = 0;
55 int r;
56 char *line = NULL, *file, *p;
57
58 while (getline(&line, &bufsiz, listfp) > 0) {
59 file = strchr(line, ' ');
60 if (file == NULL || (file[1] != ' ' && file[1] != '*')) {
61 (*formatsucks)++;
62 continue;
63 }
64 if ((size_t)(file - line) != sz * 2) {
65 (*formatsucks)++; /* checksum length mismatch */
66 continue;
67 }
68 *file = '\0';
69 file += 2;
70 for (p = file; *p && *p != '\n' && *p != '\r'; p++)
71 ; /* strip newline */
72 *p = '\0';
73 if ((fd = open(file, O_RDONLY)) < 0) {
74 weprintf("open %s:", file);
75 (*noread)++;
76 continue;
77 }
78 if (cryptsum(ops, fd, file, md)) {
79 (*noread)++;
80 continue;
81 }
82 r = mdcheckline(line, md, sz);
83 if (r == 0) {
84 printf("%s: OK\n", file);
85 } else if (r == 1) {
86 printf("%s: FAILED\n", file);
87 (*nonmatch)++;
88 } else {
89 (*formatsucks)++;
90 }
91 close(fd);
92 }
93 free(line);
94}
95
96int
97cryptcheck(int argc, char *argv[], struct crypt_ops *ops, uint8_t *md, size_t sz)
98{
99 FILE *fp;
100 int formatsucks = 0, noread = 0, nonmatch = 0, ret = 0;
101
102 if (argc == 0) {
103 mdchecklist(stdin, ops, md, sz, &formatsucks, &noread, &nonmatch);
104 } else {
105 for (; *argv; argc--, argv++) {
106 if ((*argv)[0] == '-' && !(*argv)[1]) {
107 fp = stdin;
108 } else if (!(fp = fopen(*argv, "r"))) {
109 weprintf("fopen %s:", *argv);
110 ret = 1;
111 continue;
112 }
113 mdchecklist(fp, ops, md, sz, &formatsucks, &noread, &nonmatch);
114 if (fp != stdin)
115 fclose(fp);
116 }
117 }
118
119 if (formatsucks) {
120 weprintf("%d improperly formatted line%s\n", formatsucks, formatsucks > 1 ? "s" : "");
121 ret = 1;
122 }
123 if (noread) {
124 weprintf("%d listed file%s could not be read\n", noread, noread > 1 ? "s" : "");
125 ret = 1;
126 }
127 if (nonmatch) {
128 weprintf("%d computed checksum%s did NOT match\n", nonmatch, nonmatch > 1 ? "s" : "");
129 ret = 1;
130 }
131
132 return ret;
133}
134
135int
136cryptmain(int argc, char *argv[], struct crypt_ops *ops, uint8_t *md, size_t sz)
137{
138 int fd;
139 int ret = 0;
140
141 if (argc == 0) {
142 if (cryptsum(ops, 0, "<stdin>", md))
143 ret = 1;
144 else
145 mdprint(md, "<stdin>", sz);
146 } else {
147 for (; *argv; argc--, argv++) {
148 if ((*argv)[0] == '-' && !(*argv)[1]) {
149 *argv = "<stdin>";
150 fd = 0;
151 } else if ((fd = open(*argv, O_RDONLY)) < 0) {
152 weprintf("open %s:", *argv);
153 ret = 1;
154 continue;
155 }
156 if (cryptsum(ops, fd, *argv, md))
157 ret = 1;
158 else
159 mdprint(md, *argv, sz);
160 if (fd != 0)
161 close(fd);
162 }
163 }
164
165 return ret;
166}
167
168int
169cryptsum(struct crypt_ops *ops, int fd, const char *f, uint8_t *md)
170{
171 uint8_t buf[BUFSIZ];
172 ssize_t n;
173
174 ops->init(ops->s);
175 while ((n = read(fd, buf, sizeof(buf))) > 0)
176 ops->update(ops->s, buf, n);
177 if (n < 0) {
178 weprintf("%s: read error:", f);
179 return 1;
180 }
181 ops->sum(ops->s, md);
182 return 0;
183}
184
185void
186mdprint(const uint8_t *md, const char *f, size_t len)
187{
188 size_t i;
189
190 for (i = 0; i < len; i++)
191 printf("%02x", md[i]);
192 printf(" %s\n", f);
193}