1#include <stdlib.h>
2#include <stdio.h>
3#include <string.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <unistd.h>
7#include <fcntl.h>
8#include <inttypes.h>
9#include <netinet/in.h>
10#include <limits.h>
11#include <getopt.h>
12#include <regex.h>
13#include <errno.h>
14#include <openssl/evp.h>
15#include <xar/xar.h>
16
17off_t HeapOff = 0;
18
19static char* xar_format_md5(const unsigned char* m) {
20        char* result = NULL;
21        asprintf(&result,
22                "%02x%02x%02x%02x"
23                "%02x%02x%02x%02x"
24                "%02x%02x%02x%02x"
25                "%02x%02x%02x%02x",
26                m[0], m[1], m[2], m[3],
27                m[4], m[5], m[6], m[7],
28                m[8], m[9], m[10], m[11],
29                m[12], m[13], m[14], m[15]);
30        return result;
31}
32
33void heap_check(int fd, const char *name, const char *prop, off_t offset, off_t length, const char *csum) {
34	char *buf;
35	EVP_MD_CTX ctx;
36	const EVP_MD *md;
37	unsigned char md5str[EVP_MAX_MD_SIZE];
38	unsigned int len;
39	ssize_t r;
40	char *formattedmd5;
41
42	fprintf(stderr, "Heap checking %s %s at offset: %" PRIu64 "\n", name, prop, HeapOff+offset);
43	OpenSSL_add_all_digests();
44	md = EVP_get_digestbyname("md5");
45	if( md == NULL ) {
46		fprintf(stderr, "No md5 digest in openssl\n");
47		exit(1);
48	}
49	EVP_DigestInit(&ctx, md);
50
51	buf = malloc(length);
52	if( !buf ) {
53		fprintf(stderr, "Error allocating buffer\n");
54		exit(1);
55	}
56
57	if( lseek(fd, HeapOff+offset, SEEK_SET) < 0 ) {
58		perror("lseek");
59		fprintf(stderr, "Error seeking in the heap to offet: %" PRIu64 "\n", HeapOff+offset);
60		exit(1);
61	}
62
63	r = read(fd, buf, length);
64	if( r != length ) {
65		fprintf(stderr, "Error reading from the heap\n");
66		exit(1);
67	}
68	EVP_DigestUpdate(&ctx, buf, length);
69	EVP_DigestFinal(&ctx, md5str, &len);
70
71	formattedmd5 = xar_format_md5(md5str);
72	if( strcmp(formattedmd5, csum) != 0 ) {
73		fprintf(stderr, "%s %s checksum does not match\n", name, prop);
74	}
75	free(formattedmd5);
76	free(buf);
77}
78
79void prop_check(int fd, xar_t x, xar_file_t f) {
80	xar_iter_t i;
81	const char *key, *value;
82	const char *name = NULL;
83	char *tmp;
84	off_t offset = 0, length = 0;
85	const char *origcsum = NULL;
86
87	i = xar_iter_new();
88	if( !i ) {
89		fprintf(stderr, "Error creating new prop iter\n");
90		exit(1);
91	}
92
93	xar_prop_get(f, "name", &name);
94
95	for( key = xar_prop_first(f, i); key; key = xar_prop_next(i) ) {
96		asprintf(&tmp, "%s/offset", key);
97		if( xar_prop_get(f, tmp, &value) == 0 ) {
98			offset = strtoll(value, NULL, 10);
99		}
100		free(tmp);
101		asprintf(&tmp, "%s/length", key);
102		if( xar_prop_get(f, tmp, &value) == 0 ) {
103			length = strtoll(value, NULL, 10);
104		}
105		free(tmp);
106		asprintf(&tmp, "%s/archived-checksum", key);
107		if( xar_prop_get(f, tmp, &value) == 0 ) {
108			origcsum = value;
109		}
110		free(tmp);
111
112		if( offset && length && origcsum ) {
113			heap_check(fd, name, key, offset, length, origcsum);
114			offset = 0;
115			length = 0;
116			origcsum = NULL;
117		}
118	}
119
120}
121
122int main(int argc, char *argv[]) {
123	char *file = argv[1];
124	xar_t x;
125	xar_iter_t ifile, iprop, iattr;
126	xar_file_t f;
127	const char *key;
128	int fd;
129	off_t off;
130	xar_header_t hdr;
131
132	x = xar_open(file, READ);
133	if( !x ) {
134		fprintf(stderr, "Error opening archive\n");
135		exit(1);
136	}
137
138	fd = open(file, O_RDONLY);
139	if( fd < 0 ) {
140		fprintf(stderr, "Error opening archive\n");
141		exit(1);
142	}
143
144	read(fd, &hdr, sizeof(hdr));
145	hdr.size = htons(hdr.size);
146	hdr.toc_length_compressed = xar_ntoh64(hdr.toc_length_compressed);
147	HeapOff = hdr.size + hdr.toc_length_compressed;
148
149	ifile = xar_iter_new();
150	if( !ifile ) {
151		fprintf(stderr, "Error creating file iterator");
152		exit(1);
153	}
154
155	for(f = xar_file_first(x, ifile); f; f = xar_file_next(ifile)) {
156		prop_check(fd, x, f);
157	}
158
159}
160