+++ /dev/null
-// vim: smarttab tabstop=8 shiftwidth=2 expandtab
-/********************************************************/
-/* */
-/* Implement all routine to manage SMTP low level */
-/* exchange. */
-/* */
-/********************************************************/
-#include <arpa/inet.h>
-#include <sys/types.h>
-
-#include <errno.h>
-#include <netdb.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <signal.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "subrou.h"
-#include "unieml.h"
-#include "devlog.h"
-#include "gestcp.h"
-#include "geseml.h"
-#include "lvleml.h"
-
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to free memory used by contact */
-/* */
-/********************************************************/
-static CONTYP *freecontact(CONTYP *contact)
-
-{
-#define OPEP "lvleml.c:freecontact"
-
-if (contact!=(CONTYP *)0) {
- contact->sqlptr=sql_closesql(contact->sqlptr);
- contact->logptr=log_closelog(contact->logptr);
- contact->recipients=(RCPTYP **)rou_freelist((void **)contact->recipients,
- (genfree_t)eml_freerecipient);
- contact->mailfrom=rou_freestr(contact->mailfrom);
- contact->cursesid=rou_freestr(contact->cursesid);
- contact->mainsesid=rou_freestr(contact->mainsesid);
- contact->fqdn=rou_freestr(contact->fqdn);
- contact->peername=rou_freestr(contact->peername);
- contact->peerip=rou_freestr(contact->peerip);
- contact->locserv=rou_freestr(contact->locserv);
- contact->locip=rou_freestr(contact->locip);
- contact->locname=rou_freestr(contact->locname);
- (void) free(contact);
- contact=(CONTYP *)0;
- }
-return contact;
-#undef OPEP
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to get the domain code */
-/* */
-/********************************************************/
-static _Bool setlocdom(CONTYP *contact,RCPTYP *rcpt)
-
-{
-#define OPEP "lvleml.c:setlocdom,"
-
-char done;
-int phase;
-_Bool proceed;
-
-done=true;
-phase=0;
-proceed=true;
-while (proceed==true) {
- //(void) rou_alert(0,"JMPDBG %s phase='%d' parm=<%s>",OPEP,phase,parameter);
- switch (phase) {
- case 0 : //is RCPT ok;
- if ((rcpt==(RCPTYP *)0)||(rcpt->domain==(char *)0)) {
- (void) rou_alert(0,"%s Recipient is NULL (Bug!?)",OPEP);
- done=false;
- phase=999;
- }
- break;
- case 1 : //check about local domain, TEMPORARY code
- int status;
-
- status=dns_is_domain_local(rcpt->domain,tls_get_bind_afn());
- switch (status) {
- case dns_nomx :
- done=false;
- break;
- case dns_local :
- rcpt->code='L'; //domain is local
- break;
- case dns_remote :
- rcpt->code='R'; //domain is remote
- break;
- default :
- (void) rou_alert(0,"%s Unexpected status='%d' for domain<%s>",
- OPEP,status,rcpt->domain);
- break;
- }
- break;
- default : //SAFE Guard
- proceed=false;
- break;
- }
- phase++;
- }
-return done;
-#undef OPEP
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to transmit a string to the remot peer*/
-/* */
-/********************************************************/
-static void transmit(CONTYP *contact,const char *fmt,...)
-
-{
-va_list args;
-char *line;
-
-va_start(args,fmt);
-line=(char *)0;
-if (rou_vasprintf(&line,fmt,args)>0) {
- (void) log_fprintlog(contact->logptr,true,"%s",line);
- (void) tcp_write(contact->socptr,line);
- (void) free(line);
- }
-va_end(args);
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to send the signon once the contact */
-/* with peer is detected. */
-/* */
-/********************************************************/
-static void signon(CONTYP *contact)
-
-{
-#define FMT "%d %s, ESMTP (%s) %s-%s; %s"
-
-if (contact!=(CONTYP *)0) {
- const char *mode;
- char signon[100];
-
- mode=soc_getstrmode(contact->socptr);
- (void) snprintf(signon,sizeof(signon),FMT,
- SIGNON,contact->locname,
- mode,
- appname,
- rou_getversion(),
- rou_ascsysstamp(time((time_t *)0)));
- (void) transmit(contact,"%s",signon);
- }
-#undef FMT
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to send ready link information */
-/* is a correct one */
-/* */
-/********************************************************/
-static void linkready(CONTYP *contact,_Bool suite)
-
-{
-const char *mode;
-char sepa;
-
-sepa=' ';
-if (suite==true)
- sepa='-';
-mode=soc_getstrmode(contact->socptr);
-(void) transmit(contact,"%d%c%s, link (%s) ready, your IP/FQDN=[%s/%s]",
- CMDOK,sepa,contact->locname,mode,
- contact->peerip,contact->peername);
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to add received information to */
-/* the email contents. */
-/* */
-/********************************************************/
-static _Bool addreceived(CONTYP *contact,FILE *data)
-
-{
-_Bool status;
-time_t curtime;
-int phase;
-_Bool proceed;
-
-status=true;
-curtime=time((time_t *)0);
-phase=0;
-proceed=true;
-while (proceed==true) {
- switch (phase) {
- case 0 : //Inserting the remote information
- (void) fprintf(data,"Received: from %s (IP=[%s], originator=<%s>)\n",
- contact->peername,contact->peerip,contact->mailfrom);
- break;
- case 1 : //Inserting the Receive information
- (void) fprintf(data,"\tby %s ([%s:%s]/%s-%s) with ESMTP\n",
- contact->locname,contact->locip,contact->locserv,
- appname,rou_getversion());
- break;
- case 2 : //Inserting TLS information
- if (soc_iscrypted(contact->socptr)==true) {
- (void) fprintf(data,"\t(%s)\n",soc_getcipherid(contact->socptr));
- }
- break;
- case 3 : //Inserting ID information
- (void) fprintf(data,"\tid <%s@%s>;\n",
- contact->cursesid,contact->locname);
- break;
- case 4 : //date information
- (void) fprintf(data,"\t%s\n",rou_ascsysstamp(curtime));
- break;
- default : //SAFE Guard
- proceed=false;
- break;
- }
- phase++;
- }
-return status;
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to check if helo or ehlo paratmeter */
-/* is a correct one */
-/* */
-/********************************************************/
-static _Bool isgoodfqdn(CONTYP *contact,char *parameter)
-
-{
-#define OPEP "lvleml.c:isgoodfqdn"
-
-_Bool done;
-int phase;
-_Bool proceed;
-
-done=false;
-phase=0;
-proceed=true;
-while (proceed==true) {
- //(void) rou_alert(0,"JMPDBG %s phase='%d' parm=<%s>",OPEP,phase,parameter);
- switch (phase) {
- case 0 : //checking if we have a parameter
- if ((parameter==(char *)0)||(strlen(parameter)==0))
- phase=999; //no parameter
- break;
- case 1 : //seems to be a good fqdn
- contact->fqdn=rou_freestr(contact->fqdn);
- contact->fqdn=strdup(parameter);
- done=true;
- break;
- default : //SAFE guard
- proceed=false;
- break;
- }
- phase++;
- }
-return done;
-#undef OPEP
-}
-/*
-\f
-*/
-/************************************************/
-/* */
-/* Procedure to set create the sessid count*/
-/* file. This file is used to keep track */
-/* of the number of the sessionid|(rcpt) */
-/* used to send email to all recipient. */
-/* */
-/************************************************/
-static _Bool setcountfile(CONTYP *contact)
-
-{
-#define OPEP "lvleml.c:setcountfile,"
-
-_Bool status;
-int num;
-FILE *qfile;
-int phase;
-_Bool proceed;
-
-status=false;
-num=0;
-qfile=(FILE *)0;
-phase=0;
-proceed=true;
-while (proceed==true) {
- switch (phase) {
- case 0 : //is contact good
- if (contact==(CONTYP *)0) {
- (void) rou_alert(0,"%s contact pointer is NULL (bug?)",OPEP);
- phase=999;
- }
- break;
- case 1 : //counting recipient number
- if ((num=rou_nbrlist((void **)contact->recipients))==0)
- phase=999; //No recipient!
- break;
- case 2 : //creating the count file
- if ((qfile=eml_createqfile(contact->cursesid,EXTCNT))==(FILE *)0) {
- (void) rou_alert(0,"%s Unable to open 'count' qfile <%s> (error=<%s>)",
- OPEP,contact->cursesid,strerror(errno));
- phase=999;
- }
- break;
- case 3 : //inserting number of receipient
- if (fprintf(qfile,"%d\n",num)<1) {
- (void) rou_alert(0,"%s Unable to set 'count' in qfile <%s> (error=<%s>)",
- OPEP,contact->cursesid,strerror(errno));
- (void) fclose(qfile);
- phase=999; //trouble trouble
- }
- break;
- case 4 : //closing count file
- if (fclose(qfile)!=0) {
- (void) rou_alert(0,"%s Unable to close qfile <%s> (error=<%s>)",
- OPEP,contact->cursesid,strerror(errno));
- phase=999; //trouble trouble
- }
- break;
- case 5 : //everything fine
- status=true;
- break;
- default : //SAFE Guard
- proceed=false;
- break;
- }
- phase++;
- }
-return status;
-
-
-#undef OPEP
-}
-/*
-\f
-*/
-/************************************************/
-/* */
-/* Procedure to set RCPT directive to */
-/* forward email to SMTP peers. */
-/* */
-/************************************************/
-static _Bool setdirectives(CONTYP *contact,char *ext)
-
-{
-#define OPEP "lvleml.c:setdirectives,"
-
-_Bool status;
-FILE *trans;
-int phase;
-_Bool proceed;
-
-status=false;
-trans=(FILE *)0;
-phase=0;
-proceed=true;
-while (proceed==true) {
- //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
- switch (phase) {
- case 0 : //Creating the file
- if ((trans=eml_createqfile(contact->cursesid,ext))==(FILE *)0)
- phase=999; //trouble trouble
- break;
- case 1 : //write data to trans file;
- if (eml_mktransfile(contact,trans)==false) {
- (void) eml_closeqfile(trans);
- phase=999; //Trouble trouble
- }
- break;
- case 2 : //closing transfile
- if (eml_closeqfile(trans)<0)
- phase=999; //Trouble trouble
- break;
- case 3 : //everythin fine
- status=true;
- break;
- default : //SAFE guard
- proceed=false;
- break;
- }
- phase++;
- }
-#undef OPEP
-return status;
-}
-/*
-\f
-*/
-/************************************************/
-/* */
-/* Procedure to send a simple SMTP ccommand*/
-/* (no need to have the response wording) */
-/* */
-/************************************************/
-static int simple_smtp_command(RMTTYP *rmt,char *fmt,...)
-
-{
-va_list args;
-char strloc[300];
-
-va_start(args,fmt);
-(void) vsnprintf(strloc,sizeof(strloc),fmt,args);
-va_end(args);
-return tcp_smtp_command(rmt,(char ***)0,strloc);
-}
-/*
-\f
-*/
-/************************************************/
-/* */
-/* Procedure to accept EMAIL contents from */
-/* SMTP peers. */
-/* Return true, if everything is fine */
-/* */
-/************************************************/
-static _Bool getdata(CONTYP *contact)
-
-{
-#define OPEP "lvleml.c:getdata,"
-#define EXTMP "tmp"
-
-_Bool done;
-FILE *queue;
-_Bool completed;
-int total;
-TIMESPEC start;
-int phase;
-_Bool proceed;
-
-done=false;
-queue=(FILE *)0;
-completed=false;
-total=0;
-phase=0;
-proceed=setdirectives(contact,EXTMP);
-while (proceed==true) {
- //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
- switch (phase) {
- case 0 : //checking if we have recipient
- if (rou_nbrlist((void **)contact->recipients)==0) {
- char *cmt;
-
- cmt="RCPT first. transaction protocol command out of sequence";
- (void) transmit(contact,"%d 5.5.0 %s",BADSEQ,cmt);
- done=true; //lets say DATA will be issued
- proceed=false; //No recipients
- }
- break;
- case 1 : //opening the queue email
- if ((queue=eml_createqfile(contact->cursesid,""))==(FILE *)0)
- phase=999; //trouble trouble
- break;
- case 2 : //adding received stamp to file
- if (addreceived(contact,queue)==false)
- phase=999; //trouble trouble
- break;
- case 3 : //sending 'go ahead' to remote
- (void) clock_gettime(CLOCK_REALTIME,&start);
- (void) transmit(contact,"%d 3.5.0 %s",
- DATAOK,"End data with <CR><LF>.<CR><LF>");
- break;
- case 4 : //get incoming line, detect 'single dot' as end
- while (completed==false) {
- int got;
- char *line;
-
- completed=false;
- got=tcp_getline(contact->socptr,WAITRMT,&line);
- if (got<0) { //data timeout
- phase=999; //trouble trouble
- break; //exiting loop
- }
- total+=got;
- if (strcmp(line,".")==0) {
- completed=true;
- }
- else {
- if ((strlen(line)>1)&&(line[0]=='.'))
- (void) memmove(line,line+1,strlen(line));
- (void) fprintf(queue,"%s\n",line);
- }
- line=rou_freestr(line);
- }
- break;
- case 5 : //got all data
- if (eml_closeqfile(queue)<0)
- phase=999; //Trouble trouble
- break;
- case 6 : //creating the count file
- if (setcountfile(contact)==false)
- phase=999; //Unable to create count file???
- break;
- case 7 : //renameing directive
- if (eml_renameqfile(contact->cursesid,EXTMP,EXTRANS)==false)
- phase=999; //Trouble trouble
- break;
- case 8 : //everything fine
- const char *fmt;
- unsigned int delta;
-
- total+=1023;
- total/=1024; //KBytes
- delta=rou_getdifftime(&start);
- fmt="%d 3.5.3 Message accepted for delivery (Session ID=<%s>)";
- (void) transmit(contact,fmt,CMDOK,contact->cursesid);
- fmt="(DATA stream received: %d Kbytes within %d.%03d seconds)";
- (void) log_fprintlog(contact->logptr,false,fmt,total,delta/1000,delta%1000);
- done=true;
- proceed=false; //task done
- break;
- default : //SAFE guard
- (void) transmit(contact,"%d 5.5.4 %s",
- DATRJC,"Server does not accept mail");
- proceed=false;
- break;
- }
- phase++;
- }
-return done;
-
-#undef EXTMP
-#undef OPEP
-}
-/*
-\f
-*/
-/************************************************/
-/* */
-/* Procedure to send an "HELO" message */
-/* if EHLO message is not accepted. */
-/* */
-/************************************************/
-static _Bool dohelo(CONTYP *contact,char *parameter)
-
-{
-#define OPEP "lvleml.c:dohelo"
-#define DETAIL "HELO argument is mandatory, closing connection"
-
-_Bool done;
-
-if ((done=isgoodfqdn(contact,parameter))==false)
- (void) transmit(contact,"%d 5.5.4 %s.",BADPAR,DETAIL);
-else
- (void) linkready(contact,false);
-return done;
-#undef DETAIL
-#undef OPEP
-}
-/*
-\f
-*/
-/************************************************/
-/* */
-/* Procedure to send an "HELO" message */
-/* if EHLO message is not accepted. */
-/* */
-/************************************************/
-static _Bool doehlo(CONTYP *contact,char *parameter)
-
-{
-static char *ehlostr[]= {
- "-STARTTLS",
- "-8BITMIME",
- "-ENHANCEDSTATUSCODES",
- "-AUTH PLAIN LOGIN",
- " HELP",
- (char *)0
- };
-
-#define OPEP "lvleml.c:doehlo"
-#define DETAIL "syntax error (domain part missing), closing connection"
-
-_Bool done;
-int strstart;
-int phase;
-_Bool proceed;
-
-done=false;
-strstart=0;
-phase=0;
-proceed=true;
-while (proceed==true) {
- //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
- switch (phase) {
- case 0 : //Do we have a parameter
- if ((done=isgoodfqdn(contact,parameter))==false) {
- (void) transmit(contact,"%d 5.5.4 %s.",BADPAR,DETAIL);
- phase=999; //Trouble trouble
- }
- break;
- case 1 : //thereis an FQDN
- (void) linkready(contact,true);
- (void) transmit(contact,"%d-SIZE %ld",CMDOK,MXMSIZE);
- if (soc_iscrypted(contact->socptr)==true)
- strstart++;
- for (int i=strstart;ehlostr[i]!=(char *)0;i++) {
- (void) transmit(contact,"%d%s",CMDOK,ehlostr[i]);
- }
- done=true;
- break;
- default : //SAFE guard
- proceed=false;
- break;
- }
- phase++;
- }
-return done;
-#undef DETAIL
-#undef OPEP
-}
-/*
-\f
-*/
-/************************************************/
-/* */
-/* Procedure to manage a "MAIL FROM:" */
-/* ommand from the SMTP client. */
-/* */
-/************************************************/
-static _Bool checkfrom(CONTYP *contact,char *mailfrom)
-
-{
-_Bool success;
-_Bool proceed;
-int phase;
-
-success=false;
-proceed=true;
-phase=0;
-while (proceed==true) {
- switch (phase) {
- case 0 : //do we have an originator
- if ((mailfrom==(char *)0)||(strlen(mailfrom)<3)) {
- (void) transmit(contact,"%d 5.5.0 <%s> originator not specified",
- BADPAR,mailfrom);
- phase=999; //no need to go further
- }
- break;
- case 1 : //do we have already a from
- if (contact->mailfrom!=(char *)0) {
- (void) transmit(contact,"%d 5.5.1 '%s' %s",
- BADPAR,contact->mailfrom,
- "was previously defined as originator"
- );
- phase=999; //no need to go further
- }
- break;
- case 2 : //check from format
- if ((mailfrom[0]!='<')||(mailfrom[strlen(mailfrom)-1]!='>')) {
- (void) transmit(contact,"%d 5.5.2 '%s' bad Format error",
- BADPAR,mailfrom);
- phase=999; //no need to go further
- }
- mailfrom[strlen(mailfrom)-1]='\000';
- (void) memmove(mailfrom,mailfrom+1,strlen(mailfrom));
- break;
- case 3 : //everything ok
- contact->mailfrom=strdup(mailfrom);
- (void) transmit(contact,"%d 2.1.3 %s.. sender ok",
- CMDOK,contact->mailfrom);
- break;
- default : //SAFE guard
- proceed=false;
- break;
- }
- phase++;
- }
-return success;
-}
-/*
-\f
-*/
-/************************************************/
-/* */
-/* Procedure to manage a "RCPT TO:" */
-/* command from the SMTP client. */
-/* */
-/************************************************/
-static _Bool checkto(CONTYP *contact,char *rcptto)
-
-{
-#define OPEP "lvleml.c:checkto,"
-_Bool success;
-RCPTYP *neu;
-const char *detail;
-char *report;
-_Bool proceed;
-int phase;
-
-success=false;
-neu=(RCPTYP *)0;
-detail="Address accepted";
-report=(char *)0;
-proceed=true;
-phase=0;
-while (proceed==true) {
- //(void) rou_alert(0,"JMPDBG %s phase='%d' rcptto=<%s>",OPEP,phase,rcptto);
- switch (phase) {
- case 0 : //do we have an originator
- if ((rcptto==(char *)0)||(strlen(rcptto)==0)) {
- (void) transmit(contact,"%d 5.6.0 <%s> recipient not specified",
- BADPAR,rcptto);
- phase=999; //no need to go further
- }
- break;
- case 1 : //check rcpt format
- if ((rcptto[0]!='<')||(rcptto[strlen(rcptto)-1]!='>')) {
- (void) transmit(contact,"%d 5.6.1 '%s' bad Format error",
- BADPAR,rcptto);
- phase=999; //no need to go further
- }
- rcptto[strlen(rcptto)-1]='\000';
- (void) memmove(rcptto,rcptto+1,strlen(rcptto));
- break;
- case 2 : //checking rcptto format
- neu=eml_isemailok(rcptto,&report);
- if (neu==(RCPTYP *)0) {
- (void) transmit(contact,"%d 5.6.2 %s",NOTEML,report);
- report=rou_freestr(report);
- phase=999; //no need to go further
- }
- break;
- case 3 : //Do we have a domain MX
- if (setlocdom(contact,neu)==false) {
- (void) transmit(contact,"%d 5.6.3 %s (domain=%s)",
- MISSMX,
- "No valid MX found for recipient domain name",
- neu->domain);
- neu=eml_freerecipient(neu); //free recipient
- phase=999; //no need to go further
- }
- break;
- case 4 : //Storing rcpt to
- if (eml_addrecipient(&(contact->recipients),neu)==false) {
- detail="duplicate recipients will be consolidated";
- neu=eml_freerecipient(neu);
- }
- break;
- case 5 : //everything ok
- (void) transmit(contact,"%d 2.6.4 %s",CMDOK,detail);
- success=true;
- break;
- default : //SAFE guard
- proceed=false;
- break;
- }
- phase++;
- }
-return success;
-#undef OPEP
-}
-/*
-\f
-*/
-/************************************************/
-/* */
-/* Procedure to reset the current session */
-/* */
-/************************************************/
-static _Bool doreset(CONTYP *contact,char *parameter)
-
-{
-#define LOCSEQ "2.1.0"
-
-(void) transmit(contact,"%d-%s flushed session %s",
- CMDOK,LOCSEQ,contact->cursesid);
-contact->numreset++;
-contact->recipients=(RCPTYP **)rou_freelist((void **)(contact->recipients),
- (genfree_t)eml_freerecipient);
-contact->mailfrom=rou_freestr(contact->mailfrom);
-contact->cursesid=rou_freestr(contact->cursesid);
-contact->cursesid=eml_getcursesid(contact->mainsesid,contact->numreset);
-(void) transmit(contact,"%d %s opening new session %s",
- CMDOK,LOCSEQ,contact->cursesid);
-return true;
-
-#undef LOCSEQ
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to to send ehlo (or helo) to remote */
-/* MX server. */
-/* Return true if succesfull */
-/* */
-/********************************************************/
-static _Bool greetings_rmt(RMTTYP *rmt)
-
-{
-#define OPEP "lvleml.c:greetings_rmt,"
-
-_Bool done;
-int phase;
-_Bool proceed;
-
-done=false;
-phase=0;
-proceed=true;
-while (proceed==true) {
- int rspcode;
-
- rspcode=ERRPROC;
- switch (phase) {
- case 0 : //Sending EHLO
- rspcode=simple_smtp_command(rmt,"EHLO %s",rmt->orgdomain);
- switch (rspcode) {
- case CMDOK : //So fare, so good
- break;
- default : //Trouble
- (void) rou_alert(0,"%s EHLO Remote <%s> unexpected answer code '%d'",
- OPEP,rmt->curmx,rspcode);
- phase++; //No STARTTLS available
- break;
- }
- break;
- case 1 : //Stating starttls
- phase=999; //No need to go futher
- rspcode=simple_smtp_command(rmt,"STARTTLS",rmt->orgdomain);
- switch (rspcode) {
- case SIGNON : //link is now encrypted
- done=soc_starttls(rmt->socptr,false);
- switch (done) {
- case true :
- (void) log_fprintlog(rmt->logptr,false,"crypted link is now set");
- break;
- case false :
- (void) log_fprintlog(rmt->logptr,false,"Unable to set crypted link");
- break;
- }
- phase=999; //link is now established
- break;
- default : //Trouble
- (void) rou_alert(0,"%s Unable to establish crypted link with <%s>",
- OPEP,rmt->curmx);
- break;
- }
- break;
- case 2 : //Sending HELO
- rspcode=simple_smtp_command(rmt,"HELO %s",rmt->orgdomain);
- switch (rspcode) {
- case CMDOK : //So fare, so good
- done=true;
- phase=999;
- break;
- default : //Trouble
- (void) rou_alert(0,"%s, HELO Remote <%s> unexpected answer code '%d'",
- OPEP,rmt->curmx,rspcode);
- break;
- }
- break;
- default : //SAFE Guard
- proceed=false;
- break;
- }
- phase++;
- }
-return done;
-
-#undef OPEP
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to connect to the remote SMTP server */
-/* */
-/********************************************************/
-static _Bool connect_to_mx(RMTTYP *rmt)
-
-{
-#define OPEP "lvleml.c:connect_to_mx,"
-
-_Bool done;
-int phase;
-int proceed;
-
-done=false;
-phase=0;
-proceed=true;
-while (proceed==true) {
- switch (phase) {
- case 0 : //do we have MX
- if (rmt->mxs==(MXTYP **)0) {
- (void) log_fprintlog(rmt->logptr,false,"NO MX found for domain <%s>",
- rmt->dstdomain);
- phase=999;
- }
- break;
- case 1 : //Trying to connect
- MXTYP **mxs;
- const char *srcip;
-
- mxs=rmt->mxs;
- srcip=(const char *)0;
- while (*mxs!=(MXTYP *)0) {
- rmt->curmx=*mxs;
- (void) rou_alert(0,"%s JMPDBG trying connect to <%s>",
- OPEP,rmt->curmx->mxname);
- rmt->socptr=soc_openfeedsock(pro_smtp,srcip,rmt->curmx->mxname,EMLPORT);
- if (rmt->socptr!=(SOCPTR *)0) {
- char cmt[100];
-
- (void) snprintf(cmt,sizeof(cmt),"Now Connected to MX <%s>",
- rmt->curmx->mxname);
- (void) log_fprintlog(rmt->logptr,false,cmt);
- break;
- }
- mxs++;
- }
- if (rmt->socptr==(SOCPTR *)0)
- phase=999;
- break;
- case 2 : //waiting for signon
- int res;
-
- res=tcp_get_smtp_reply(rmt,WAITRMT,(char ***)0);
- switch (res) {
- case SIGNON : //everything fine
- break;
- default : //not getting the right signon
- phase=999; //No need to go further
- break;
- }
- break;
- case 3 : //send greetings
- if ((done=greetings_rmt(rmt))==false)
- phase=999; //greeting not successful!
- break;
- case 4 : //send greetings
- break;
- default : //SAFE Guard
- proceed=false;
- break;
- }
- phase++;
- }
-return done;
-
-#undef OPEP
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to send the data to the remote server */
-/* */
-/********************************************************/
-static void senddata(RMTTYP *rmt,TRATYP **tosend,const char *sessid)
-
-{
-#define OPEP "lvleml.c:senddata,"
-
-int rspcode;
-int sent;
-TIMESPEC start;
-int phase;
-_Bool proceed;
-
-rspcode=0;
-sent=0;
-phase=0;
-proceed=true;
-(void) clock_gettime(CLOCK_REALTIME,&start);
-while (proceed==true) {
- switch (phase) {
- case 0 : //Sendig data request
- rspcode=simple_smtp_command(rmt,"DATA");
- switch (rspcode) {
- case DATAOK : //data accepted
- break;
- default : //Unexpected return code
- phase=999; //Not accepting data
- break;
- }
- break;
- case 1 : //sending session data
- sent=tcp_send_smtp_data(rmt,sessid);
- if (sent<0)
- phase=999; //No need to wait form response code
- break;
- case 2 : //send the text termination
- (void) tcp_write(rmt->socptr,".");
- rspcode= tcp_get_smtp_reply(rmt,WAITRMT,(char ***)0);
- break;
- case 3 : //sending session data
- const char *fmt;
- unsigned int delta;
-
- sent+=1023;
- sent/=1024; //Sent now in KByes
- fmt="Data stream Sent: %d Kbytes within %d.%03d seconds";
- delta=rou_getdifftime(&start);
- (void) log_fprintlog(rmt->logptr,false,fmt,sent,delta/1000,delta%1000);
- switch (rspcode) {
- case CMDOK :
- const char *cmt;
-
- cmt="Transmission completed successfully";
- (void) log_fprintlog(rmt->logptr,false,cmt);
- break;
- case MALABRT : //Data rejected
- break;
- default : //Unexpected return code
- break;
- }
- break;
- case 4 : //Updating sending
- TRATYP **dest;
-
- dest=tosend;
- while (*dest!=(TRATYP *)0) {
- switch ((*dest)->sendcode) {
- case CMDOK :
- if (rspcode==CMDOK) {
- (*dest)->code='C'; //Data was sent properly
- }
- break;
- case UKNUSER : //NO BREAK
- case BADPAR :
- break;
- default :
- (void) rou_alert(0,"%s sessid=<%s>, Unexpected code='%d' (Bug?)",
- OPEP,sessid,rspcode);
- break;
- }
- dest++;
- }
- break;
- default : //SAFE Guard
- proceed=false;
- break;
- }
- phase++;
- }
-#undef OPEP
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to send the whole email transaction */
-/* */
-/********************************************************/
-static void sending_email(char *orgdomain,char *dstdomain,char *sessid,TRATYP **tra)
-
-{
-#define OPEP "lvleml.c:sending_email,"
-
-time_t isnow;
-RMTTYP rmt;
-int tobesend;
-TRATYP **tosend;
-int phase;
-_Bool proceed;
-
-isnow=time((time_t *)0);
-(void) memset(&rmt,'\000',sizeof(rmt));
-rmt.mxs=dns_getmx(dstdomain);
-rmt.dstdomain=dstdomain;
-rmt.orgdomain=orgdomain;
-tosend=(TRATYP **)0;
-tobesend=0;
-phase=0;
-proceed=true;
-while (proceed==true) {
- //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase);
- switch (phase) {
- case 0 : //process completed?
- if ((*tra)==(TRATYP *)0)
- phase=999; //all scanning done
- break;
- case 1 : //collecting email to be sent
- rmt.logptr=log_closelog(rmt.logptr);
- while (*tra!=(TRATYP *)0) {
- if (strcmp((*tra)->sessid,sessid)!=0) {
- sessid=(*tra)->sessid;
- break;
- }
- if (((*tra)->date+(*tra)->delay)<=isnow) {
- switch ((*tra)->code) {
- case 'R' : //remote email (MX is remote)
- (void) eml_add_delay(isnow,*tra);
- tosend=(TRATYP **)rou_addlist((void **)tosend,(void *)(*tra));
- break;
- default : //Status is not to be send
- (void) rou_alert(0,"%s Directive is not! remote email (Bug?)",OPEP);
- break;
- }
- }
- tra++;
- }
- break;
- case 2 : //Checking if we have email to be sent
- if (tosend==(TRATYP **)0)
- phase=-1; //lets continue to see other email
- break;
- case 3 : { //checking if connection is open
- char cmt[100];
-
- (void) snprintf(cmt,sizeof(cmt),"session-id=%s",sessid);
- rmt.logptr=log_openlog(sessid,false,cmt);
- if (rmt.socptr!=(SOCPTR *)0) { //reset the connection
- phase++; //NO need to open connection
- }
- break;
- }
- case 4 : //Opening connection if not open
- if (connect_to_mx(&rmt)==false) {
- char cmt[100];
-
- (void) snprintf(cmt,sizeof(cmt),"Unable to contact ANY MX for domain <%s>",
- dstdomain);
- (void) log_fprintlog(rmt.logptr,false,cmt);
- if (tosend!=(TRATYP **)0) {
- TRATYP **ptr;
- char note[150];
-
- (void) snprintf(note,sizeof(note),"%d %s",NOANSWR,cmt);
- ptr=tosend;
- while (*ptr!=(TRATYP *)0) {
- (void) eml_freetra_resp(*ptr);
- (*ptr)->resp=(char **)rou_addlist((void **)(*ptr)->resp,
- (void *)strdup(note));
- ptr++;
- }
- (void) free(tosend);
- }
- phase=999; //No need to go further
- }
- break;
- case 5 : { //sending originator
- int rspcode;
-
- rspcode=simple_smtp_command(&rmt,"MAIL FROM: <%s>",(*tosend)->mailfrom);
- switch (rspcode) {
- case CMDOK : //originator accepted
- break;
- default : //unexpected answer
- (void) rou_alert(0,"%s JMPDBG unexpected response code='%d'",
- OPEP,rspcode);
- phase+=2; //not sending data
- break;
- }
- break;
- }
- case 6 : { //sending recipient list
- int rspcode;
- TRATYP **dest;
-
- tobesend=0;
- dest=tosend;
- while (*dest!=(TRATYP *)0) {
- char ***resp;
-
- (void) eml_freetra_resp(*dest);
- resp=&((*dest)->resp);
- rspcode=tcp_smtp_command(&rmt,resp,"RCPT TO: <%s>",(*dest)->rcptto);
- switch (rspcode) {
- case CMDOK : //originator accepted
- tobesend++;
- (*dest)->sendcode=rspcode;
- break;
- case UKNUSER : //recipient is unknown
- case NORELAY : //email no relayed
- (*dest)->code='W'; //Need to send a Warning
- (*dest)->sendcode=rspcode;
- break;
- default : //Not accepted recipient
- (void) rou_alert(0,"%s sessid=<%s>, unknwon code='%d'",
- OPEP,sessid,rspcode);
- (*dest)->code='C'; //completed (Temporary JMPDBG);
- (*dest)->sendcode=BADPAR;
- break;
- }
- dest++;
- }
- if (tobesend>=0)
- (void) senddata(&rmt,tosend,sessid);
- break;
- }
- case 8 : //cleaning recipient list
- (void) free(tosend);
- tosend=(TRATYP **)0;
- phase=0; //Lets see if we have other recipient
- break;
- default : //SAFE Guard
- rmt.logptr=log_closelog(rmt.logptr);
- proceed=false;
- break;
- }
- phase++;
- }
-rmt.mxs=dns_freemxlist(rmt.mxs);
-
-#undef OPEP
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to proceed with peer exchange */
-/* 5 return values: */
-/* 1 exiting via "quit" */
-/* 0 contact timeout */
-/* -1 signal received */
-/* -2 remote disconnected */
-/* -3 BUG! */
-/* */
-/********************************************************/
-PUBLIC int eml_docontact(CONTYP *contact)
-
-{
-#define OPEP "lvleml.c:eml_docontact"
-
-int status;
-int got;
-int delay;
-int penalty;
-_Bool proceed;
-
-status=1;
-got=0;
-delay=300; //5 minutes standard delay
-penalty=1;
-if (debug>1)
- delay/=10; //30 sec in debug mode
-proceed=true;
-(void) signon(contact);
-while (proceed==true) {
- char *line;
- CODTYP code;
-
- line=(char *)0;
- got=tcp_getline(contact->socptr,delay,&line);
- if (got<=0) { //timeout or trouble?
- char str[100];
-
- switch (got) {
- case 0 : //timeout
- (void) snprintf(str,sizeof(str),"No data from remote within %d sec",delay);
- break;
- case -1 : //signal received
- (void) snprintf(str,sizeof(str),"Signal Received");
- break;
- case -2 : //contact lost
- (void) snprintf(str,sizeof(str),"Lost link with remote");
- break;
- default :
- (void) snprintf(str,sizeof(str),"Unexpected status='%d' (Bug?)",status);
- status=-3;
- break;
- }
- (void) log_fprintlog(contact->logptr,false,"Contact terminated; "
- "condition=<%s>",str);
- //(void) rou_alert(0,"%s exit status='%d'",OPEP,status);
- break; //no need to go further
-
- }
- (void) log_fprintlog(contact->logptr,false,"%s",line);
- code=eml_getcode(line);
- switch (code) {
- case c_data : //Peer request to transfer email corps.
- proceed=getdata(contact);
- break;
- case c_helo : //HELO SMTP protocol
- proceed=dohelo(contact,line);
- break;
- case c_ehlo : //EHLO SMTP protocol
- proceed=doehlo(contact,line);
- break;
- case c_noop : //No Operation
- (void) transmit(contact,"%d 2.0.0 OK, %s",
- CMDOK,contact->mainsesid);
- break;
- case c_quit : //QUIT SMTP protocol
- (void) transmit(contact,"%d 2.0.0 Bye, closing connection CNT=%s",
- QUITOK,contact->mainsesid);
- status=1; //every thing fine
- proceed=false;
- break;
- case c_mail : //MAIL FROM: checking originator
- (void) checkfrom(contact,line);
- break;
- case c_rcpt : //Doing rpt scanning
- if (checkto(contact,line)==false) {
- (void) sleep(penalty); //relaxing bad guys
- penalty*=2;
- }
- break;
- case c_rset : //Doing session reset
- proceed=doreset(contact,line);
- break;
- case c_starttls : //EHLO start encrypted link in server mode
- switch (soc_starttls(contact->socptr,true)) {
- case true : //link now in TLS crypted mode
- (void) transmit(contact,"%d Link now encrypted (cipher=<%s>)",
- CMDOK,soc_get_cipher_name(contact->socptr));
- break;
- case false : //unable to establish link
- (void) transmit(contact,"%d 5.3.3 command starttls not successful",
- CMDBAD);
- status=-1;
- proceed=false;
- break;
- }
- break;
- case c_unknown : //unknown keyword
- (void) rou_alert(0,"SMTP Command <%s> from [%s] is unknown (config?)",
- line,contact->peerip);
- (void) transmit(contact,"%d-5.5.1 Unrecognized command, see RFC 5321",CMDBAD);
- (void) transmit(contact,"%d-5.5.1 https://www.rfc-editor.org",CMDBAD);
- (void) transmit(contact,"%d 5.5.1 session %s is still running",
- CMDBAD,contact->mainsesid);
- break;
- default :
- (void) rou_alert(0,"%s Unable to find entry for code='%d' (Bug?)",OPEP,code);
- (void) transmit(contact,"%d-5.5.1 Unrecognized command, see RFC 5321",CMDBAD);
- (void) transmit(contact,"%d 2.0.0 Bug!, closing connection Immediatly (%s)",
- QUITOK,contact->mainsesid);
- status=-1; //remote is a trouble maker
- status=-3;
- proceed=false;
- break;
- }
- line=rou_freestr(line);
- }
-return status;
-#undef OPEP
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to wait for a remote client. */
-/* return all reference to the established contact.*/
-/* */
-/********************************************************/
-PUBLIC CONTYP *eml_getcontact(SOCPTR *socptr,int pos)
-
-{
-#define OPEP "lvleml.c:eml_getcontact"
-#define MXCARIN 200 //maximun number of char
- //within carpile
-
-CONTYP *contact;
-int phase;
-_Bool proceed;
-
-contact=(CONTYP *)0;
-phase=0;
-proceed=true;
-while (proceed==true) {
- //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
- switch (phase){
- case 0 : //check for binding
- if (socptr==(SOCPTR *)0) {
- (void) rou_alert(0,"%s socket pointer is NULL (Bug!?)",OPEP);
- phase=999; //not going further
- }
- break;
- case 1 : //connecting to database
- contact=(CONTYP *)calloc(1,sizeof(CONTYP));
- contact->sqlptr=sql_opensql();
- if (contact->sqlptr==(SQLPTR *)0) {
- (void) rou_alert(0,"%s Unable to contact database",OPEP);
- (void) sleep(2);//delay to avoid avalanche
- (void) free(contact);
- contact=(CONTYP *)0;
- phase=999; //no contact possible.
- }
- break;
- case 2 : //waiting from contact
- if ((contact->socptr=soc_accept(socptr,pos))==(SOCPTR *)0) {
- (void) rou_alert(3,"%s Unable to open contact",OPEP);
- contact=freecontact(contact);
- phase=999; //no contact
- }
- break;
- case 3 : //Preparing contact
- contact->mainsesid=eml_getmainsesid();
- contact->cursesid=eml_getcursesid(contact->mainsesid,contact->numreset);
- contact->locname=soc_getaddrinfo(contact->socptr,true,true);
- contact->locip=soc_getaddrinfo(contact->socptr,true,false);
- if (contact->locip!=(char *)0) {
- char *ptr;
-
- //extracting service port number
- if ((ptr=strrchr(contact->locip,':'))!=(char *)0) {
- *ptr='\000';
- contact->locserv=strdup(ptr+1);
- }
- }
- contact->peername=soc_getaddrinfo(contact->socptr,false,true);
- contact->peerip=soc_getaddrinfo(contact->socptr,false,false);
- contact->logptr=log_openlog(contact->mainsesid,true,(const char *)0);
- (void) rou_alert(0,"Contact from peer <%s> to port <%s> started",
- contact->peerip,contact->locserv);
- break;
- case 4 : //check contact validity
- if ((contact->locname==(char *)0)||(contact->peerip==(char *)0)) {
- (void) rou_alert(0,"%s Unable to establish contact entities",OPEP);
- contact=freecontact(contact);
- phase=999; //no identity
- }
- break;
- case 5 : //contact is good, then sending a signon
- (void) log_fprintlog(contact->logptr,false,"opening connection CNT=%s",
- contact->mainsesid);
- break;
- default : //SAFE guard
- proceed=false;
- break;
- }
- phase++;
- }
-return contact;
-#undef MXCARIN
-#undef OPEP
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to wait for a remote client. */
-/* return the frreed memory contact (NULL pointer) */
-/* */
-/********************************************************/
-PUBLIC CONTYP *eml_dropcontact(CONTYP *contact)
-
-{
-#define OPEP "lvleml.c:eml_dropcontact"
-
-int phase;
-_Bool proceed;
-
-phase=0;
-proceed=true;
-while (proceed==true) {
- //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
- switch (phase){
- case 0 : //check for binding
- if (contact==(CONTYP *)0) {
- (void) rou_alert(0,"%s Contact pointer is NULL (Bug!?)",OPEP);
- phase=999; //not going further
- }
- break;
- case 1 : //properly closing remote contact
- (void) rou_alert(0,"Contact from peer <%s> to port <%s> terminated",
- contact->peerip,contact->locserv);
- contact->socptr=soc_release(contact->socptr);
- //(void) kill(getppid(),SIGCHLD);
- //(void) rou_alert(0,"%s JMPDBG signal SIGCHLD sent to='%d'",OPEP,getppid());
- break;
- case 2 : //freeing contact memory
- contact=freecontact(contact);
- break;
- default : //SAFE guard
- proceed=false;
- break;
- }
- phase++;
- }
-return contact;
-#undef OPEP
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to generate transfile contents */
-/* return all reference to contact. */
-/* */
-/********************************************************/
-PUBLIC _Bool eml_mktransfile(CONTYP *contact,FILE *qfile)
-
-{
-#define OPEP "lvleml.c:eml_mktrans"
-
-_Bool status;
-
-status=true;
-if ((contact!=(CONTYP *)0)&&(contact->recipients!=(RCPTYP **)0)) {
- RCPTYP **ptr;
- TRATYP **tralist;
- time_t isnow;
-
- ptr=contact->recipients;
- tralist=(TRATYP **)0;
- isnow=time((time_t *)0);
- while (*ptr!=(RCPTYP *)0) {
- TRATYP *tra;
- char data[300];
-
-
- (void) snprintf(data,sizeof(data),"%s@%s",(*ptr)->userid,(*ptr)->domain);
- tra=(TRATYP *)calloc(1,sizeof(TRATYP));
- tra->code=(*ptr)->code;
- tra->date=isnow;
- tra->delay=0;
- tra->sessid=strdup(contact->cursesid);
- tra->mailfrom=strdup(contact->mailfrom);
- tra->rcptto=strdup(data);
- tralist=(TRATYP **)rou_addlist((void **)tralist,(void *)tra);
- ptr++;
- }
- (void) eml_dump_list_tra(qfile,tralist);
- tralist=(TRATYP **)rou_freelist((void **)tralist,(genfree_t)eml_freetra);
- }
-return status;
-#undef OPEP
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to store local email (MX local) within*/
-/* the serveur right directory. */
-/* */
-/********************************************************/
-PUBLIC void eml_local_email(TRATYP **tra)
-
-{
-#define OPEP "lvleml.c:eml_local_email,"
-
-time_t isnow;
-
-isnow=time((time_t *)0);
-while (*tra!=(TRATYP *)0) {
- if (((*tra)->date+(*tra)->delay)>isnow)
- continue;
- (void) eml_add_delay(isnow,*tra);
- switch ((*tra)->code) {
- case 'L' : //local email (MX is local)
- (*tra)->code='C';
- if (eml_store_email(*tra)==false) {
- (*tra)->code='L'; //Will try to deliver later one
- (void) rou_alert(0,"%s Unable to deliver local email <%s> to <%s>",
- OPEP,(*tra)->sessid,(*tra)->rcptto);
- }
- break;
- default : //Unexpected local? email??
- (void) rou_alert(0,"%s Directive is not! local email (Bug?)",OPEP);
- (void) rou_alert(0,"%s TRA=<%cs %lu %04u %s %s %s",OPEP,
- (*tra)->code,
- (*tra)->date,
- (*tra)->delay,
- (*tra)->sessid,
- (*tra)->mailfrom,
- (*tra)->rcptto);
- break;
- }
- tra++;
- }
-#undef OPEP
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to send email to remote recipient */
-/* */
-/********************************************************/
-PUBLIC void eml_remote_email(TRATYP **tra)
-
-{
-#define OPEP "lvleml.c:eml_remote_email,"
-
-char *orgdomain;
-char *dstdomain;
-char *sessid;
-int phase;
-_Bool proceed;
-
-orgdomain=(char *)0;
-dstdomain=(char *)0;
-sessid=(char *)0;
-phase=0;
-proceed=true;
-while (proceed==true) {
- switch (phase) {
- case 0 : //Check if we have tra
- if (tra==(TRATYP **)0) {
- (void) rou_alert(0,"%s Transaction pointer is NULL (Bug?)",OPEP);
- phase=999;
- }
- break;
- case 1 : //set originator domain
- if ((orgdomain=strrchr((*tra)->mailfrom,'@'))!=(char *)0)
- orgdomain++;
- if (orgdomain==(char *)0) {
- (void) rou_alert(0,"%s Originator address <%s> without domain? (Bug?)",
- OPEP,(*tra)->mailfrom);
- phase=999;
- }
- break;
- case 2 : //detecting remote domain
- if ((dstdomain=strrchr((*tra)->rcptto,'@'))!=(char *)0)
- dstdomain++;
- if (dstdomain==(char *)0) {
- (void) rou_alert(0,"%s Recipient address <%s> without domain? (Bug?)",
- OPEP,(*tra)->rcptto);
- phase=999;
- }
- break;
- case 3 : //checking if we have a session ID
- sessid=(*tra)->sessid;
- if (sessid==(char *)0) {
- (void) rou_alert(0,"%s Session ID is NULL (Bug?)",OPEP);
- sessid="0000-0000";
- }
- break;
- case 4 : //sending the whole transaction to remote server
- (void) sending_email(orgdomain,dstdomain,sessid,tra);
- break;
- default : //SAFE Guard
- proceed=false;
- break;
- }
- phase++;
- }
-
-#undef OPEP
-}
-/*
-^L
-*/
-/********************************************************/
-/* */
-/* Procedure to rebounce an email which was NOT */
-/* deliverable. */
-/* */
-/********************************************************/
-PUBLIC void eml_rebounce_email(TRATYP *tra)
-
-{
-char *tmp;
-
-(void) rou_alert(0,"JMPDG rebounce");
-tmp=tra->mailfrom;
-tra->mailfrom=tra->rcptto;
-tra->mailfrom=tmp;
-tra->code='L';
-}
-