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