/* Copyright 1998, Merit Network, Inc. and the University of Michigan */
/* $Id: mailchk.c,v 1.7 2002/10/23 02:58:50 ljb Exp $
* originally Id: mailchk.c,v 1.2 1998/08/10 19:24:23 dogcow Exp */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <regex.h>
#include <stdlib.h>
#include <errno.h>
#include <regex.h>
#include <irrauth.h> /* Includes the PGP cookies, pgpmailauth and pgpkeyauth */
#define BIGSTRBUFLEN 2048 /* space for large strings */
#define SMALLSTRBUFLEN 256 /* space for small strings */
extern trace_t *default_trace;
/* Given a transaction file that has been stripped of PGP encoding
* information (if there are any PGP signatures), append email header
* information and 'password:' fields to each object in the transaction file.
* Email header information is the 'From', 'msg-id', 'date', and 'subject'
* email fields.
*
* Recall the ripe181 password convention. If a password field appears
* anywhere in a transaction it applies to the rest of the objects.
* So this routine looks for any password fields and appends the password
* to all subsequent objects in the transaction.
*
* When we refer to "append" information, we mean append a field of the form:
* HDR-XXX: <value>
* the syntax checker is designed to recognized these fields as special
* and to pass them to the auth checker to use. See hdr_fields.c for a
* listing of all the header fields.
*
* Return:
* 0..n (ie, number of non-null lines read)
* this routine can detect null submissions
* -1 an error occured (eg, opening the input file)
*/
int addmailcookies (trace_t *tr, int daemon_mode, char *infn, char *outfn) {
char curline[BIGSTRBUFLEN], passwd[SMALLSTRBUFLEN];
char email_info[BIGSTRBUFLEN], from_line[SMALLSTRBUFLEN];
char *hdr, *strptr;
FILE *infile, *outfile;
regex_t mailfromre, mailfromncre, messidre, subjre, datere;
regex_t blanklinere, cookieinsre, passwdre, mailreplytore;
regmatch_t mailfromrm[4];
int in_headers = 1, count_lines = 0;
int first_line = 1, seen_reply_to = 0;
int unknown_user = 0;
int whichoffset = 0, eo, so, prev, obj_len;
int end_obj = 0, src_seen = 0, in_obj = 0, done = 0;
infile = myfopen(tr, infn, "r", "addmailcookies(): input file");
if (infile == NULL)
return(-1);
outfile = myfopen(tr, outfn, "w", "addmailcookies(): output file");
if (outfile == NULL) {
fclose(infile);
return(-1);
}
/* initialization */
passwd[0] = '\0';
from_line[0] = '\0';
email_info[0] = '\0';
regcomp(&mailfromre, mailfrom, (REG_EXTENDED|REG_ICASE));
regcomp(&mailreplytore, mailreplyto, (REG_EXTENDED|REG_ICASE));
regcomp(&mailfromncre, mailfromnc, REG_ICASE);
regcomp(&messidre, messid, (REG_EXTENDED|REG_ICASE));
regcomp(&subjre, subj, REG_EXTENDED|REG_ICASE);
regcomp(&datere, date, REG_EXTENDED|REG_ICASE);
regcomp(&blanklinere, blankline, REG_EXTENDED|REG_NOSUB);
regcomp(&cookieinsre, cookieins, (REG_NOSUB|REG_EXTENDED|REG_ICASE));
regcomp(&passwdre, password, (REG_EXTENDED|REG_ICASE));
while (!done) {
/* loop reading lines from message - allow room to append \n\0 */
done = (NULL == fgets (curline, BIGSTRBUFLEN - 2, infile)) ? 1 : 0;
if (done) {
if (memcmp (curline, "password:", 9)) {
if (curline[strlen (curline) - 1] != '\n')
fputs ("\n", outfile);
if (curline[0] == '\n')
break;
}
memcpy (curline, "\n", 2);
}
if (first_line && 0 != regexec (&mailfromncre, curline, 0, 0, 0)) {
in_headers = 0;
if (!daemon_mode) /* it's not a mail or tcp submission */
unknown_user = 1;
}
/* The first line _has_ to match /^From/, or else it's not really a
mail message. The syntax checker doesn't like the mail headers as
an object. :) */
first_line = 0;
if (in_headers && regexec (&blanklinere, curline, 0, 0, 0) == 0) {
in_headers = 0;
if (seen_reply_to == 0 && from_line[0] != '\0')
if (strlen(email_info) + strlen(from_line) > BIGSTRBUFLEN) {
trace(ERROR, tr, "Email headers exceeds maximum length of %d:\n %s%s", BIGSTRBUFLEN, email_info, from_line);
fclose(outfile);
unlink(outfn);
return(-1);
}
strcat (email_info, from_line);
}
/* have to special case /From(:?)/ because it can have stuff in either
match position one or three. */
/* pick off the 'From', 'msg-id', 'date', 'subject' from the
* the email header (if there is one)
*/
if (in_headers) {
so = eo = -1; hdr = NULL; /* make the compiler happy */
if (0 == regexec(&mailfromre, curline, 4, mailfromrm, 0)) {
if (mailfromrm[3].rm_so != -1)/* <foo@bar> stuff */
whichoffset = 3;
else
whichoffset = 1;
obj_len = mailfromrm[whichoffset].rm_eo - mailfromrm[whichoffset].rm_so;
if (obj_len >= SMALLSTRBUFLEN - strlen(FROM) - 2) {
trace(ERROR, tr, "Mail From \"%s\" exceeds maximum length of %d.\n", curline, SMALLSTRBUFLEN - strlen(FROM) - 2);
fclose(outfile);
unlink(outfn);
return(-1);
}
strcpy (from_line, (char *) FROM);
strptr = from_line + strlen(FROM);
memcpy (strptr, (char *) (curline + mailfromrm[whichoffset].rm_so),
(size_t) (obj_len));
strptr += obj_len;
*strptr++ = '\n';
*strptr = '\0';
} /* header snarf */
if (0 == regexec(&mailreplytore, curline, 4, mailfromrm, 0)) {
seen_reply_to = 1;
if (mailfromrm[3].rm_so != -1)/* <foo@bar> stuff */
whichoffset = 3;
else
whichoffset = 1;
so = mailfromrm[whichoffset].rm_so;
eo = mailfromrm[whichoffset].rm_eo;
hdr = (char *) FROM;
} /* header snarf */
else if (0 == regexec(&messidre, curline, 2, mailfromrm, 0)) {
so = mailfromrm[1].rm_so;
eo = mailfromrm[1].rm_eo;
hdr = (char *) MSG_ID;
}
else if (0 == regexec(&subjre, curline, 2, mailfromrm, 0)) {
so = mailfromrm[1].rm_so;
eo = mailfromrm[1].rm_eo;
hdr = (char *) SUBJECT;
}
else if (0 == regexec(&datere, curline, 2, mailfromrm, 0)) {
so = mailfromrm[1].rm_so;
eo = mailfromrm[1].rm_eo;
hdr = (char *) DATE;
}
if (so != -1) {
*(curline + eo + 1) = '\0';
*(curline + eo) = '\n';
if (strlen(email_info) + strlen(hdr) + strlen((char *) (curline + so)) > BIGSTRBUFLEN) {
trace(ERROR, tr, "Email headers exceeds maximum length of %d:\n %s%s%s", BIGSTRBUFLEN, email_info, hdr, (char *) (curline + so));
fclose(outfile);
unlink(outfn);
return(-1);
}
strcat (email_info, hdr);
strcat (email_info, (char *) (curline + so));
}
}
/* else not in headers */
else {
prev = in_obj;
if (regexec (&blanklinere, curline, (size_t) 0, NULL, 0)) {
if (in_obj == 0) {
src_seen = 0;
if (unknown_user) {
fputs ((char *) HDR_START, outfile);
fputs ("\n", outfile);
fputs ((char *) FROM, outfile);
fputs ((char *) UNKNOWN_USER_NAME, outfile);
fputs ("\n", outfile);
fputs ((char *) UNKNOWN_USER, outfile);
fputs ("\n", outfile);
fputs ((char *) HDR_END, outfile);
fputs ("\n", outfile);
}
}
in_obj = 1;
end_obj = 0;
count_lines++;
}
else {
end_obj = in_obj;
in_obj = 0;
}
if (in_obj && !src_seen)
src_seen = (int) (0 == regexec (&cookieinsre, curline, (size_t) 0, NULL, 0));
/*
printf ("(end_obj, src_seen)=(%d,%d):%s", end_obj, src_seen, curline);
*/
if (0 == regexec (&passwdre, curline, 3, mailfromrm, 0)) {
if (mailfromrm[1].rm_so != -1) {
if (mailfromrm[2].rm_so != -1)
whichoffset = 2;
else
whichoffset = 1;
/* enclose passwd in '"'s; it can have spaces in it :( */
obj_len = mailfromrm[whichoffset].rm_eo - mailfromrm[1].rm_so;
if (obj_len >= SMALLSTRBUFLEN - 3) {
trace(ERROR, tr, "Passord \"%s\" exceeds maximum length of %d.\n", curline, SMALLSTRBUFLEN - 3);
fclose(outfile);
unlink(outfn);
return(-1);
}
passwd[0] = '"';
memcpy ((passwd + 1), (char *) (curline + mailfromrm[1].rm_so),
(size_t) (obj_len));
passwd[obj_len + 1] = '"';
passwd[obj_len + 2] = '\0';
}
in_obj = prev;
continue;
}
if (end_obj) {
if (src_seen && passwd[0] != '\0') {
fprintf (outfile, "password: %s\n", passwd);
/* Don't log users' password unlesss debugging */
/* trace (NORM, tr, "Admincookies found password: (%s)\n", passwd); */
}
if (email_info[0] != '\0')
fputs (email_info, outfile);
}
fputs (curline, outfile);
}
} /* fgets */
/* empty submission, make a legal header for notify routine */
if (count_lines == 0) {
fputs ((char *) HDR_START, outfile);
fputs ("\n", outfile);
fputs (email_info, outfile);
fputs ((char *) HDR_END, outfile);
fputs ("\n", outfile);
}
regfree (&messidre);
regfree (&mailfromre);
regfree (&mailreplytore);
regfree (&mailfromncre);
regfree (&subjre);
regfree (&datere);
regfree (&blanklinere);
regfree (&cookieinsre);
regfree (&passwdre);
fclose (outfile);
fclose (infile);
if (unknown_user)
return 0;
return count_lines;
}
syntax highlighted by Code2HTML, v. 0.9.1