/*
* md5.c - routines to handle MD5 checksums
*
* Copyright (C) 2002-2003 Gero Kuhlmann <gero@gkminix.han.de>
*
* 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 <common.h>
#include <nblib.h>
#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);
}
}
syntax highlighted by Code2HTML, v. 0.9.1