diff options
Diffstat (limited to 'loader2/mediacheck.c')
-rw-r--r-- | loader2/mediacheck.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/loader2/mediacheck.c b/loader2/mediacheck.c new file mode 100644 index 000000000..f82a5fd37 --- /dev/null +++ b/loader2/mediacheck.c @@ -0,0 +1,370 @@ +/* simple program to check implanted md5sum in an iso 9660 image */ +/* Copyright 2001 Red Hat, Inc. */ +/* Michael Fulbright msf@redhat.com */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <newt.h> + +#include "md5.h" + +#include "log.h" + +#define APPDATA_OFFSET 883 +#define SIZE_OFFSET 84 + +#define MAX(x, y) ((x > y) ? x : y) +#define MIN(x, y) ((x < y) ? x : y) + +typedef void (*checkCallback)(void *, long long offset); + +struct progressCBdata { + newtComponent scale; + newtComponent label; +}; + +#ifdef TESTING +#define _(x) (x) +#else +#include "lang.h" +#endif + +/* finds primary volume descriptor and returns info from it */ +/* mediasum must be a preallocated buffer at least 33 bytes long */ +int parsepvd(int isofd, char *mediasum, int *skipsectors, long long *isosize, int *isostatus) { + unsigned char buf[2048]; + unsigned char buf2[512]; + unsigned char tmpbuf[512]; + int skipfnd, md5fnd, isostatusfnd; + unsigned int loc; + long long offset; + unsigned char *p; + + if (lseek(isofd, (off_t)(16L * 2048L), SEEK_SET) == -1) + return ((long long)-1); + + offset = (16L * 2048L); + for (;1;) { + if (read(isofd, buf, 2048) <= 0) + return ((long long)-1); + + if (buf[0] == 1) + /* found primary volume descriptor */ + break; + else if (buf[0] == 255) + /* hit end and didn't find primary volume descriptor */ + return ((long long)-1); + offset += 2048L; + } + + /* read out md5sum */ + memcpy(buf2, buf + APPDATA_OFFSET, 512); + buf2[511] = '\0'; + + *isostatus = 0; + + md5fnd = 0; + skipfnd = 0; + isostatusfnd = 0; + loc = 0; + while (loc < 512) { + if (!strncmp(buf2 + loc, "ISO MD5SUM = ", 13)) { + + /* logMessage("Found ISO MD5SUM"); */ + + /* make sure we dont walk off end */ + if ((loc + 32) > 511) + return -1; + + memcpy(mediasum, buf2 + loc + 13, 32); + mediasum[32] = '\0'; + md5fnd = 1; + + logMessage("MD5SUM -> %s", mediasum); + + loc += 45; + for (p=buf2+loc; loc < 512 && *p != ';'; p++, loc++); + } else if (!strncmp(buf2 + loc, "SKIPSECTORS = ", 14)) { + char *errptr; + + /* make sure we dont walk off end */ + if ((loc + 14) > 511) + return -1; + + /* logMessage("Found SKIPSECTORS"); */ + loc = loc + 14; + for (p=tmpbuf; loc < 512 && buf2[loc] != ';'; p++, loc++) + *p = buf2[loc]; + + *p = '\0'; + + /* logMessage("SKIPSECTORS -> |%s|", tmpbuf); */ + + *skipsectors = strtol(tmpbuf, &errptr, 10); + if (errptr && *errptr) { + logMessage("Could not parse |%s|", errptr); + return -1; + } else { + logMessage("skipsectors = %d", *skipsectors); + skipfnd = 1; + } + + for (p=buf2+loc; loc < 512 && *p != ';'; p++, loc++); + } else if (!strncmp(buf2 + loc, "RHLISOSTATUS=1", 14)) { + *isostatus = 1; + isostatusfnd = 1; + logMessage("isostatus = 1"); + } else if (!strncmp(buf2 + loc, "RHLISOSTATUS=0", 14)) { + *isostatus = 0; + isostatusfnd = 1; + logMessage("isostatus = 0"); + } else { + loc++; + } + + if ((skipfnd & md5fnd) & isostatusfnd) + break; + } + + if (!(skipfnd & md5fnd)) + return -1; + + /* get isosize */ + *isosize = (buf[SIZE_OFFSET]*0x1000000+buf[SIZE_OFFSET+1]*0x10000 + + buf[SIZE_OFFSET+2]*0x100 + buf[SIZE_OFFSET+3]) * 2048LL; + + return offset; +} + +/* returns -1 if no checksum encoded in media, 0 if no match, 1 if match */ +/* mediasum is the sum encoded in media, computedsum is one we compute */ +/* both strings must be pre-allocated at least 33 chars in length */ +int checkmd5sum(int isofd, char *mediasum, char *computedsum, + checkCallback cb, void *cbdata) { + int nread; + int i; + int appdata_start_offset, appdata_end_offset; + int nattempt; + int skipsectors; + int isostatus; + unsigned int bufsize = 32768; + unsigned char md5sum[16]; + unsigned int len; + unsigned char *buf; + long long isosize, offset, pvd_offset, apoff; + MD5_CTX md5ctx; + + isostatus = 0; + if ((pvd_offset = parsepvd(isofd, mediasum, &skipsectors, &isosize, &isostatus)) < 0) + return -1; + + /* rewind, compute md5sum */ + lseek(isofd, 0L, SEEK_SET); + + MD5_Init(&md5ctx); + + offset = 0; + apoff = pvd_offset + APPDATA_OFFSET; + + buf = malloc(bufsize * sizeof(unsigned char)); + while (offset < isosize - skipsectors*2048) { + nattempt = MIN(isosize - skipsectors*2048 - offset, bufsize); + + nread = read(isofd, buf, nattempt); + if (nread <= 0) + break; + + /* overwrite md5sum we implanted with original data */ + if (offset < apoff && offset+nread >= apoff) { + appdata_start_offset = apoff - offset; + appdata_end_offset = MIN(appdata_start_offset+MIN(nread, 512), + offset + nread - apoff); + len = appdata_end_offset - appdata_start_offset; + memset(buf+appdata_start_offset, ' ', len); + } else if (offset >= apoff && offset+nread < apoff + 512) { + appdata_start_offset = 0; + appdata_end_offset = nread; + len = appdata_end_offset - appdata_start_offset; + memset(buf+appdata_start_offset, ' ', len); + } else if (offset < apoff + 512 && offset+nread >= apoff + 512) { + appdata_start_offset = 0; + appdata_end_offset = apoff + 512 - offset; + len = appdata_end_offset - appdata_start_offset; + memset(buf+appdata_start_offset, ' ', len); + } + + MD5_Update(&md5ctx, buf, nread); + offset = offset + nread; + if (cb) + cb(cbdata, offset); + } + + if (cb) + cb(cbdata, isosize); + + sleep(1); + + free(buf); + + MD5_Final(md5sum, &md5ctx); + + *computedsum = '\0'; + for (i=0; i<16; i++) { + char tmpstr[4]; + snprintf (tmpstr, 4, "%02x", md5sum[i]); + strcat(computedsum, tmpstr); + } + + if (strcmp(mediasum, computedsum)) + return 0; + else + return 1; + } + + +static void readCB(void *co, long long pos) { + struct progressCBdata *data = co; + static int tick = 0; + char tickmark[2] = "-"; + char * ticks = "-\\|/"; + + newtScaleSet(data->scale, pos); + tick++; + if (tick > 399) tick = 0; + *tickmark = ticks[tick / 100]; + + newtLabelSetText(data->label, tickmark); + newtRefresh(); +} + +int doMediaCheck(int isofd, char *descr, char *mediasum, char *computedsum, long long *isosize, int *isostatus) { + struct progressCBdata data; + newtComponent t, f, scale, label; + int rc; + int dlen; + int llen; + int skipsectors; + char tmpstr[1024]; + + if (parsepvd(isofd, mediasum, &skipsectors, isosize, isostatus) < 0) { + newtWinMessage(_("Error"), _("OK"), + _("Unable to read the disc checksum from the " + "primary volume descriptor. This probably " + "means the disc was created without adding the " + "checksum.")); + return -1; + } + + if (descr) + snprintf(tmpstr, sizeof(tmpstr), _("Checking \"%s\"..."), descr); + else + snprintf(tmpstr, sizeof(tmpstr), _("Checking media now...")); + + dlen = strlen(tmpstr); + if (dlen > 65) + dlen = 65; + + newtCenteredWindow(dlen+8, 6, _("Media Check")); + t = newtTextbox(1, 1, dlen+4, 3, NEWT_TEXTBOX_WRAP); + + newtTextboxSetText(t, tmpstr); + llen = strlen(tmpstr); + + label = newtLabel(llen+1, 1, "-"); + f = newtForm(NULL, NULL, 0); + newtFormAddComponent(f, t); + scale = newtScale(3, 3, dlen, *isosize); + newtFormAddComponent(f, scale); + + newtDrawForm(f); + newtRefresh(); + + data.scale = scale; + data.label = label; + + rc = checkmd5sum(isofd, mediasum, computedsum, readCB, &data); + + newtFormDestroy(f); + newtPopWindow(); + + return rc; +} + +int mediaCheckFile(char *file, char *descr) { + int isofd; + int rc; + int isostatus; + char *result; + unsigned char mediasum[33], computedsum[33]; + char tmpstr[256]; + char descrstr[256]; + long long isosize; + newtComponent t, f; + + isofd = open(file, O_RDONLY); + + if (isofd < 0) { + newtWinMessage(_("Error"), _("OK"), _("Unable to find install image " + "%s"), file); + return -1; + } + + isostatus = 0; + rc = doMediaCheck(isofd, descr, mediasum, computedsum, &isosize, &isostatus); + close(isofd); + + if (rc == 0) { + result = _("FAIL.\n\nIt is not recommended to use this media."); + logMessage("mediacheck: %s (%s) FAILED", file, descr); + logMessage("value of isostatus iso flag is %d", isostatus); + } else if (rc > 0) { + result = _("PASS.\n\nIt is OK to install from this media."); + logMessage("mediacheck: %s (%s) PASSED", file, descr); + logMessage("value of isostatus iso flag is %d", isostatus); + } else { + result = _("NA.\n\nNo checksum information available, unable to verify media."); + logMessage("mediacheck: %s (%s) has no checksum info", file, descr); + } + + newtCenteredWindow(60, 13, _("Media Check Result")); + t = newtTextbox(4, 1, 52, 8, NEWT_TEXTBOX_WRAP); + if (descr) + snprintf(descrstr, sizeof(descrstr), + _("of the image:\n\n%s\n\n"), descr); + else + descrstr[0] = '\0'; + + snprintf(tmpstr, sizeof(tmpstr), _("The media check %sis complete, and " + "the result is: %s\n"), descrstr, result); + newtTextboxSetText(t, tmpstr); + f = newtForm(NULL, NULL, 0); + newtFormAddComponent(f, t); + newtFormAddComponent(f, newtButton(26, 9, _("OK"))); + + newtRunForm(f); + newtFormDestroy(f); + newtPopWindow(); + return rc; +} + +#ifdef TESTING + +int main(int argc, char **argv) { + int rc; + + if (argc < 2) { + printf("Usage: checkisomd5 <isofilename>\n\n"); + exit(1); + } + + newtInit(); + newtCls(); + rc = mediaCheckFile(argv[1]); + newtFinished(); +} +#endif |