/* * md5.c - routines to handle MD5 checksums * * Copyright (C) 2002-2003 Gero Kuhlmann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: md5.c,v 1.4 2003/01/25 23:29:42 gkminix Exp $ */ #include #include #include "makerom.h" #include "doconfig.h" #include "md5.h" /* * Definition of list of checksums */ struct md5rec { char *md5sum; char *fname; struct md5rec *next; }; static struct md5rec *md5list = NULL; /* * Read one line of MD5 checksum file */ static int md5line(fd, md5buf, fnambuf) FILE *fd; char *md5buf; char *fnambuf; { int state; int c, i, j; /* Read each character of the next input line */ i = j = state = 0; while ((c = fgetc(fd)) != '\n' && c != '\0' && c != EOF) { switch (state) { case 0: if (isxdigit(c)) { if (i >= MD5_SUM_LENGTH) state = 4; else md5buf[i++] = tolower(c); } else if (i == 0 && c == '#') state = 5; else if (i > 0 && isspace(c)) state = (i == MD5_SUM_LENGTH ? 1 : 4); else if (i > 0 || !isspace(c)) state = 4; break; case 1: if (isspace(c) || c == '*') break; else state = 2; /* Fall through */ case 2: if (isprint(c)) { if (j >= MAXPATHLEN) state = 4; else fnambuf[j++] = c; } else if (isspace(c)) state = 3; else state = 4; break; case 3: case 4: case 5: /* Skip rest of line */ break; } } md5buf[i] = '\0'; fnambuf[j] = '\0'; return(state == 3 || (state == 2 && j > 0) ? 1 : (state == 5 || i == 0 ? 2 : 0)); } /* * Find an entry in the MD5 checksum database */ static struct md5rec *findfile(fname) char *fname; { struct md5rec *mp; for (mp = md5list; mp != NULL; mp = mp->next) if (!strcmp(mp->fname, fname)) break; return(mp); } /* * Read a file containing MD5 checksum strings * * Each line contains a 32 character MD5 checksum and a file name. The * last modification time of each file is compared against the last * modification time of the checksum file. If the checksum file is older * the checksum entry is considered to be invalid. */ void readmd5(fname) char *fname; { FILE *fd; struct md5rec *mp; char *chksum, *drvname; char *tmpfname = NULL; time_t fdtime; int i, lineno, errno, warnno; /* Get the last modification time of the checksum file */ fdtime = filetime(fname, FT_MTIME); /* Allocate buffers and open input file */ chksum = nbmalloc(MD5_SUM_LENGTH + 1); drvname = nbmalloc(MAXPATHLEN + 1); if ((fd = fopen(fname, "r")) == NULL) { prnerr1("unable to open MD5 checksum file %s", fname); exit(EXIT_MAKEROM_MD5FILE); } /* Read each line of input file */ lineno = 1; errno = 0; warnno = 0; while (!feof(fd)) { if ((i = md5line(fd, chksum, drvname)) == 0) { prnerr1("MD5 checksum file line %d: invalid line", lineno); errno++; } else if (i == 1) { /* Check if file exists */ copystr(&tmpfname, drvname); checkaccess(&tmpfname, config.netdrvdir); if (tmpfname != NULL) { if (findfile(tmpfname) != NULL) { prnerr1("MD5 checksum file line %d: file already defined", lineno); errno++; free(tmpfname); } else if (fdtime < filetime(tmpfname, FT_MTIME)) { prnerr1("File %s is newer than MD5 checksum file", tmpfname); warnno++; free(tmpfname); } else { mp = nbmalloc(sizeof(struct md5rec)); copystr(&(mp->md5sum), chksum); mp->fname = tmpfname; mp->next = md5list; md5list = mp; } tmpfname = NULL; } else { prnerr1("MD5 checksum file line %d: file does not exist", lineno); warnno++; } } lineno++; } /* Close input file and free buffers */ fclose(fd); free(chksum); free(drvname); if (errno > 0) exit(EXIT_MAKEROM_MD5FILE); if (warnno > 0) { prnerr0("The MD5 checksum file contains entries which are older than"); prnerr0("the files they reference. These entries will not be used,"); prnerr0("so the result of running this program might not be what you"); prnerr0("expect. Please update the MD5 checksum file or let your"); prnerr0("system administrator update it."); } } /* * Check a filename and it's checksum against the entries in the checksum * file. If the checksums don't match, or the file name doesn't exist in * the checksum database, clear the fname parameter. */ void checkmd5sum(fname, md5sum) char **fname; char *md5sum; { struct md5rec *mp; if (fname != NULL && *fname != NULL && md5sum != NULL) { mp = findfile(*fname); if (mp == NULL || strcmp(mp->md5sum, md5sum)) { /* File doesn't exist in database or checksums don't match */ free(*fname); *fname = NULL; } } } /* * Clear the MD5 checksum database */ void clearmd5() { struct md5rec *mp; while (md5list != NULL) { mp = md5list; if (mp->fname != NULL) free(mp->fname); if (mp->md5sum != NULL) free(mp->md5sum); md5list = mp->next; free(mp); } }