2 * Copyright (C) 2001-2007 Red Hat, Inc.
4 * Michael Fulbright <msf@redhat.com>
5 * Dustin Kirkland <dustin.dirkland@gmail.com>
6 * Added support for checkpoint fragment sums;
7 * Exits media check as soon as bad fragment md5sum'ed
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 #include <sys/types.h>
33 #include "libimplantisomd5.h"
35 #define APPDATA_OFFSET 883
36 #define SIZE_OFFSET 84
38 /* Length in characters of string used for fragment md5sum checking */
39 #define FRAGMENT_SUM_LENGTH 60
40 /* FRAGMENT_COUNT must be an integral divisor or FRAGMENT_SUM_LENGTH */
41 /* 60 => 2, 3, 4, 5, 6, 10, 12, 15, 20, or 30 */
42 #define FRAGMENT_COUNT 20
44 /* number of sectors to ignore at end of iso when computing sum */
45 #define SKIPSECTORS 15
47 #define MAX(x, y) ((x > y) ? x : y)
48 #define MIN(x, y) ((x < y) ? x : y)
50 /* finds primary volume descriptor and returns info from it */
51 /* mediasum must be a preallocated buffer at least 33 bytes long */
52 static int parsepvd(int isofd, char *mediasum, long long *isosize) {
53 unsigned char buf[2048];
55 unsigned char *p __attribute__((unused));
57 if (lseek(isofd, 16*2048, SEEK_SET) == -1)
58 return ((long long)-1);
62 if (read(isofd, buf, 2048L) == -1)
63 return ((long long)-1);
66 /* found primary volume descriptor */
68 else if (buf[0] == 255)
69 /* hit end and didn't find primary volume descriptor */
70 return ((long long)-1);
76 memcpy(mediasum, buf + APPDATA_OFFSET + 13, 32);
79 for (p=mediasum; *p; p++)
83 /* if the md5sum was all spaces, we didn't find md5sum */
89 *isosize = (buf[SIZE_OFFSET]*0x1000000+buf[SIZE_OFFSET+1]*0x10000 +
90 buf[SIZE_OFFSET+2]*0x100 + buf[SIZE_OFFSET+3]) * 2048LL;
96 static unsigned int writeAppData(unsigned char *appdata, char *valstr, unsigned int loc) {
97 if (loc + strlen(valstr) > 511) {
98 printf("Attempted to write too much appdata, exiting...\n");
102 memcpy(appdata + loc, valstr, strlen(valstr));
104 return loc+strlen(valstr);
110 int implantISOFile(char *fname, int supported, int forceit, int quiet, char **errstr) {
116 int current_fragment = 0;
117 int previous_fragment = 0;
119 long long isosize, total;
120 unsigned char md5sum[16];
121 unsigned char fragmd5sum[16];
123 unsigned int bufsize = 32768;
125 unsigned char orig_appdata[512];
126 unsigned char new_appdata[512];
129 char fragstr[FRAGMENT_SUM_LENGTH+1];
130 MD5_CTX md5ctx, fragmd5ctx;
132 isofd = open(fname, O_RDWR);
135 *errstr = "Error - Unable to open file %s\n\n";
139 pvd_offset = parsepvd(isofd, mediasum, &isosize);
140 if (pvd_offset < 0) {
141 *errstr = "Could not find primary volumne!\n\n";
145 lseek(isofd, pvd_offset + APPDATA_OFFSET, SEEK_SET);
146 nread = read(isofd, orig_appdata, 512);
150 for (i=0; i < 512; i++)
151 if (orig_appdata[i] != ' ')
155 *errstr = "Application data has been used - not implanting md5sum!\n";
159 /* write out blanks to erase old app data */
160 lseek(isofd, pvd_offset + APPDATA_OFFSET, SEEK_SET);
161 memset(new_appdata, ' ', 512);
162 i = write(isofd, new_appdata, 512);
164 printf("write failed %d\n", i);
170 lseek(isofd, 0L, SEEK_SET);
174 buf = malloc(bufsize * sizeof(unsigned char));
177 /* read up to 15 sectors from end, due to problems reading last few */
178 /* sectors on burned CDs */
179 while (total < isosize - SKIPSECTORS*2048) {
180 nattempt = MIN(isosize - SKIPSECTORS*2048 - total, bufsize);
181 nread = read(isofd, buf, nattempt);
186 MD5_Update(&md5ctx, buf, nread);
188 /* if we're onto the next fragment, calculate the previous sum and write */
189 current_fragment = total * (FRAGMENT_COUNT+1) / (isosize - SKIPSECTORS*2048);
190 if ( current_fragment != previous_fragment ) {
191 memcpy(&fragmd5ctx, &md5ctx, sizeof(MD5_CTX));
192 MD5_Final(fragmd5sum, &fragmd5ctx);
193 for (i=0; i<FRAGMENT_SUM_LENGTH/FRAGMENT_COUNT; i++) {
195 snprintf(tmpstr, 2, "%01x", fragmd5sum[i]);
196 strncat(fragstr, tmpstr, 2);
198 /* printf("\nFragment [%i]: %s\n", previous_fragment, fragstr); */
199 previous_fragment = current_fragment;
202 total = total + nread;
206 MD5_Final(md5sum, &md5ctx);
209 for (i=0; i<16; i++) {
211 snprintf (tmpstr, 4, "%02x", md5sum[i]);
212 strncat(md5str, tmpstr, 2);
216 printf("Inserting md5sum into iso image...\n");
217 printf("md5 = %s\n", md5str);
218 printf("Inserting fragment md5sums into iso image...\n");
219 printf("fragmd5 = %s\n", fragstr);
220 printf("frags = %d\n", FRAGMENT_COUNT);
222 /* memcpy(new_appdata, orig_appdata, 512); */
223 memset(new_appdata, ' ', 512);
226 loc = writeAppData(new_appdata, "ISO MD5SUM = ", loc);
227 loc = writeAppData(new_appdata, md5str, loc);
228 loc = writeAppData(new_appdata, ";", loc);
230 buf = malloc(512 * sizeof(unsigned char));
231 snprintf((char *)buf, 512, "SKIPSECTORS = %d", SKIPSECTORS);
233 loc = writeAppData(new_appdata, (char *)buf, loc);
234 loc = writeAppData(new_appdata, ";", loc);
239 printf("Setting supported flag to 1\n");
240 loc = writeAppData(new_appdata, "RHLISOSTATUS=1", loc);
243 printf("Setting supported flag to 0\n");
244 loc = writeAppData(new_appdata, "RHLISOSTATUS=0", loc);
247 loc = writeAppData(new_appdata, ";", loc);
249 loc = writeAppData(new_appdata, "FRAGMENT SUMS = ", loc);
250 loc = writeAppData(new_appdata, fragstr, loc);
251 loc = writeAppData(new_appdata, ";", loc);
253 buf = malloc(512 * sizeof(unsigned char));
254 snprintf((char *)buf, 512, "FRAGMENT COUNT = %d", FRAGMENT_COUNT);
255 loc = writeAppData(new_appdata, (char *)buf, loc);
256 loc = writeAppData(new_appdata, ";", loc);
259 loc = writeAppData(new_appdata, "THIS IS NOT THE SAME AS RUNNING MD5SUM ON THIS ISO!!", loc);
261 i = lseek(isofd, pvd_offset + APPDATA_OFFSET, SEEK_SET);
263 printf("seek failed\n");
265 i = write(isofd, new_appdata, 512);
267 printf("write failed %d\n", i);