home *** CD-ROM | disk | FTP | other *** search
- RCS_ID_C= "$Id: smtpd.c,v 1.7 1994/02/06 10:07:33 gwalter Rel $";
- /*
- * smtpd.c --- an example of TCP daemon for AmiTCP/IP
- *
- * $Log: smtpd.c,v $
- * Revision 1.7 1994/02/06 10:07:33 gwalter
- * Changed to use TCPLog from logger.lib
- * Line buffer size increased
- *
- * Revision 1.6 1994/02/01 19:49:35 gwalter
- * Parameters added, tidying
- *
- * Revision 1.5 1994/01/09 14:01:27 gwalter
- * Timeouts, improved logging
- *
- * Revision 1.3 1993/12/30 16:38:18 gwalter
- * Changed to display QUIT command from client.
- *
- * Revision 1.2 1993/12/21 09:44:14 gwalter
- * Reference to pathnames.h removed
- *
- * Revision 1.1 1993/12/21 09:34:12 gwalter
- * Initial revision
- *
- * Revision 1.1 1993/12/05 18:10:02 gwalter
- * Initial revision
- *
- *
- */
-
- #include "smtpd_rev.h"
-
- char ApplicationID[] = "SMTPD";
-
- const char version[] = VERSTAG;
-
- char copyright[] =
- "Copyright © 1993 Graham Walter, <amitcp@gwalter.demon.co.uk>\n"
- "20 Kingstable St, Eton, Berks, England.\n";
-
- #ifdef AMIGA
- #if __SASC
- #include <proto/socket.h>
- #include <proto/dos.h>
- #include <clib/exec_protos.h>
- #include <pragmas/exec_sysbase_pragmas.h>
- #elif __GNUC__
- #include <inline/socket.h>
- #include <inline/exec.h>
- #else
- #include <clib/socket_protos.h>
- #endif
- #endif /* AMIGA */
-
- #include <errno.h>
- #include <netdb.h>
-
- #include <sys/param.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <sys/syslog.h>
-
- #include <signal.h>
-
- #include <dos/dos.h>
- #include <exec/execbase.h>
- #include <dos/var.h>
- #include <dos/dostags.h>
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <time.h>
- #include <inetdlib.h>
-
- #include <lineread.h>
-
- #include "smtpd.h"
-
- char * gethostname( char * host, long size );
-
- extern struct ExecBase *SysBase;
-
- BPTR Stdin = NULL;
- BPTR Stdout = NULL;
- BPTR Stderr = NULL;
-
- char ** LocalHostAliases;
- char * LocalHost;
- char PeerName[MAX_HOSTLEN+1];
-
- char * LogFileName;
- char * RMailCommand = RMAIL_TEMPLATE;
-
- int ErrorCount;
-
- void
- _STIdosStdio(void)
- {
- struct Process *p = (struct Process *)SysBase->ThisTask;
-
- Stdin = p->pr_CIS;
- Stdout = p->pr_COS;
- Stderr = p->pr_CES ? p->pr_CES : Stdout;
- }
-
- /* Handle various mailer errors. */
-
- static char * ApplicationErrorMsgs[] =
- {
- "" /*"Network fault"*/,
- MAILERR_TEXT_BAD_RESPONSE,
- MAILERR_TEXT_NOTEMP,
- MAILERR_TEXT_INVALID_COMMAND,
- MAILERR_TEXT_SEND_ERROR,
- MAILERR_TEXT_NO_MEMORY,
- MAILERR_TEXT_EXPECTING_HELO,
- MAILERR_TEXT_TEMPWRITE,
- MAILERR_TEXT_CONNECTION_LOST,
- MAILERR_TEXT_SELECT,
- MAILERR_TEXT_TIMEOUT,
- MAILERR_TEXT_LOCALHOST,
- MAILERR_TEXT_INVALID_ARGUMENTS,
- MAILERR_TEXT_NO_DELIVERY,
- MAILERR_TEXT_NOT_DELIVERED,
- MAILERR_TEXT_COMMAND_REJECT
- };
-
- void
- MailError(int Type, char * info )
- {
- char * errortext;
- char syserrorbuffer[SHORT_BUFFER_LEN];
-
- if( Type == 0 )
- {
- char * syserrortext;
-
- if( errno < __sys_nerr)
- syserrortext = (UBYTE *)__sys_errlist[errno];
- else
- syserrortext = (UBYTE *)__sys_errlist[0];
-
- sprintf( syserrorbuffer, "%s %%s", syserrortext );
- errortext = syserrorbuffer;
- }
- else
- {
- if( Type < sizeof( ApplicationErrorMsgs ) / sizeof( ApplicationErrorMsgs[0] ) )
- errortext = ApplicationErrorMsgs[Type];
- else
- errortext = MAILERR_TEXT_UNKNOWN_ERROR;
- }
-
- TCPLog( LOG_ERR, errortext, (info) ? info: "" );
-
- if( ++ErrorCount >= MAX_ERRORS )
- {
- TCPLog( LOG_CRIT, MAILERR_TEXT_ABORTING_MAXERRS );
-
- exit( 20 );
- }
- }
-
- /* Get the date, and format it for RFC822. */
-
- char *
- GetDate( void )
- {
- time_t clock;
-
- clock = time(NULL);
-
- return ctime(&clock);
- }
-
- char **
- gethostent( void )
- {
- char ** nameblock;
- char ** alias;
- char local[STD_BUFFER_LEN];
- struct hostent * hostent;
- int i;
-
- if( nameblock = calloc( MAX_ALIASES+2, sizeof( char * ) ) )
- {
- gethostname( local, sizeof( local ) );
-
- if( hostent = gethostbyname( local ) )
- {
- nameblock[0] = hostent->h_name;
-
- for( i = 1, alias = hostent->h_aliases; *alias; alias++ )
- {
- nameblock[i++] = strdup( *alias );
-
- if( i > MAX_ALIASES )
- break;
- }
- }
- else
- {
- free( nameblock );
- nameblock = NULL;
- }
- }
- else
- MailError( MAILERR_NO_MEMORY, NULL );
-
- if( ! nameblock )
- MailError( MAILERR_LOCALHOST, NULL );
-
- return( nameblock );
- }
-
- int
- StripCRLF( char * buffer )
- {
- int len;
-
- len = strlen( buffer );
-
- if( len && ( buffer[len-1] == '\n' ) )
- buffer[--len] = '\0';
-
- if( len && ( buffer[len-1] == '\r' ) )
- buffer[--len] = '\0';
-
- return( len );
- }
-
- /* Get a line from a socket */
-
- int
- GetLine( int s, char * buffer, struct LineRead * rl )
- {
- static int len = 0;
- int nfds;
- fd_set readfds;
- fd_set excepfds;
- static struct timeval timeout = { TIMEOUT, 0 };
-
- for( ;; )
- {
- if( ! len )
- {
- FD_ZERO( &readfds );
- FD_SET(s, &readfds );
-
- FD_ZERO( &excepfds );
- FD_SET(s, &excepfds );
-
- if( (nfds = select(s + 1, &readfds, NULL, &excepfds, &timeout )) < 0)
- {
- MailError( MAILERR_SELECT, "GetLine" );
- return( -1 );
- }
-
- if( ! nfds )
- {
- MailError( MAILERR_TIMEOUT, "GetLine" );
- return( -1 );
- }
- }
-
- if( ( len = lineRead( rl ) ) != 0 )
- break;
-
- if( ! rl->rl_Line )
- {
- return( -1 ); /* EOF */
- }
-
- }
-
- if( len <= 0 )
- {
- MailError( 0, "GetLine" );
- return( -1 );
- }
-
- strcpy( buffer, rl->rl_Line );
-
- return( StripCRLF( buffer ) );
- }
-
- /* Simply send some text down the socket; check the write succeeds, but don't
- check for any response. */
-
- int
- SendText(int s, char *Text)
- {
- if( send( s, Text, strlen(Text), 0 ) != strlen(Text) )
- {
- MailError( 0, "SendText" );
- return( 0 );
- }
-
- return 1;
- }
-
- int
- isCommand( char * buffer, char * Command )
- {
- int len = strlen( Command );
- int Status = FALSE;
-
- if( ( strnicmp( buffer, Command, len ) == 0 )
- && ( ( isspace( buffer[len] ) )
- || ( buffer[len] == '\0' ) ) )
- {
- Status = TRUE;
- }
-
- return( Status );
- }
-
- int StoreRecipient( char * to, char * from )
- {
- char * cp;
- char * host;
- char ** alias;
- int length;
-
- if( ! ( cp = strchr( from, ':' ) ) )
- return( FALSE );
-
- from = cp + 1;
-
- if( *from == '<' )
- {
- if( ! ( cp = strchr( from, '>' ) ) )
- return( FALSE );
-
- from ++;
- length = cp - from;
- }
- else
- {
- length = stcarg( from, " \r\n" );
- }
-
- memcpy( to, from, length );
- to[length] = '\0';
-
- if( strchr( to, '%' ) ) /* need to forward ? */
- return( FALSE );
-
- if( ! ( cp = strchr( to, '@' ) ) ) /* no host specified */
- return( TRUE );
-
- host = cp + 1;
- length = strlen( host );
- *cp = '\0';
-
- for( alias = LocalHostAliases; *alias; alias++ )
- {
- if( stricmp( host, *alias ) == 0 ) /* this host */
- return( TRUE );
-
- if( ( strnicmp( host, *alias, length ) == 0 )
- && ( (*alias)[length] == '.' ) )
- return( TRUE ); /* valid abbreviation */
- }
-
- return( FALSE );
- }
-
- int
- LogMail( ULONG fh )
- {
- ULONG logfh;
- static buffer[STD_BUFFER_LEN];
- int len;
-
- if( ! (logfh = Open( LogFileName, MODE_READWRITE ) ) )
- {
- TCPLog( LOG_WARNING, MAILERR_TEXT_LOG_OPEN_FAIL );
- return( 1 );
- }
-
- Seek( logfh, 0, OFFSET_END );
-
- Seek( fh, 0, OFFSET_BEGINNING );
-
- while( len = Read( fh, buffer, sizeof( buffer ) ) )
- {
- Write( logfh, buffer, len );
- }
-
- Write( logfh, "\n", 1 );
-
- Close( logfh );
-
- return( 0 );
- }
-
- int
- PassMailToRecipients( int s, struct LineRead * rl, char * From, ULONG rfh )
- {
- char * tfile;
- ULONG tfh;
- char * line;
- char * reply;
- char buffer[STD_BUFFER_LEN];
- char Recipient[STD_BUFFER_LEN];
- long len;
- int SentCount;
- int status = 0;
-
- if( ! rfh )
- {
- SendText( s, SMTP_RESPONSE_NO_RECIPIENTS );
-
- TCPLog( LOG_WARNING, MAILERR_TEXT_NO_RECIPIENTS );
-
- return( 0 );
- }
-
- tfile = tmpnam( NULL );
- if( ! ( tfh = Open( tfile, MODE_NEWFILE ) ) )
- {
- MailError( MAILERR_NOTEMP, "Data" );
-
- return( 1 );
- }
-
- strcpy( buffer, GetDate() );
-
- FPrintf( tfh, "From %s %s", From, buffer );
-
- FPrintf( tfh, "Return-Path: <%s>\n", From );
-
- FPrintf( tfh, "Received: ") ;
- FPrintf( tfh, "from %s ", PeerName );
- FPrintf( tfh, "by %s with SMTP\n\tid AA%05ld; %s",
- LocalHost, 1, buffer );
-
-
- if( ! SendText(s, SMTP_RESPONSE_RECEIVING ) )
- {
- Close( tfh );
- return( 1 );
- }
-
- for(;;)
- {
- if( ( len = GetLine( s, buffer, rl ) ) < 0 )
- {
- MailError( 0, "Getting Mail Item Data" );
- Close( tfh );
- return( 1 );
- }
-
- line = buffer;
-
- if( line[0] == '.' )
- {
- if( line[1] == '\0' )
- {
- break;
- }
-
- line++;
- }
-
- FPrintf( tfh, "%s\n", line );
- }
-
- Flush( tfh );
-
- if( LogFileName )
- LogMail( tfh );
-
- Close( tfh );
-
- Seek( rfh, 0, OFFSET_BEGINNING );
-
- SentCount = 0;
-
- while( status == 0
- && ( FGets( rfh, Recipient, sizeof( Recipient ) - 1 ) > 0 ) )
- {
- StripCRLF( Recipient );
-
- sprintf( buffer, RMailCommand, tfile, Recipient );
- if( SystemTags( buffer, TAG_DONE ) == 0 )
- SentCount++;
- else
- MailError( MAILERR_NO_DELIVERY, Recipient );
- }
-
- if( SentCount )
- {
- DeleteFile( tfile );
-
- reply = SMTP_RESPONSE_OK;
- }
- else
- {
- MailError( MAILERR_NOT_DELIVERED, tfile );
-
- reply = SMTP_RESPONSE_NO_DELIVERY;
- }
-
- if( ! SendText(s, reply ) )
- return( 1 );
-
- return( 0 );
- }
-
- int ReadMailItem( int s, struct LineRead * rl )
- {
- char * From;
- char * cp;
- long len;
- char * buffer;
- char Recipient[STD_BUFFER_LEN] = "";
- char rfname[L_tmpnam];
- ULONG rfh = NULL;
- int status = 0;
-
- if( ! ( buffer = malloc( MAX_LINE_LENGTH ) ) )
- {
- return( 1 );
- }
-
- strcpy( buffer, rl->rl_Line + strlen( "MAIL FROM:" ) );
- if( buffer[0] == '<' )
- {
- if( cp = strchr( buffer, '>' ) )
- *cp = '\0';
- cp = buffer + 1;
- }
- else cp = buffer;
-
- StripCRLF( buffer );
-
- From = strdup( cp );
-
- if( ! SendText( s, SMTP_RESPONSE_OK ) )
- {
- free( buffer );
- free( From );
- return( 1 );
- }
-
- for(;;)
- {
- if( ( len = GetLine( s, buffer, rl ) ) < 0 )
- {
- status = 1;
- break;
- }
-
- if( isCommand( buffer, SMTP_COMMAND_RCPT ) )
- {
- char * reply;
-
- if( StoreRecipient( Recipient, buffer ) )
- {
- reply = SMTP_RESPONSE_OK;
-
- if( ! rfh )
- {
- if( ! ( rfh = Open( tmpnam( rfname ), MODE_NEWFILE ) ) )
- {
- MailError( MAILERR_NOTEMP, "Recipients" );
- status = 1;
- break;
- }
- }
-
- if( FPrintf( rfh, "%s\n", Recipient ) <= 0 )
- {
- MailError( MAILERR_TEMPWRITE, "Recipients (w)" );
- reply = SMTP_RESPONSE_NOWRITE_RECIPIENT;
- }
- }
- else
- reply = SMTP_RESPONSE_WHOTHEHECK;
-
- if( reply[0] != '2' )
- MailError( MAILERR_COMMAND_REJECT, buffer );
-
- if( ! SendText(s, reply ) )
- {
- status = 1;
- break;
- }
- }
- else if( isCommand( buffer, SMTP_COMMAND_RSET ) )
- {
- TCPLog( LOG_INFO, buffer );
-
- if( ! SendText(s, SMTP_RESPONSE_OK ) )
- {
- status = 1;
- break;
- }
-
- break;
- }
- else if( isCommand( buffer, SMTP_COMMAND_NOOP ) )
- {
- if( ! SendText(s, SMTP_RESPONSE_OK ) )
- {
- status = 1;
- break;
- }
- }
- else if( isCommand( buffer, SMTP_COMMAND_DATA ) )
- {
- if( ! rfh )
- {
- SendText( s, SMTP_RESPONSE_NO_RECIPIENTS );
-
- TCPLog( LOG_WARNING, MAILERR_TEXT_NO_RECIPIENTS );
-
- break;
- }
-
- Flush( rfh );
-
- status = PassMailToRecipients( s, rl, From, rfh );
-
- break;
- }
- else if( isCommand( buffer, SMTP_COMMAND_QUIT ) )
- {
- TCPLog( LOG_INFO, buffer );
-
- sprintf( buffer, SMTP_RESPONSE_CLOSING, LocalHost );
-
- SendText( s, buffer );
-
- return( 1 );
- }
- else
- {
- MailError( MAILERR_INVALID_COMMAND, buffer );
- status = 1;
- break;
- }
- }
-
- if( rfh )
- {
- Close( rfh );
- DeleteFile( rfname );
- }
-
- free( buffer );
- free( From );
- return( status );
- }
-
- int
- main(int argc, char **argv)
- {
- long len;
- int s = server_socket;
-
- #ifdef LOGGING
- #include <netinet/in.h>
- struct sockaddr_in sin;
- int sval;
- #endif
- char buffer[STD_BUFFER_LEN];
- struct LineRead * rl;
-
- struct RDArgs *Args;
- long ArgRes[ARGCOUNT];
- register int i = 0;
-
- for( i = 0; i < ARGCOUNT; ArgRes[i++] = NULL )
- ;
-
- /* Look at command line arguments. */
- #ifdef DEBUG
- TCPLog( LOG_DEBUG, "starting, %ld arguments", argc );
- if( argc )
- TCPLog( LOG_DEBUG, "1st argument:%s", argv[0] );
- #endif
-
- if(!(Args = ReadArgs((UBYTE *)SMTPD_TEMPLATE, ArgRes, NULL)))
- {
- MailError( MAILERR_INVALID_ARGUMENTS, NULL );
- return( 20 );
- }
-
- if( ArgRes[ARG_LOGFILE] )
- {
- LogFileName = strdup( (char*)(ArgRes[ARG_LOGFILE]) );
- #ifdef DEBUG
- TCPLog( LOG_DEBUG, "LogFile set to %s", LogFileName );
- #endif
- }
-
- if( ArgRes[ARG_RMAIL] )
- {
- RMailCommand = strdup( (char*)(ArgRes[ARG_RMAIL]) );
- #ifdef DEBUG
- TCPLog( LOG_DEBUG, "RMailCommand set to %s", RMailCommand );
- #endif
- }
-
- FreeArgs(Args);
-
- if ( s == -1 )
- {
- #ifdef STANDALONE
- struct sockaddr_in sin;
-
- s = serveraccept( "smtp", &sin );
- if ( s != -1 )
- {
- FPrintf( Stderr, "Accepted a connection from %s, port %ld\n",
- inet_ntoa( sin.sin_addr ), sin.sin_port );
- } else
- #endif
- return 1;
- }
-
- if( ! ( LocalHostAliases = gethostent( ) ) )
- return( 1 );
-
- LocalHost = LocalHostAliases[0];
-
- #ifdef LOGGING /* unused for now */
- sval = sizeof( sin );
- if ( getpeername( 0, &sin, &sval ) < 0 )
- fatal( "getpeername" );
- #endif
-
- if( ! ( rl = ( struct LineRead * )AllocMem( sizeof ( *rl ), 0 ) ) )
- {
- MailError( MAILERR_NO_MEMORY, NULL );
- return( 1 );
- }
-
- initLineRead( rl, s, /*LF_REQLF*/ 1, RL_BUFSIZE );
-
- sprintf( buffer, SMTP_RESPONSE_READY, LocalHost );
-
- if( ! SendText( s, buffer ) )
- return( 1 );
-
- if( ( ( len = GetLine( s, buffer, rl ) ) <= strlen( SMTP_COMMAND_HELO ) + 1 )
- || ( ! isCommand( buffer, SMTP_COMMAND_HELO ) ) )
- {
- MailError( MAILERR_EXPECTING_HELO, buffer );
- return( 1 );
- }
-
- TCPLog( LOG_INFO, buffer );
-
- strcpy( PeerName, buffer + strlen( SMTP_COMMAND_HELO ) + 1 );
-
- sprintf( buffer, SMTP_RESPONSE_OK_SUBS, LocalHost );
-
- if( ! SendText( s, buffer ) )
- return( 1 );
-
- for(;;)
- {
- if( ( len = GetLine( s, buffer, rl ) ) < 0 )
- {
- MailError( MAILERR_CONNECTION_LOST, NULL );
-
- return( 1 );
- }
-
- if( isCommand( buffer, SMTP_COMMAND_QUIT ) )
- {
- TCPLog( LOG_INFO, buffer );
-
- sprintf( buffer, SMTP_RESPONSE_CLOSING, LocalHost );
- if( ! SendText( s, buffer ) )
- {
- return( 1 );
- }
-
- break;
- }
- else if( isCommand( buffer, SMTP_COMMAND_NOOP ) )
- {
- if( ! SendText(s, SMTP_RESPONSE_OK ) )
- {
- return( 1 );
- }
- }
- else if( isCommand( buffer, SMTP_COMMAND_RSET ) )
- {
- if( ! SendText(s, SMTP_RESPONSE_OK ) )
- {
- return( 1 );
- }
- }
- else if( isCommand( buffer, SMTP_COMMAND_MAIL ) )
- {
- TCPLog( LOG_INFO, buffer );
-
- if( ReadMailItem( s, rl ) )
- return( 1 );
- }
- else
- {
- MailError( MAILERR_INVALID_COMMAND, buffer );
-
- if( ! SendText(s, SMTP_RESPONSE_PARDON ) )
- {
- return( 1 );
- }
- }
-
- }
-
- #if 0
- TCPLog( LOG_DEBUG, "Terminating normally" );
- #endif
-
- return 0;
- }
-