+// 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 <ctype.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 "subafn.h"
+#include "subrou.h"
+#include "subcnv.h"
+#include "unidig.h"
+#include "unieml.h"
+#include "uniprc.h"
+#include "devlog.h"
+#include "gestcp.h"
+#include "gessql.h"
+#include "geseml.h"
+#include "lvleml.h"
+
+//env variable to define the list of relayable
+#define RELAYS "RELAYABLE"
+
+static const char *cry="(crypted link is now set in '%s' mode, security level='%d')";
+
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to update the termination condition */
+/* within contact. */
+/* current session. */
+/* */
+/********************************************************/
+static void setterminator(CONTYP *contact,const char *condition)
+
+{
+if (contact!=(CONTYP *)0) {
+ contact->termend=rou_freestr(contact->termend);
+ contact->termend=strdup(condition);
+ }
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to update database and free the */
+/* current session. */
+/* */
+/********************************************************/
+static void freesessid(CONTYP *contact)
+
+{
+if (contact->session!=(SESTYP *)0) {
+ if (contact->mailfrom!=(char *)0) {
+ contact->session->sfrom=strdup(contact->mailfrom);
+ (void) sql_mngses(contact->sqlptr,sql_update,&(contact->session));
+ }
+ contact->session=sql_freeses(contact->session);
+ }
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to manage curent SMTP session data */
+/* within contact. */
+/* */
+/********************************************************/
+static void getsessid(CONTYP *contact)
+
+{
+if (contact!=(CONTYP *)0) {
+ char *newsid;
+
+ newsid=eml_getcursesid(contact->mainsesid,contact->numreset);
+ contact->session=(SESTYP *)calloc(1,sizeof(SESTYP));
+ contact->session->sessid=newsid;
+ (void) sql_mngses(contact->sqlptr,sql_insert,&(contact->session));
+ }
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to free memory used by contact */
+/* */
+/********************************************************/
+static CONTYP *freecontact(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:freecontact"
+
+if (contact!=(CONTYP *)0) {
+ long debut;
+ long fin;
+
+ debut=0;
+ fin=0;
+ (void) freesessid(contact);
+ contact->logptr=log_closelog(contact->logptr,&debut,&fin);
+ if (contact->mainsesid!=(char *)0) {
+ (void) sql_addevent(contact->sqlptr,contact->mainsesid,debut,fin);
+ contact->mainsesid=rou_freestr(contact->mainsesid);
+ }
+ contact->sqlptr=sql_closesql(contact->sqlptr);
+ contact->termend=rou_freestr(contact->termend);
+ contact->relayok=(AFNTYP **)rou_freelist((void **)contact->relayok,
+ (genfree_t)afn_freeipnum);
+ contact->recipients=(RCPTYP **)rou_freelist((void **)contact->recipients,
+ (genfree_t)eml_freerecipient);
+ contact->authname=rou_freestr(contact->authname);
+ contact->mailfrom=rou_freestr(contact->mailfrom);
+ 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->localafns=(AFNTYP **)rou_freelist((void **)contact->localafns,
+ (genfree_t)afn_freeipnum);
+ 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,contact->localafns);
+ 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 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) eml_transmit(contact,true,"%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;
+_Bool flush;
+char sepa;
+
+sepa=' ';
+flush=true;
+if (suite==true) {
+ flush=false;
+ sepa='-';
+ }
+mode=soc_getstrmode(contact->socptr);
+(void) eml_transmit(contact,flush,"%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;
+const char *esmtp;
+int phase;
+_Bool proceed;
+
+status=true;
+esmtp="ESMTP";
+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
+ if (contact->privilege==rel_authentic)
+ esmtp="ESMTPA";
+ (void) fprintf(data,"\tby %s ([%s:%s]/%s-%s) with %s\n",
+ contact->locname,
+ contact->locip,
+ contact->locserv,
+ appname,rou_getversion(),
+ esmtp);
+ break;
+ case 2 : //Inserting TLS information
+ if (soc_iscrypted(contact->socptr)==true) {
+ char *cipherid;
+
+ cipherid=soc_getcipherid(contact->socptr);
+ if (cipherid!=(char *)0)
+ (void) fprintf(data,"\t(%s)\n",cipherid);
+ cipherid=rou_freestr(cipherid);
+ }
+ break;
+ case 3 : //Inserting ID information
+ (void) fprintf(data,"\tid <%s@%s>;\n",
+ contact->session->sessid,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 remote IP credit */
+/* */
+/********************************************************/
+static int checkcredit(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:checkcredit,"
+
+int status;
+SRVTYP *srv;
+int phase;
+_Bool proceed;
+
+status=FAILED;
+srv=(SRVTYP *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //reading remote server information
+ if (sql_mngremote(contact->sqlptr,sql_select,contact->peerip,&srv)==false) {
+ (void) rou_alert(0,"%s Unable to find server data for remote <%s> (BUg?)",
+ OPEP,contact->peerip);
+ phase=999;
+ }
+ break;
+ case 1 : //checking credential
+ if (srv->links>1) {
+ status=ALREADY;
+ (void) eml_note(contact,NULL,"%d 4.5.6 already connected",status);
+ (void) eml_transmit(contact,true,"%d 4.5.6 already connected",status);
+ phase=999; //To many server connected
+ }
+ break;
+ case 2 : //checking if black listed (low credit)
+ if (srv->credit<0) {
+ char *cmt;
+ const char *ninfo;
+
+ cmt=srv->listing;
+ ninfo="%d-4.5.7 Originator server IP [%s] black listed <%s>";
+ if (cmt==(char *)0)
+ cmt="credit too low";
+ (void) log_fprintlog(contact->logptr,false,"(Remote %s[%s] credit='%d' %s)",
+ contact->peername,
+ contact->peerip,
+ srv->credit,"too low");
+ status=BLCKLST;
+ (void) eml_note(contact,NULL,ninfo,status,contact->peerip,cmt);
+ (void) eml_transmit(contact,true,ninfo,status,contact->peerip,cmt);
+ (void) setterminator(contact,"Remote server credit is too low");
+ phase=999; //To many server connected
+ }
+ break;
+ case 3 : //remote server is "credible"
+ status=CMDOK;
+ break;
+ default : //SAFE Guard, freeing memory
+ srv=sql_freesrv(srv);
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return status;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to split a plain authentication string*/
+/* Match with the user provided. */
+/* */
+/********************************************************/
+static void split_auth_plain(char *sequence,char *data[3])
+
+{
+char *locdata[3];
+char *dup;
+char *ptr;
+int count;
+
+(void) memset(locdata,'\000',sizeof(locdata));
+dup=strdup(sequence);
+ptr=dup;
+for (count=0;(count<3)&&(ptr!=(char *)0);count++) {
+ char *mark;
+
+ if ((mark=strstr(ptr,IOBNULL))!=(char *)0) {
+ *mark='\000';
+ mark+=strlen(IOBNULL);
+ }
+ locdata[count]=strdup(ptr);
+ ptr=mark;
+ }
+(void) memmove(data,locdata,sizeof(locdata));
+dup=rou_freestr(dup);
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to check if the password submitted */
+/* Match with the user provided. */
+/* */
+/********************************************************/
+static _Bool checklogin(CONTYP *contact,char **rmtpass,char *sequence)
+
+{
+#define OPEP "lvleml.c:checklogin,"
+
+_Bool isok;
+char *data[3];
+char *givenhash;
+int phase;
+_Bool proceed;
+
+isok=false;
+(void) memset(data,'\000',sizeof(data));
+givenhash=(char *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //make sure we have data
+ (void) split_auth_plain(sequence,data);
+ if ((data[1]==(char *)0)||(data[2]==(char *)0)) {
+ (void) rou_alert(0,"%s missing data from <%s> (Bug?)",OPEP,sequence);
+ phase=999; //No need to go further
+ }
+ break;
+ case 1 : //do we have valide data?
+ if ((strlen(data[1])==0)||(strlen(data[2])==0)) {
+ (void) rou_alert(0,"%s data[1]=<%s> or data[2]=<%s> missing (Remote Bug?)",
+ OPEP,data[1],data[2]);
+ phase=999; //No need to go further
+ }
+ break;
+ case 2 : { //checking user password
+ USRTYP *usr;
+
+ usr=(USRTYP *)0;
+ contact->authname=rou_freestr(contact->authname);
+ contact->authname=strdup(data[1]);
+ *rmtpass=strdup(data[2]);
+ if (sql_mngusr(contact->sqlptr,sql_select,data[1],&usr)==true) {
+ char *givenpass;;
+
+ givenpass=data[2];
+ if (usr->password==(char *)0) {
+ (void) rou_alert(0,"%s usr=<%s> password empty, assigning one",
+ OPEP,data[1]);
+ usr->password=cnv_getrndstr(10);
+ }
+ if (usr->password[0]=='$') {
+ char *ptr;
+ char idsalt[100];
+
+ (void) memset(idsalt,'\000',sizeof(idsalt));
+ (void) strncpy(idsalt,usr->password,sizeof(idsalt)-1);
+ if ((ptr=strrchr(idsalt,'$'))!=(char *)0) {
+ ptr++;
+ *ptr='\000';
+ }
+ if ((ptr=crypt(givenpass,idsalt))==(char *)0) {
+ (void) rou_alert(0,"%s Trouble to crypt (Bug?) givenpass=<%s> "
+ "salt=<%s> (error=<%s>)",
+ OPEP,givenpass,idsalt,strerror(errno));
+ ptr=data[2]; //trying to overcome
+ }
+ givenpass=ptr;
+ }
+ isok=(strcmp(givenpass,usr->password)==0);
+ usr=sql_freeusr(usr);
+ }
+ }
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+givenhash=rou_freestr(givenhash);
+for (int i=0;i<3;i++)
+ data[i]=rou_freestr(data[i]);
+return isok;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to manage authentication in "plain" */
+/* mode, return "decoded", NULL if not extracted */
+/* */
+/********************************************************/
+static void get_auth_plain(CONTYP *contact,char *received,char **rmtpass)
+
+{
+#define OPEP "lvleml.c:get_auth_plain,"
+
+char *decoded;
+
+*rmtpass=(char *)0;
+decoded=(char *)0;
+if ((received==(char *)0)||(strlen(received)==0)) {
+ char *line;
+ int got;
+
+ line=(char *)0;
+ (void) eml_transmit(contact,true,"%d 5.7.1 Please provide auth sequence",SENDB64);
+ got=tcp_getline(contact->socptr,contact->delay,&line);
+ if (got>0) {
+ (void) log_fprintlog(contact->logptr,false,"%s",line);
+ decoded=cnv_getb64(line);
+ line=rou_freestr(line);
+ }
+ }
+else
+ decoded=cnv_getb64(received);
+if (decoded!=(char *)0) {
+ if (checklogin(contact,rmtpass,decoded)==true) {
+ contact->credit+=2;
+ contact->privilege=rel_authentic;
+ }
+ decoded=rou_freestr(decoded);
+ }
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to manage authentication in "login" */
+/* mode, return goodpass true if successful */
+/* */
+/********************************************************/
+static void get_auth_login(CONTYP *contact,char **rmtpass)
+
+{
+static char *logdat[]={"VXNlcm5hbWU6", //Username: in B64
+ "UGFzc3dvcmQ6", //Password: in B64
+ (char *)0};
+char local[200];
+
+(void) memset(local,'\000',sizeof(local));
+for (int i=0;i<2;i++) {
+ char *line;
+ char *ptr;
+ int got;
+
+ (void) strcat(local,IOBNULL);
+ (void) eml_transmit(contact,true,"%d %s",SENDB64,logdat[i]);
+ got=tcp_getline(contact->socptr,contact->delay,&line);
+ if (got<=0) {
+ const char *ninfo="%d 5.7.2 auth sequence missing";
+
+ (void) strcpy(local,"");
+ (void) eml_note(contact,NULL,ninfo,UKNUSER);
+ (void) eml_transmit(contact,true,ninfo,UKNUSER);
+ break; //exiting from loop
+ }
+ (void) log_fprintlog(contact->logptr,false,"%s",line);
+ if ((ptr=cnv_getb64(line))!=(char *)0) {
+ (void) strncat(local,ptr,(sizeof(local)-1)-strlen(ptr));
+ ptr=rou_freestr(ptr);
+ }
+ line=rou_freestr(line);
+ }
+if (strlen(local)>0) {
+ if (checklogin(contact,rmtpass,local)==true) {
+ contact->credit+=2;
+ contact->privilege=rel_authentic;
+ }
+ }
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to manage authentication in */
+/* digest-md5 mode. */
+/* Return a builded "decoded" string from */
+/* the exchange with the remote sereur */
+/* see RFC 2831. */
+/* */
+/* */
+/********************************************************/
+static void get_auth_digest_md5(CONTYP *contact,char **rmtpass)
+
+{
+#define OPEP "lvleml.c:get_auth_digest_md5,"
+
+char *challenge;
+RSPTYP *resp;
+char answer[300];
+char hash[40];
+int phase;
+_Bool proceed;
+
+*rmtpass=strdup("$1(a_digest_md5)");
+challenge=(char *)0;
+resp=(RSPTYP *)0;
+(void) memset(answer,'\000',sizeof(answer));
+(void) memset(hash,'\000',sizeof(hash));
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //assign the reaml challeng
+ break;
+ case 1 : //Building the challenge sequence
+ if ((challenge=dig_getchallenge())==(char *)0) {
+ (void) rou_alert(0,"%s Unable to get challenge sequence (Bug!)",OPEP);
+ phase=999;
+ }
+ break;
+ case 2 : { //sending challenge to remote
+ char *b64;
+
+ b64=cnv_setb64(challenge);
+ (void) eml_transmit(contact,true,"%d %s",SENDB64,b64);
+ b64=rou_freestr(b64);
+ }
+ break;
+ case 3 : { //getting the challenge answer
+ char *line;
+
+ if (tcp_getline(contact->socptr,contact->delay,&line)>0) {
+ //if a clear text QUIT is received because of deep trouble
+ if (strcasecmp(line,"QUIT")!=0) {
+ char *res;
+
+ res=cnv_getb64(line);
+ (void) rou_alert(2,"%s received=<%s>",OPEP,res);
+ (void) snprintf(answer,sizeof(answer),"%s",res);
+ res=rou_freestr(res);
+ }
+ line=rou_freestr(line);
+ }
+ if (strlen(answer)==0)
+ phase=999; //no need to go further
+ }
+ break;
+ case 4 : //Parsing the answer
+ if ((resp=dig_parseresp(answer))==(RSPTYP *)0)
+ phase=999; //Unable to parse answer
+ break;
+ case 5 : //checking if we have a user name
+ if (resp->username==(char *)0) {
+ (void) rou_alert(0,"%s No username in challenge answer!",OPEP);
+ phase=999; //Unable to parse answer
+ }
+ break;
+ case 6 : { //getting the user name and password
+ USRTYP *usr;
+
+ contact->authname=rou_freestr(contact->authname);
+ contact->authname=strdup(resp->username);
+ if (sql_mngusr(contact->sqlptr,sql_select,resp->username,&usr)==true) {
+ if (usr->hash!=(char *)0)
+ (void) strncpy(hash,usr->hash,sizeof(hash)-1);
+ usr=sql_freeusr(usr);
+ }
+ if (strlen(hash)==0) {
+ (void) rou_alert(0,"%s user <%s> missing hash value!",OPEP,resp->username);
+ phase=999; //No need to go further
+ }
+ }
+ break;
+ case 7 : { //sending the rspauth sequence.
+ char *HAS;
+ char *rspauth;
+ char *b64;
+
+ if ((HAS=dig_hashresp(resp,"",hash))==(char *)0) {
+ (void) rou_alert(0,"%s Unable to get the hash rspauth (Bug!)",OPEP);
+ break;
+ }
+ (void) rou_asprintf(&rspauth,"rspauth=%s",HAS);
+ b64=cnv_setb64(rspauth);
+ (void) eml_transmit(contact,true,"%d %s",SENDB64,b64);
+ b64=rou_freestr(b64);
+ rspauth=rou_freestr(rspauth);
+ HAS=rou_freestr(HAS);
+ }
+ break;
+ case 8 : { //waiting client to send an empty line
+ char *line;
+ int count;
+
+ line=(char *)0;
+ count=tcp_getline(contact->socptr,contact->delay,&line);
+ if (count<0)
+ (void) rou_alert(0,"%s delay expired to get remote empty line (network?)",
+ OPEP);
+ line=rou_freestr(line); //EMPTY Line!
+ }
+ break;
+ case 9 : { //comparing result.
+ char *HA0;
+
+ if ((HA0=dig_hashresp(resp,"AUTHENTICATE",hash))==(char *)0) {
+ (void) rou_alert(0,"%s Unable to get the hash response (Bug!)",OPEP);
+ break;
+ }
+ if (strcmp(HA0,resp->response)==0) {
+ contact->credit+=3; //very good authentication
+ contact->privilege=rel_authentic;
+ }
+ HA0=rou_freestr(HA0);
+ }
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+resp=dig_freeresp(resp);
+challenge=rou_freestr(challenge);
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to extract authentication info. */
+/* return a login sequence as */
+/* 'username password' if successful */
+/* NULL if unable to extract login */
+/* */
+/********************************************************/
+static _Bool getauth(CONTYP *contact,char *buffer)
+
+{
+#define OPEP "lvleml.c:getauth,"
+#define DISP "---- "
+
+static char *vocloc[]={"PLAIN","LOGIN","DIGEST-MD5",(char *)0};
+
+int code;
+char *rmtpass;
+char local[200];
+int phase;
+_Bool proceed;
+
+code=-1;
+rmtpass=(char *)0;
+(void) memset(local,'\000',sizeof(memset));
+phase=0;
+proceed=true;
+while (proceed==true) {
+ (void) rou_dbglive(9,OPEP,"phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //empty phase
+ break;
+ case 1 : //check buffer
+ if ((buffer==(char *)0)||(strlen(buffer)==0)) {
+ const char *ninfo="%d 5.7.1 Missing auth type";
+
+ (void) eml_note(contact,NULL,ninfo,UKNUSER);
+ (void) eml_transmit(contact,true,ninfo,UKNUSER);
+ phase=999; //No need to go further
+ }
+ break;
+ case 2 : //check the authentication type
+ (void) strncpy(local,buffer,sizeof(local)-1);
+ for (code=0;vocloc[code]!=(char *)0;code++) {
+ if (strncasecmp(local,vocloc[code],strlen(vocloc[code]))==0) {
+ register int taille;
+ register char *ptr;
+
+ taille=strlen(vocloc[code]);
+ ptr=local+taille+1;
+ (void) memcpy(local,ptr,strlen(ptr)+1);
+ break;
+ }
+ }
+ if (vocloc[code]==(char *)0) {
+ static char *cmt="bad authentication type";
+
+ (void) rou_alert(0,"%s auth type <%s> unknown (Bug?)",OPEP,local);
+ (void) eml_note(contact,NULL,"%d %s",BADPAR,cmt);
+ (void) eml_transmit(contact,true,"%d 5.7.2 %s",BADPAR,cmt);
+ (void) setterminator(contact,cmt);
+ phase=999; //Trouble Trouble
+ }
+ break;
+ case 3 : //getting "username password" accorind login type
+ switch (code) {
+ case 0 : //AUTH PLAIN
+ if (soc_iscrypted(contact->socptr)==true)
+ (void) get_auth_plain(contact,local,&rmtpass);
+ else {
+ static char *cmt="Unsafe PLAIN auth mode";
+
+ contact->credit-=2;
+ (void) eml_note(contact,NULL,"%d %s",FAILED,cmt);
+ (void) eml_transmit(contact,true,"%d 5.7.3 %s",FAILED,cmt);
+ (void) setterminator(contact,cmt);
+ phase=999;
+ }
+ break;
+ case 1 : //AUTH LOGIN
+ if (soc_iscrypted(contact->socptr)==true)
+ (void) get_auth_login(contact,&rmtpass);
+ else {
+ static char *cmt="Unsafe LOGIN auth mode";
+
+ contact->credit-=2;
+ (void) eml_note(contact,NULL,"%d %s",FAILED,cmt);
+ (void) eml_transmit(contact,true,"%d 5.7.3 %s",FAILED,cmt);
+ (void) setterminator(contact,cmt);
+ phase=999;
+ }
+ break;
+ case 2 : //AUTH DIGEST-MD5
+ (void) get_auth_digest_md5(contact,&rmtpass);
+ break;
+ default : { //not yet implemented
+ static char *cmt="Unexpected auth mode";
+
+ (void) rou_alert(0,"%s auth type <%d> not yet implemented (Bug?!)",
+ OPEP,code);
+ (void) eml_note(contact,NULL,"%d 5.7.5 %s",FAILED,cmt);
+ (void) eml_transmit(contact,true,"%d 5.7.5 %s",FAILED,cmt);
+ (void) setterminator(contact,cmt);
+ phase=999;
+ }
+ break;
+ }
+ break;
+ case 4 : { //do we have a decoded sequence??
+ char *fmt;
+ char *auth;
+
+ fmt=DISP"Auth accepted for user=<%s>";
+ auth=contact->authname;
+ if (contact->privilege!=rel_authentic) {
+ fmt=DISP"Auth Rejected status='%d' for user=<%s> pass=<%s>";
+ (void) log_fprintlog(contact->logptr,true,fmt,BADAUTH,auth,rmtpass);
+ (void) sleep(2);
+ (void) eml_note(contact,NULL,"%d user <%s> pass=<%s> bad authentication",
+ BADAUTH,auth,rmtpass);
+ (void) eml_transmit(contact,true,"%d 5.7.4 wrong authentication",BADAUTH);
+ (void) setterminator(contact,"Authentication failure");
+ contact->credit-=1;
+ phase=999;
+ }
+ else {
+ (void) log_fprintlog(contact->logptr,true,fmt,auth);
+ (void) eml_note(contact,NULL,"%d 5.7.5 authentication successful",IDOK);
+ (void) eml_transmit(contact,true,"%d 5.7.5 authentication successful",IDOK);
+ contact->credit+=2;
+ }
+ }
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+rmtpass=rou_freestr(rmtpass);
+return (contact->privilege==rel_authentic);
+
+#undef DISP
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* checking if local recipient is acceptable. */
+/* */
+/********************************************************/
+static _Bool is_user_good(CONTYP *contact,char *rcptto)
+
+{
+_Bool isok;
+USRTYP *usr;
+int phase;
+_Bool proceed;
+
+isok=false;
+usr=(USRTYP *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //is user a local user
+ if ((sql_mngusr(contact->sqlptr,sql_select,rcptto,&usr))==false) {
+ (void) eml_note(contact,rcptto,"%d 5.6.0 <%s> unknown user",
+ UKNUSER,rcptto);
+ (void) eml_transmit(contact,true,"%d 5.6.0 <%s> unknown user",
+ UKNUSER,rcptto);
+ phase=999; //No user found in database
+ }
+ break;
+ case 1 : //are we in relaying mode
+ switch (contact->privilege) {
+ case rel_authentic :
+ case rel_isrelay : //everything fine
+ isok=true; //we accepte "internal user"
+ phase=999; //no need to check lock and spf
+ break;
+ default :
+ break;
+ }
+ break;
+ case 2 : //is user lock?
+ if (usr->lock==1) {
+ (void) eml_note(contact,rcptto,"%d 5.6.1 <%s> account lock",
+ EXPIRED,rcptto);
+ (void) eml_transmit(contact,true,"%d 5.6.1 <%s> account lock",
+ EXPIRED,rcptto);
+ phase=999; //No user found in database
+ }
+ break;
+ case 3 : //check is origin is SPF OK
+ switch (contact->fromspf) {
+ case spf_neutral : //'?' status
+ case spf_pass : //good SPF
+ isok=true;
+ break;
+ case spf_fail : //Bad SPF
+ (void) eml_note(contact,rcptto,"%d 5.6.6 %s from IP=[%s]",
+ FAILED,"Relaying not allowed",
+ contact->peerip);
+ (void) eml_transmit(contact,rcptto,"%d 5.6.6 %s from IP=[%s]",
+ FAILED,"Relaying not allowed",
+ contact->peerip);
+ break;
+ case spf_softfail : //Bad SPF
+ (void) eml_note(contact,rcptto,"%d 5.6.7 %s from IP=[%s]",
+ FAILED,"SPF soft fail not allowed",
+ contact->peerip);
+ (void) eml_transmit(contact,rcptto,"%d 5.6.7 %s from IP=[%s]",
+ FAILED,"SPF soft fail not allowed",
+ contact->peerip);
+ break;
+ default : //trouble trouble
+ (void) eml_note(contact,rcptto,"%d 5.6.8 %s (<%s> SPF unknown)",
+ FAILED,
+ "Originator domain BAD SPF definition",
+ contact->mailfrom);
+ (void) eml_transmit(contact,true,"%d 5.6.8 %s (<%s> SPF unknown)",
+ FAILED,
+ "Originator domain BAD SPF definition",
+ contact->mailfrom);
+ break;
+ }
+ break;
+ default : //SAFE Guard
+ usr=sql_freeusr(usr);
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return isok;
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* checking if remote recipient is relayable. */
+/* */
+/********************************************************/
+static _Bool is_remote_good(CONTYP *contact,RCPTYP *rmtusr)
+
+{
+#define OPEP "lvleml.c:is_remote_good,"
+
+_Bool remotegood;
+const char *cmt;
+int phase;
+_Bool proceed;
+
+remotegood=false;
+cmt=(const char *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : { //Is there an MX for the user remote domain
+ MXTYP **mxs;
+
+ cmt="No MX nor IP for";
+ if ((mxs=dns_getmx(rmtusr->domain))!=(MXTYP **)0) {
+ for (int i=0;mxs[i]!=(MXTYP *)0;i++) {
+ if (mxs[i]->mxip!=(char **)0) {
+ phase++; //No need to check for domain IP
+ break;
+ }
+ }
+ mxs=dns_freemxlist(mxs);
+ }
+ }
+ break;
+ case 1 : { //is the domain with an IP address
+ char **iplist;
+
+ if ((iplist=dns_get_ip_list(rmtusr->domain))==(char **)0)
+ phase=999; //not even an IP for domain
+ iplist=(char **)rou_freelist((void **)iplist,(genfree_t)rou_freestr);
+ }
+ break;
+ case 2 : //is connection acceptable
+ switch (contact->privilege) {
+ case rel_authentic :
+ case rel_isrelay : //everything fine
+ break;
+ case rel_plain :
+ cmt="No relay accepted";
+ contact->credit-=2; //Trying to abuse server
+ phase=999; //not relayable
+ break;
+ default :
+ cmt="Unchecked status";
+ phase=999; //not relayable
+ break;
+ }
+ break;
+ case 3 : //so it a good remote
+ remotegood=true;
+ break;
+ default : //SAFE Guard
+ if (remotegood==false) {
+ char *rcptto;
+
+ (void) rou_asprintf(&rcptto,"%s@%s",rmtusr->userid,rmtusr->domain);
+ (void) eml_note(contact,rcptto,"%d 2.8.0 %s for domain <%s>",
+ NORELAY,cmt,rmtusr->domain);
+ (void) eml_transmit(contact,true,"%d 2.8.0 %s for domain <%s>",
+ NORELAY,cmt,rmtusr->domain);
+ rcptto=rou_freestr(rcptto);
+ }
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return remotegood;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to check if helo or ehlo parameter */
+/* is a correct one */
+/* */
+/********************************************************/
+static _Bool isgoodfqdn(CONTYP *contact,char *parameter)
+
+{
+#define OPEP "lvleml.c:isgoodfqdn"
+#define HELL " !@#$%^&*()=+[]{}|\\:;'\"<>,?"
+
+_Bool good;
+int phase;
+_Bool proceed;
+
+good=false;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ (void) rou_dbglive(7,OPEP,"phase='%d' parm=<%s>",phase,parameter);
+ switch (phase) {
+ case 0 : //is parameter starting with '.'
+ if ((parameter[0]=='.')||(parameter[0]=='-'))
+ phase=999; //no allowed to start with dot or dash
+ break;
+ case 1 : //do we have '..' somewehre
+ if ((strstr(parameter,"..")!=(char *)0)||
+ (strstr(parameter,"-.")!=(char *)0)||
+ (strstr(parameter,".-")!=(char *)0))
+ phase=999; //no allowed to start with dot
+ break;
+ case 2 : //check if char set is allowed
+ if (strpbrk(parameter,HELL)!=(char *)0)
+ phase=999; //no a good charset
+ break;
+ case 3 : //checking if parameter is only ascii
+ int taille;
+
+ taille=strlen(parameter);
+ for (int i=0;i<taille;i++) {
+ if (isascii(parameter[i])==false) {
+ phase=999; //non ascii charatere
+ break;
+ }
+ }
+ break;
+ case 4 : //seems to be a good fqdn
+ good=true;
+ contact->fqdn=rou_freestr(contact->fqdn);
+ contact->fqdn=strdup(parameter);
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return good;
+
+#undef HELL
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to check if helo or ehlo parameter */
+/* is an acceptable one */
+/* */
+/********************************************************/
+static _Bool isgoodhelo(CONTYP *contact,char *parameter)
+
+{
+#define OPEP "lvleml.c:isgoodhelo"
+#define DETAIL "HELO argument is incorrect, closing connection"
+
+_Bool good;
+int last;
+char original[100];
+int phase;
+_Bool proceed;
+
+good=false;
+last=0;
+(void) memset(original,'\000',sizeof(original));
+phase=0;
+proceed=true;
+while (proceed==true) {
+ (void) rou_dbglive(7,OPEP,"phase='%d' domain=<%s>",phase,parameter);
+ switch (phase) {
+ case 0 : //checking if we have a parameter
+ if (parameter==(char *)0) {
+ (void) rou_alert(0,"%s sesid=<%s> fqdn is missing!",
+ OPEP,contact->mainsesid);
+ phase=999; //no parameter
+ }
+ break;
+ case 1 : //strip possible space at the end pf parameter
+ (void) strncpy(original,parameter,sizeof(original)-1);
+ last=strlen(parameter)-1;
+ while ((parameter[last]==' ')&&(last>=0)) {
+ parameter[last]='\000';
+ last--;
+ }
+ break;
+ case 2 : //cannot start with '.'
+ if (parameter[0]=='.') {
+ (void) rou_alert(0,"%s sesid=<%s> wrong fqdn=<%s>"
+ OPEP,contact->mainsesid,parameter);
+ phase=999; //wrong parameter
+ }
+ break;
+ case 3 : //check if we have an fqdn
+ if ((good=isgoodfqdn(contact,parameter))==true)
+ phase=999;
+ break;
+ case 4 : //is it an enclosed IP
+ if ((parameter[0]=='[')&&(parameter[last]==']')) {
+ parameter[last]='\000';
+ (void) memmove(parameter,parameter+1,last);
+ last--;
+ last--;
+ if (strlen(parameter)==0) {
+ phase=999;
+ }
+ }
+ break;
+ case 5 : //checking if it is starting or endig with dot
+ if ((parameter[0]=='.')||(parameter[last]=='.'))
+ phase=999; //yes but not acceptable
+ break;
+ case 6 : //checking fi double dot inside
+ if (strstr(parameter,"..")!=(char *)0)
+ phase=999; //yes but not acceptable
+ break;
+ case 7 : //are all character good
+ if (strlen(parameter)==strspn(parameter,".0123456789"))
+ good=true;
+ break;
+ default : //SAFE guard
+ if (good==false) {
+ (void) eml_note(contact,NULL,"%d 5.5.4 %s.",BADPAR,DETAIL);
+ (void) eml_transmit(contact,true,"%d 5.5.4 %s.",BADPAR,DETAIL);
+ }
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return good;
+
+#undef DETAIL
+#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)||(contact->session==(SESTYP *)0)) {
+ (void) rou_alert(0,"%s contact pointer or session 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->session->sessid,EXTCNT))==(FILE *)0) {
+ (void) rou_alert(0,"%s Unable to open 'count' qfile <%s> (error=<%s>)",
+ OPEP,contact->session->sessid,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->session->sessid,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->session->sessid,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->session->sessid,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 */
+/* */
+/************************************************/
+//NOTE
+//MAIL FROM <sender> [BODY=7BIT|BODY=8BITMIME] [SIZE=number_of_bytes]
+static _Bool getdata(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:getdata,"
+#define EXTMP "tmp"
+
+_Bool done;
+FILE *queue;
+_Bool inheader;
+_Bool completed;
+u_long total;
+TIMESPEC start;
+int phase;
+_Bool proceed;
+
+done=false;
+queue=(FILE *)0;
+inheader=true;
+completed=false;
+total=0;
+phase=0;
+proceed=true;
+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) eml_transmit(contact,true,"%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->session->sessid,""))==(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) eml_transmit(contact,true,"%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 (inheader==true) {
+ (void) eml_scan_headerline(contact->session,line);
+ if (strlen(line)==0)
+ inheader=false;
+ }
+ 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
+ contact->session->taille=total;
+ (void) setdirectives(contact,EXTMP);
+ if (eml_renameqfile(contact->session->sessid,EXTMP,EXTRANS)==false)
+ phase=999; //Trouble trouble
+ break;
+ case 8 : //everything fine
+ const char *fmt;
+ unsigned int delta;
+ char duration[40];
+
+ total+=1023;
+ total/=1024; //KBytes
+ delta=rou_getdifftime(&start);
+ (void) snprintf(duration,sizeof(duration),"%d.%03d",delta/1000,delta%1000);
+ contact->session->duration=strdup(duration);;
+ fmt="%d-3.5.3 Session ID=<%s>";
+ (void) eml_transmit(contact,false,fmt,CMDOK,contact->session->sessid);
+ fmt="%d-3.5.3 data stream received: %d Kbytes within %s seconds)";
+ (void) eml_transmit(contact,false,fmt,CMDOK,total,duration);
+ fmt="%d 3.5.3 Message accepted for delivery";
+ (void) eml_transmit(contact,true,fmt,CMDOK,contact->session->sessid);
+ done=true;
+ proceed=false; //task done
+ break;
+ default : //SAFE guard
+ (void) eml_transmit(contact,true,"%d 5.5.4 Server does not accept mail",
+ DATRJC);
+ 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"
+
+_Bool done;
+
+if ((done=isgoodhelo(contact,parameter))==false) {
+ (void) setterminator(contact,"HELO parameter missing");
+ contact->credit-=2;
+ }
+else
+ (void) linkready(contact,false);
+return done;
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to send an "HELO" message */
+/* if EHLO message is not accepted. */
+/* */
+/************************************************/
+static _Bool doehlo(CONTYP *contact,char *parameter)
+
+{
+static struct {
+ int display; //0 ->always, 1-->plain 2-->crypted
+ char *str; //the message to display
+ }ehlo[]={
+ {1,"STARTTLS"},
+ {1,"AUTH DIGEST-MD5"},
+ {2,"AUTH PLAIN LOGIN DIGEST-MD5"},
+ {0,"SIZE "MXMSIZE},
+ {0,"8BITMIME"},
+ {0,"ENHANCEDSTATUSCODES"},
+ {0,(char *)0}
+ };
+
+#define OPEP "lvleml.c:doehlo"
+
+_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=isgoodhelo(contact,parameter))==false) {
+ (void) setterminator(contact,"HELO parameter incorrect");
+ contact->credit-=2; //penalty
+ phase=999; //Trouble trouble
+ }
+ break;
+ case 1 : //thereis an FQDN
+ (void) linkready(contact,true);
+ if (soc_iscrypted(contact->socptr)==true)
+ strstart++;
+ for (int i=strstart;ehlo[i].str!=(char *)0;i++) {
+ char space;
+
+ space='-';
+ if (ehlo[i+1].str==(char *)0)
+ space=' ';
+ switch (ehlo[i].display) {
+ case 0 : //always display
+ break;
+ case 1 : //display on plain only
+ if (soc_iscrypted(contact->socptr)==true)
+ continue;
+ break;
+ case 2 : //display on crypted only
+ if (soc_iscrypted(contact->socptr)==false)
+ continue;
+ break;
+ }
+ (void) eml_transmit(contact,false,"%d%c%s",CMDOK,space,ehlo[i].str);
+ }
+ (void) eml_transmit(contact,true,"");
+ done=true;
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return done;
+#undef DETAIL
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to manage a "ORGN:" */
+/* command from the SMTP client. */
+/* Purpose of this command is to simulate */
+/* (or overide) the IP remote client. */
+/* */
+/* NOTE: Only compiled in debug mode. */
+/* */
+/************************************************/
+#ifdef MODEDEBUG
+
+static _Bool set_orgn_rmtip(CONTYP *contact,char *rmtip)
+
+{
+#define OPEP "lvleml.c:set_orgn_rmtip,"
+
+_Bool isok;
+AFNTYP *afn;
+int phase;
+_Bool proceed;
+
+isok=false;
+afn=(AFNTYP *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //is the new IP valide
+ if ((afn=afn_getoneipnum(rmtip))==(AFNTYP *)0) {
+ (void) rou_alert(0,"%s <%s> is not a good ip (Testing?)",OPEP,rmtip);
+ phase=999;
+ }
+ break;
+ case 1 : //we have good ip, lets disconnect previous
+ if (sql_newconnect(contact->sqlptr,contact->peerip,-1)<0) {
+ (void) rou_alert(0,"%s Unable to update database remotes table (system?)"
+ OPEP);
+ phase=999;
+ }
+ break;
+ case 2 : { //ready to change IP'
+ char *reverse;
+
+ contact->peerip=rou_freestr(contact->peerip);
+ contact->peerip=strdup(rmtip);
+ reverse=afn_reversipnum(afn);
+ contact->peername=rou_freestr(contact->peername);
+ contact->peername=dns_get_reverse_addr(reverse);
+ reverse=rou_freestr(reverse);
+ }
+ break;
+ case 3 : //adjust privilege according new IP
+ switch (contact->privilege) {
+ case rel_authentic :
+ break;
+ case rel_isrelay : //need to force rel_plain
+ contact->privilege=rel_plain;
+ //NO BREAK;
+ case rel_plain :
+ if (afn_is_ip_relayable(contact->peerip,contact->relayok)==true)
+ contact->privilege=rel_isrelay; //IP is relayable
+ break;
+ default :
+ (void) rou_alert(0,"%s unexpected privilege '%d' (Bug?)",
+ OPEP,contact->privilege);
+ phase=999;
+ break;
+ }
+ break;
+ case 4 : //let update links
+ if (sql_newconnect(contact->sqlptr,rmtip,1)!=1) {
+ static char *end;
+
+ end="You have another connection still in progress";
+ (void) rou_alert(0,"%s <%s> Too many '%d' links! (Testing?)",
+ OPEP,rmtip,sql_newconnect(contact->sqlptr,rmtip,0));
+ (void) eml_transmit(contact,true,"%d contact denied <%s>",NOTNOW,end);
+ contact->termend=rou_freestr(contact->termend);
+ contact->termend=strdup(end);
+ contact->credit=-1; //small penalty
+ (void) sleep(1); //To avoid avalanche
+ (void) sql_newconnect(contact->sqlptr,rmtip,-1);
+ phase++; //connection rejected
+ }
+ break;
+ case 5 : //everything is now fine
+ (void) signon(contact);
+ isok=true;
+ break;
+ default : //SAFE Guard
+ afn=afn_freeipnum(afn);
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return isok;
+
+#undef OPEP
+}
+#endif
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to manage a "MAIL FROM:" */
+/* ommand from the SMTP client. */
+/* */
+/************************************************/
+static _Bool checkfrom(CONTYP *contact,char *mailfrom)
+
+{
+#define OPEP "lvleml.c:checkfrom"
+
+_Bool success;
+char *strsize;
+int status;
+int phase;
+_Bool proceed;
+
+success=false;
+strsize=(char *)0;
+status=CMDOK;
+proceed=true;
+phase=0;
+while (proceed==true) {
+ (void) rou_dbglive(9,OPEP,"Phase='%d'",phase);
+ switch (phase) {
+ case 0 : //do we have an originator
+ if ((mailfrom==(char *)0)||(strlen(mailfrom)<3)) {
+ (void) eml_transmit(contact,true,"%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) eml_transmit(contact,true,"%d 5.5.1 '%s' %s",
+ BADPAR,contact->mailfrom,
+ "was previously defined as originator");
+ phase=999; //no need to go further
+ }
+ break;
+ case 2 : //do we have SIZE= component
+ if ((strsize=strchr(mailfrom,' '))!=(char *)0) {
+ while (*strsize==' ') {
+ *strsize='\000';
+ strsize++;
+ }
+ //JMPDBG need to check size
+ }
+ break;
+ case 3 : //check from format
+ if ((mailfrom[0]!='<')||(mailfrom[strlen(mailfrom)-1]!='>')) {
+ (void) eml_transmit(contact,true,"%d 5.5.3 '%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 4 : //check if contact authenticated
+ switch (contact->privilege) {
+ case rel_isrelay : //Remote IP was already relaying
+ //NO BREAK;
+ case rel_authentic : //User was authenticated
+ break;
+ case rel_plain : //remote IP is plain
+ if ((status=checkcredit(contact))!=CMDOK) {
+ contact->credit=-1; //found bad guy.
+ (void) eml_transmit(contact,true,"%d 5.5.4 Closing connection",status);
+ phase=999; //bad credit not need to go further
+ }
+ break;
+ default :
+ (void) rou_alert(0,"%s unexpected priviliged='%d' (Bug?)",
+ OPEP,contact->privilege);
+ (void) eml_transmit(contact,true,"%d 5.5.5 Closing connection",FAILED);
+ phase=999; //bad credit not need to go further
+ break;
+ }
+ break;
+ case 5 : //Checking if the SPF is good from the originator
+ contact->fromspf=spf_getspf(mailfrom,contact->peerip);
+ (void) rou_dbglive(5,OPEP,"found SPF for <%s/[%s]> to be <%s>",
+ mailfrom,contact->peerip,
+ spf_spfASCII(contact->fromspf));
+ break;
+ case 6 : //everything ok
+ contact->mailfrom=strdup(mailfrom);
+ (void) eml_transmit(contact,true,"%d 2.1.3 %s sender ok",
+ CMDOK,contact->mailfrom);
+ success=true;
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return success;
+
+#undef OPEP
+}
+/*
+\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 will be processed";
+report=(char *)0;
+proceed=true;
+phase=0;
+while (proceed==true) {
+ (void) rou_dbglive(9,OPEP,"phase='%d' rcptto=<%s>",phase,rcptto);
+ switch (phase) {
+ case 0 : //do we have a mailfrom
+ if ((contact->mailfrom==(char *)0)||(strlen(contact->mailfrom)==0)) {
+ (void) eml_transmit(contact,true,"%d 5.6.0 Bad sequence of commands.",
+ BADSEQ);
+ phase=999; //no need to go further
+ }
+ break;
+ case 1 : //do we have an originator
+ if ((rcptto==(char *)0)||(strlen(rcptto)==0)) {
+ (void) eml_note(contact,rcptto,"%d 5.6.1 recipient not specified",BADPAR);
+ (void) eml_transmit(contact,true,"%d 5.6.1 recipient not specified",BADPAR);
+ phase=999; //no need to go further
+ }
+ break;
+ case 2 : //check rcpt format
+ if ((rcptto[0]!='<')||(rcptto[strlen(rcptto)-1]!='>')) {
+ (void) eml_note(contact,rcptto,"%d 5.6.2 '%s' bad Format error",
+ BADPAR,rcptto);
+ (void) eml_transmit(contact,true,"%d 5.6.2 '%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 3 : //checking rcptto format
+ neu=eml_isemailok(rcptto,&report);
+ if (neu==(RCPTYP *)0) {
+ (void) eml_note(contact,rcptto,"%d 5.6.3 %s",NOTEML,report);
+ (void) eml_transmit(contact,true,"%d 5.6.3 %s",NOTEML,report);
+ report=rou_freestr(report);
+ phase=999; //no need to go further
+ }
+ break;
+ case 4 : //Do we have a domain MX
+ if (setlocdom(contact,neu)==false) {
+ (void) eml_note(contact,rcptto,"%d 5.6.4 %s (domain=%s)",
+ MISSMX,
+ "No valid MX found for recipient"
+ " domain name",
+ neu->domain);
+ (void) eml_transmit(contact,true,"%d 5.6.4 %s (domain=%s)",
+ MISSMX,
+ "No valid MX found for recipient"
+ " domain name",
+ neu->domain);
+ phase=999; //no need to go further
+ }
+ break;
+ case 5 : //if the local user acceptable
+ switch (neu->code) {
+ case 'L' : //local user/domain
+ if (is_user_good(contact,rcptto)==false)
+ phase=999;
+ break;
+ case 'R' : //remote user/domain
+ if (is_remote_good(contact,neu)==false)
+ phase=999;
+ break;
+ default :
+ (void) eml_transmit(contact,true," 5.6.5 %s (domain=%s,code='%c')",
+ FAILED,
+ "system error with domain status",
+ neu->domain,neu->code);
+ phase=999; //no need to go further
+ break;
+ }
+ break;
+ case 6 : //Storing rcpt to
+ if (eml_addrecipient(&(contact->recipients),neu)==false) {
+ detail="duplicate recipients will be consolidated";
+ neu=eml_freerecipient(neu);
+ }
+ break;
+ case 7 : //everything ok
+ (void) eml_note(contact,rcptto,"%d 5.6.7 %s <%s>",CMDOK,detail,rcptto);
+ (void) eml_transmit(contact,true,"%d 5.6.7 %s <%s>",CMDOK,detail,rcptto);
+ success=true;
+ break;
+ default : //SAFE guard
+ if (success==false)
+ neu=eml_freerecipient(neu);
+ 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) eml_transmit(contact,true,"%d-%s flushed session %s",
+ CMDOK,LOCSEQ,contact->session->sessid);
+(void) freesessid(contact);
+contact->numreset++;
+(void) getsessid(contact);
+contact->recipients=(RCPTYP **)rou_freelist((void **)(contact->recipients),
+ (genfree_t)eml_freerecipient);
+contact->mailfrom=rou_freestr(contact->mailfrom);
+(void) eml_transmit(contact,true,"%d %s opening new session %s",
+ CMDOK,LOCSEQ,contact->session->sessid);
+return true;
+
+#undef LOCSEQ
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send a confirmation ehlo on the */
+/* crypted link. */
+/* */
+/********************************************************/
+_Bool sendehlo(RMTTYP *rmt)
+
+{
+_Bool done;
+
+done=false;
+return done;
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure 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 : //Starting 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 : {
+ int level;
+
+ level=soc_get_sec_level(rmt->socptr);
+ (void) log_fprintlog(rmt->logptr,false,cry,"client",level);
+ (void) usleep(10000); //10 ms delay
+ rspcode=simple_smtp_command(rmt,"EHLO %s",rmt->orgdomain);
+ switch (rspcode) {
+ case CMDOK :
+ break;
+ default :
+ (void) log_fprintlog(rmt->logptr,false,"No server confirmation");
+ done=false;
+ break;
+ }
+ }
+ 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 close the remote connection with MX*/
+/* */
+/********************************************************/
+static RMTTYP *close_mx(RMTTYP *rmt)
+
+{
+#define OPEP "lvleml.c:close_mx,"
+
+int phase;
+_Bool proceed;
+
+phase=0;
+proceed=(rmt!=(RMTTYP *)0);
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //need to disconnect
+ if (rmt->socptr!=(SOCPTR *)0) {
+ char **resp;
+ int rspcode;
+
+ resp=(char **)0;
+ rspcode=tcp_smtp_command(rmt,&resp,"QUIT");
+ switch (rspcode) {
+ case QUITOK : //Everything fine
+ break;
+ default :
+ (void) rou_alert(0,"%s Unexpected QUIT status='%d' (check code!)",
+ OPEP,rspcode);
+ break;
+ }
+ resp=(char **)rou_freelist((void **)resp,(genfree_t)rou_freestr);
+ rmt->socptr=soc_closefeedsock(rmt->socptr);
+ }
+ break;
+ case 1 : //free memory
+ rmt->mxs=dns_freemxlist(rmt->mxs);
+ rmt->orgdomain=rou_freestr(rmt->orgdomain);
+ rmt->dstdomain=rou_freestr(rmt->dstdomain);
+ (void) free(rmt);
+ rmt=(RMTTYP *)0;
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return rmt;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to connect to the remote SMTP server */
+/* */
+/********************************************************/
+static RMTTYP *connect_mx(LOGPTR *logptr,TRATYP *tra)
+
+{
+#define OPEP "lvleml.c:connect_to_mx,"
+
+_Bool done;
+char *orgdomain;
+char *dstdomain;
+MXTYP **mxs;
+RMTTYP *rmt;
+int phase;
+int proceed;
+
+done=false;
+orgdomain=strrchr(tra->sfrom,'@');
+dstdomain=strrchr(tra->rcptto,'@');
+mxs=(MXTYP **)0;
+rmt=(RMTTYP *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //preparing RMT record
+ if ((orgdomain==(char *)0)||(dstdomain==(char *)0)) {
+ char cmt[100];
+
+ (void) snprintf(cmt,sizeof(cmt),"from <%s> or rcpt <%s>, without domain",
+ tra->sfrom,tra->rcptto);
+ (void) log_fprintlog(rmt->logptr,false,cmt);
+ (void) rou_alert(0,"%s %s (Bug!)",OPEP,cmt);
+ phase=999;
+ }
+ break;
+ case 1 : //looking for MX list
+ orgdomain++;
+ dstdomain++;
+ mxs=dns_getmx(dstdomain);
+ if (mxs==(MXTYP **)0) {
+ (void) log_fprintlog(rmt->logptr,false,"NO MX found for domain <%s>",
+ dstdomain);
+ phase=999;
+ }
+ break;
+ case 2 : //creating rmt record
+ rmt=(RMTTYP *)calloc(1,sizeof(RMTTYP));
+ rmt->logptr=logptr;
+ rmt->mxs=mxs;
+ rmt->orgdomain=strdup(orgdomain);
+ rmt->dstdomain=strdup(dstdomain);
+ 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,(char *)0,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; //MX available found
+ }
+ mxs++;
+ }
+ if (rmt->socptr==(SOCPTR *)0) {
+ (void) rou_alert(0,"%s Found NO MX available for domain <%s>",
+ OPEP,dstdomain);
+ rmt=close_mx(rmt); //closing remote connection
+ phase=999; //No NX found!
+ }
+ break;
+ case 3 : //waiting MX 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
+ rmt=close_mx(rmt); //closing remote connection
+ phase=999; //No need to go further
+ break;
+ }
+ break;
+ case 4 :
+ if ((done=greetings_rmt(rmt))==false)
+ rmt=close_mx(rmt); //closing remote connection
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return rmt;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to reset the remote session */
+/* */
+/********************************************************/
+static _Bool reset_mx(RMTTYP *rmt)
+
+{
+#define OPEP "lvleml.c:reset_mx,"
+
+_Bool ok;
+int rspcode;
+char **resp;
+
+ok=false;
+resp=(char **)0;
+rspcode=tcp_smtp_command(rmt,&resp,"RSET");
+switch (rspcode) {
+ case CMDOK : //Everythin fine
+ ok=true;
+ break;
+ default :
+ (void) rou_alert(0,"%s Unexpected code='%d' (Code?)",OPEP,rspcode);
+ for (int i=0;resp[i]!=(char *)0;i++)
+ (void) rou_alert(0,"%s resp[%d]=<%s>",OPEP,i,resp[i]);
+ break;
+ }
+resp=(char **)rou_freelist((void **)resp,(genfree_t)rou_freestr);
+return ok;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send the data to the remote server */
+/* */
+/********************************************************/
+static void senddata(RMTTYP *rmt,TRATYP **tosend)
+
+{
+#define OPEP "lvleml.c:senddata,"
+
+int rspcode;
+int sent;
+TIMESPEC start;
+char *sessid;
+char **resp;
+int phase;
+_Bool proceed;
+
+rspcode=0;
+sent=0;
+sessid=(*tosend)->sessid;
+resp=(char **)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
+ rspcode=tcp_get_smtp_reply(rmt,WAITRMT,&resp);
+ 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 :
+ (void) eml_duptra_resp(*dest,resp);
+ 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++;
+ }
+resp=(char **)rou_freelist((void **)resp,(genfree_t)rou_freestr);
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send one email session to intended */
+/* recipient. */
+/* */
+/********************************************************/
+static void send_to_mx(RMTTYP *rmt,TRATYP **tosend)
+
+{
+#define OPEP "lvleml.c:send_to_mx,"
+
+int tobesend;
+char *sessid;
+TRATYP **dest;
+
+tobesend=0;
+sessid=(*tosend)->sessid;
+dest=tosend;
+while (*dest!=(TRATYP *)0) {
+ int rspcode;
+ 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;
+ default : //Not accepted recipient
+ (void) rou_alert(0,"%s sessid=<%s>, unknwon code='%d' (Bug?)",
+ OPEP,sessid,rspcode);
+ //NO BREAK
+ case UKNUSER : //recipient is unknown
+ case NORELAY : //email no relayed
+ (*dest)->code='W'; //Need to send a Warning
+ (*dest)->sendcode=rspcode;
+ break;
+ }
+ dest++;
+ }
+if (tobesend>0)
+ (void) senddata(rmt,tosend);
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send the whole email transaction */
+/* */
+/********************************************************/
+static void sending_email(LOGPTR *logptr,TRATYP **tra)
+
+{
+#define OPEP "lvleml.c:sending_email,"
+
+time_t isnow;
+char *sessid;
+RMTTYP *rmt;
+TRATYP **tosend;
+int phase;
+_Bool proceed;
+
+isnow=time((time_t *)0);
+sessid=(char *)0;
+rmt=(RMTTYP *)0;
+tosend=(TRATYP **)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //do we have a email request
+ if ((tra)==(TRATYP **)0) {
+ (void) rou_alert(0,"%s No email to send to remote! (Bug?)",OPEP);
+ phase=999; //all scanning done
+ }
+ break;
+ case 1 : //process completed?
+ if ((*tra)==(TRATYP *)0)
+ phase=999; //all scanning done
+ break;
+ case 2 : //do a remote reset if needed
+ if (rmt!=(RMTTYP *)0) {
+ if (reset_mx(rmt)==false) {
+ rmt=close_mx(rmt);
+ phase=999; //Trouble Trouble
+ }
+ }
+ break;
+ case 3 : //collecting email to be sent
+ sessid=(*tra)->sessid;
+ 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 4 : //Checking if we have email to be sent
+ if (tosend==(TRATYP **)0)
+ phase=0; //lets continue to see other email
+ break;
+ case 5 : //is MX link already open??
+ if (rmt!=(RMTTYP *)0)
+ phase++; //No need to open MX link (again);
+ break;
+ case 6 : //Opening connection if not open
+ if ((rmt=connect_mx(logptr,*tosend))==(RMTTYP *)0) {
+ TRATYP **ptr;
+ char cmt[100];
+ char note[150];
+
+ ptr=tosend;
+ (void) snprintf(cmt,sizeof(cmt),"Unable to contact ANY MX to reach <%s>",
+ (*tosend)->rcptto);
+ (void) log_fprintlog(logptr,false,cmt);
+ (void) snprintf(note,sizeof(note),"%d %s",NOANSWR,cmt);
+ 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 7 : { //sending originator
+ int rspcode;
+
+ rspcode=simple_smtp_command(rmt,"MAIL FROM: <%s>",(*tosend)->sfrom);
+ 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 8 : //sending recipient list
+ (void) send_to_mx(rmt,tosend);
+ (void) free(tosend);
+ tosend=(TRATYP **)0;
+ phase=0; //Trying to send NEXT sequence of email to be sent
+ break;
+ default : //SAFE Guard
+ rmt=close_mx(rmt);
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to transmit a string to the remot peer*/
+/* */
+/********************************************************/
+PUBLIC void eml_transmit(CONTYP *contact,_Bool flush,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);
+ contact->transout=tcp_addline(contact->transout,line);
+ }
+if (flush==true) {
+ (void) tcp_write(contact->socptr,contact->transout);
+ contact->transout=rou_freestr(contact->transout);
+ }
+line=rou_freestr(line);
+va_end(args);
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to report the contact ongoing */
+/* informationn. store this information */
+/* within the database. */
+/* */
+/************************************************/
+PUBLIC void eml_note(CONTYP *contact,char *rcpt,const char *fmt,...)
+
+{
+#define OPEP "lvleml.c:eml_status"
+
+va_list args;
+char **resp;
+char *report;
+ACTTYP action;
+
+va_start(args,fmt);
+resp=(char **)0;
+(void) rou_vasprintf(&report,fmt,args);
+resp=(char **)rou_addlist((void **)resp,(void *)report);
+(void) memset(&action,'\000',sizeof(ACTTYP));
+action.code='X';
+action.sessid=contact->session->sessid;
+action.reverse=contact->peername;
+action.remoteip=contact->peerip;
+if (contact->mailfrom!=(char *)0)
+ action.sfrom=contact->mailfrom;
+if (contact->session->hfrom!=(char *)0)
+ action.hfrom=contact->session->hfrom;
+if (contact->session->hsubject!=(char *)0)
+ action.hsubject=contact->session->hsubject;
+action.rcptto=rcpt;
+action.resp=resp;
+if (sql_mngact(contact->sqlptr,&action)==false)
+ (void) rou_alert(0,"%s, unable to store report within database (bug?",OPEP);
+resp=(char **)rou_freelist((void **)resp,(genfree_t)rou_freestr);
+va_end(args);
+
+#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 Multiple remote connection */
+/* -4 BUG! */
+/* */
+/********************************************************/
+PUBLIC int eml_docontact(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:eml_docontact"
+
+int status;
+int got;
+int penalty; //answer time penalty, in case of wrong auth
+_Bool proceed;
+
+status=1;
+got=0;
+penalty=1;
+proceed=true;
+(void) signon(contact);
+while (proceed==true) {
+ char *line;
+ CODTYP code;
+
+ line=(char *)0;
+ got=tcp_getline(contact->socptr,contact->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",
+ contact->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) setterminator(contact,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_help : //HELP SMTP protocol
+ (void) eml_transmit(contact,true,"%d 2.0.1 see https://datatracker.ietf.org"
+ "/doc/html/rfc5321",
+ GOTHELP);
+ (void) sleep(1); //avoiding abuse
+ break;
+ case c_noop : //No Operation
+ (void) eml_transmit(contact,true,"%d 2.0.0 OK, %s",
+ CMDOK,contact->mainsesid);
+ break;
+ case c_quit : //QUIT SMTP protocol
+ contact->credit++; //clean disconnect
+ (void) setterminator(contact,"QUIT received");
+ (void) eml_transmit(contact,true,"%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
+ proceed=checkfrom(contact,line);
+ break;
+#ifdef MODEDEBUG
+ case c_orgn : //Debug mode to override remote IP
+ proceed=set_orgn_rmtip(contact,line);
+ break;
+#endif
+ case c_auth : //Auth request
+ if (getauth(contact,line)==false)
+ proceed=false; //Authentication failed
+ 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
+ (void) usleep(100000);
+ (void) soc_purge(contact->socptr,contact->peerip);
+ (void) eml_transmit(contact,true,"%d 2.0.0 Ready to start TLS",SIGNON);
+ switch (soc_starttls(contact->socptr,true)) {
+ case true : { //link now in TLS crypted mode (server mode)
+ int level;
+
+ level=soc_get_sec_level(contact->socptr);
+ (void) log_fprintlog(contact->logptr,false,cry,"server",level);
+ }
+ break;
+ case false : //unable to establish link
+ (void) setterminator(contact,"starttls not successful");
+ (void) eml_transmit(contact,true,"%d 5.3.3 command starttls not "
+ "successful",CMDBAD);
+ status=-1;
+ proceed=false;
+ break;
+ }
+ break;
+ case c_unknown : //unknown keyword
+ contact->credit-=2; //Trying to confuse server?
+ (void) rou_alert(0,"SMTP Command <%s> from [%s] is unknown (config?)",
+ line,contact->peerip);
+ (void) eml_transmit(contact,true,"%d-5.5.1 Unrecognized command, "
+ "see RFC 5321",CMDBAD);
+ (void) eml_transmit(contact,true,"%d-5.5.1 https://www.rfc-editor.org",
+ CMDBAD);
+ (void) eml_transmit(contact,true,"%d 5.5.1 session %s is still running",
+ CMDBAD,contact->mainsesid);
+ break;
+ default :
+ contact->credit-=10; //Trying to bug server
+ (void) rou_alert(0,"%s Unable to find entry for code='%d' (Bug?)",OPEP,code);
+ (void) eml_transmit(contact,true,"%d-5.5.1 Unrecognized command, "
+ "see RFC 5321",CMDBAD);
+ (void) eml_transmit(contact,true,"%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
+#define MXDELAY 300 //maximun waiting time 5 minutes standard delay
+
+CONTYP *contact;
+int phase;
+_Bool proceed;
+
+contact=(CONTYP *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ (void) rou_dbglive(9,OPEP,"phase='%d'",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();
+ contact->credit=0;
+ if (contact->sqlptr==(SQLPTR *)0) {
+ (void) rou_alert(0,"%s Unable to contact database",OPEP);
+ (void) sleep(2);//delay to avoid avalanche
+ (void) eml_dropcontact(contact);
+ contact=(CONTYP *)0;
+ phase=999; //no contact possible.
+ }
+ break;
+ case 2 : //loading the relayable IP list
+ contact->relayok=eml_load_relayed(getenv(RELAYS));
+ break;
+ case 3 : //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 4 : //Preparing contact
+ contact->mainsesid=eml_getmainsesid();
+ contact->delay=MXDELAY;
+ contact->privilege=rel_plain; //Standard connection
+ if (debug>1)
+ contact->delay/=10; //30 sec in debug mode
+ (void) getsessid(contact);
+ 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,(const char *)0);
+ contact->localafns=afn_getipnums(contact->locip);
+ (void) rou_alert(0,"Contact from peer <%s> to port <%s> started",
+ contact->peerip,contact->locserv);
+ break;
+ case 5 : //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 6 : //checking if remote IP is relayable
+ if (afn_is_ip_relayable(contact->peerip,contact->relayok)==true) {
+ contact->privilege=rel_isrelay; //IP is relayable
+ contact->credit++;
+ }
+ break;
+ case 7 : //contact is good, then sending a signon
+ (void) prc_settitle("%s:%s, incoming contact from [%s] on [%s:%s]",
+ APPNAME,appname,contact->peerip,
+ contact->locname,contact->locserv);
+ (void) log_fprintlog(contact->logptr,true,"Start CNT=%s",contact->mainsesid);
+ (void) log_fprintlog(contact->logptr,false,"(Contact open from [%s] to "
+ "[%s:%s])",
+ contact->peerip,
+ contact->locip,
+ contact->locserv);
+ if (soc_iscrypted(contact->socptr)==true) {
+ int level;
+
+ level=soc_get_sec_level(contact->socptr);
+ (void) log_fprintlog(contact->logptr,false,cry,"server",level);
+ }
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return contact;
+#undef MXCARIN
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to wait for a remote client. */
+/* return the fee memory contact (NULL pointer) */
+/* */
+/********************************************************/
+PUBLIC CONTYP *eml_dropcontact(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:eml_dropcontact"
+
+SRVTYP *srv;
+int phase;
+_Bool proceed;
+
+srv=(SRVTYP *)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 (contact==(CONTYP *)0) {
+ (void) rou_alert(0,"%s Contact pointer is NULL (Bug!?)",OPEP);
+ phase=999; //not going further
+ }
+ break;
+ case 1 : //getting the remote server information
+ if (sql_mngremote(contact->sqlptr,sql_select,contact->peerip,&srv)==false) {
+ (void) rou_alert(0,"%s Unable to get remote [%s] data (Bug!?)",
+ OPEP,contact->peerip);
+ phase++; //No need to do update
+ }
+ break;
+ case 2 : //Updating remote server data
+ if (srv!=(SRVTYP *)0) { //Always
+ char *bank;
+
+ srv->credit+=contact->credit;
+ srv->update=time((time_t *)0);
+ if (sql_mngremote(contact->sqlptr,sql_update,contact->peerip,&srv)==false) {
+ (void) rou_alert(0,"%s Unable to UPDATE remote [%s] data (Bug!?)",
+ OPEP,contact->peerip);
+ }
+ bank=eml_showcredit(contact->peerip,contact->peername,
+ contact->credit,srv->credit);
+ (void) log_fprintlog(contact->logptr,true,"(%s)",bank);
+ bank=rou_freestr(bank);
+ srv=sql_freesrv(srv);
+ }
+ break;
+ case 3 : //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);
+ break;
+ case 4 : //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->remoteip=strdup(contact->peerip);
+ tra->reverse=strdup(contact->peername);
+ tra->sessid=strdup(contact->session->sessid);
+ tra->sfrom=strdup(contact->mailfrom);
+ tra->rcptto=strdup(data);
+ (void) strcpy(data,"email header, 'From:' missing");
+ if (contact->session->hfrom!=(char *)0)
+ (void) strncpy(data,contact->session->hfrom,sizeof(data)-1);
+ tra->hfrom=strdup(data);
+ (void) strcpy(data,"email header, 'Subject:' missing");
+ if (contact->session->hsubject!=(char *)0)
+ (void) strncpy(data,contact->session->hsubject,sizeof(data)-1);
+ tra->hsubject=strdup(data);
+ tralist=(TRATYP **)rou_addlist((void **)tralist,(void *)tra);
+ ptr++;
+ }
+ (void) eml_dump_list_tra(qfile,tralist);
+ (void) sql_update_tradb(contact->sqlptr,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)->sfrom,
+ (*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 *mainsesid;
+LOGPTR *logptr;
+long debut;
+long fin;
+int phase;
+_Bool proceed;
+
+mainsesid=(char *)0;
+logptr=(LOGPTR *)0;
+debug=0;
+fin=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 : //checking if we have a session ID
+ if ((*tra)->sessid==(char *)0) {
+ (void) rou_alert(0,"%s Session ID is NULL (Bug?)",OPEP);
+ phase=999;
+ }
+ break;
+ case 2 : //extracting the main session number
+ char *ptr;
+ char cmt[100];
+
+ mainsesid=strdup((*tra)->sessid);
+ ptr=strrchr(mainsesid,'-');
+ if (ptr!=(char *)0)
+ *ptr='\000';
+ (void) snprintf(cmt,sizeof(cmt),"main-session-id=%s",mainsesid);
+ logptr=log_openlog(mainsesid,cmt);
+ mainsesid=rou_freestr(mainsesid);
+ break;
+ case 3 : //sending all email within transaction
+ (void) sending_email(logptr,tra);
+ break;
+ case 4 : //closing log linked to session
+ logptr=log_closelog(logptr,&debut,&fin);
+ 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->sfrom;
+tra->sfrom=tra->rcptto;
+tra->sfrom=tmp;
+tra->code='L';
+}
+