From: Vincent Nolet-Pigeon Date: Wed, 17 Dec 2025 19:30:10 +0000 (-0500) Subject: Sync project from jmp/safe sources X-Git-Tag: tag-0.19^0 X-Git-Url: https://jmp-git.ovh.safe.ca/?a=commitdiff_plain;h=refs%2Fheads%2Fmaster;p=mailleur.ref Sync project from jmp/safe sources --- 55c3bd425f78593b76e418f7c8c998c6aca38613 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..24823ba --- /dev/null +++ b/Makefile @@ -0,0 +1,299 @@ +#==================================================================== +#Makefile to build the package +#default make +default : clean prod +#-------------------------------------------------------------------- +#test area Makefile +include Makefile.dbg +#distribution area Makefile +include Makefile.dist +#-------------------------------------------------------------------- +#Executable generation area +LOAD = $(shell echo -j `echo $(shell /usr/bin/getconf _NPROCESSORS_ONLN)`) +#-------------------------------------------------------------------- +prod \ +debug \ + : + @ for i in $(SUBDIR) ; \ + do \ + $(MAKE) $(LOAD) DB=$(DB) -C $$i $@ ; \ + done + + +allclean \ +clean : cleanrpm + @ for i in $(SUBDIR) ; \ + do \ + $(MAKE) -s -C $$i $@ ; \ + done + @ - rm -fr $(APPNAME)-* + +posql : clean debug + @ ln -nsf bin-posql bin + @ $(MAKE) -s newtest + +mysql : clean debug + @ ln -nsf bin-mysql bin + @ $(MAKE) -s newtest + +#==================================================================== +FEEDPAR = \ + $(TESTIP) \ + $(TESTPORT) \ + ./$(DATATST)/feed0*.tst + +#to test with an external server +extfeed : debug + @ bin-utils/feeder \ + -f \ + -d3 \ + -c ./conf/feeder.conf.dvl \ + $(EXTIP) \ + $(EXTPORT) \ + ./$(DATATST)/$(ONEFEED) + + +#direct test +tstfeed : debug + @ bin-utils/feeder \ + -c ./conf/$(APPNAME).conf.dvl \ + $(FEEDPAR) + + + +#using gdb +dbgfeed : debug + @ gdb \ + --args \ + bin-utils/feeder \ + -f \ + -d 2 \ + -c ./conf/$(APPNAME).conf.dvl \ + $(TESTIP) \ + $(TESTPORT) \ + ./$(DATATST)/$(ONEFEED).tst + +valfeed : debug #valgring of emlrcvr + @ echo "feed valgrind test" + @ valgrind \ + --leak-check=full \ + --show-leak-kinds=$(VALKIND) \ + bin-utils/feeder \ + -f \ + -d2 \ + -c ./conf/feeder.conf.dvl \ + $(TESTIP) \ + $(TESTPORT) \ + ./$(DATATST)/$(ONEFEED) + + +# --track-fds=yes \ +#testing TLS connection +tlsrcvr : + @ clear + openssl s_client \ + -trace \ + -crlf \ + -status \ + -CAfile /etc/pki/tls/make-ca/ca-bundle.crt \ + -cert certs/localhost-cert.pem \ + -key certs/localhost-key.pem \ + -starttls smtp \ + -connect mailpostg.example.com:25 +# -connect smtp1.example.com:25 +# -connect courriel.colba.net:25 +# -connect mx1.free.fr:25 +# -connect $(TESTSRV):$(TESTPORT) + +tlsmx1 : + @ clear + openssl s_client \ + -trace \ + -crlf \ + -status \ + -CAfile /etc/pki/tls/make-ca/ca-bundle.crt \ + -cert certs/localhost-cert.pem \ + -key certs/localhost-key.pem \ + -starttls smtp \ + -connect mx1.free.fr:25 + +go465 : + @ clear + @ openssl s_client \ + -crlf \ + --showcerts \ + -key certs/localhost-key.pem \ + -cert_chain certs/localhost-chain-cert.pem \ + -CAfile /etc/pki/tls/make-ca/ca-bundle.crt \ + -tls1_2 \ + -connect $(TESTIP):1025 + +# -status +# -crlf +# -msg +# -debug +# -showcerts +# -tls1_2 +# -connect mailpostg.example.com:25 +# -connect $(TESTSRV):$(TESTPORT) +# -connect smtp.google.com:25 +# -connect courriel.colba.net:25 +# +#testing TLS with google +tlsref: + @ clear + @ openssl s_client \ + -quiet \ + -crlf \ + -CAfile /etc/pki/tls/make-ca/ca-bundle.crt \ + -cert certs/localhost-cert.pem \ + -key certs/localhost-key.pem \ + -starttls smtp \ + -connect tar1.osukiss.org:25 + +# -connect mx2.free.fr:25 +# -connect tar1.orukiss.org:25 +# -connect mailprod1.safe.ca:587 +# -connect tar1.osukiss.org:25 +# -connect smtp.google.com:25 +# -connect courriel.colba.net:25 +# -connect courriel.colba.net:587 +# -connect mailmysql.example.com:25 +# -connect $(TESTSRV):$(TESTPORT) + +#-------------------------------------------------------------------- +#starting email receiver + +eml465 : prepare + @ echo + @ echo "--------------" + @ echo "starting $@" + @ $(TESTDIR)/$(SBINDIR)/emlrcvr \ + -c ./conf/$(APPNAME).conf.dvl \ + -d 1 \ + -r $(TESTDIR) \ + smtps:$(TESTIP):1065:1 + + +prepare : clean debug newtest + +#-------------------------------------------------------------------- +#test procedure +#-------------------------------------------------------------------- +#testing SPF fonction +tstspf : clean debug + @ shell/test-spf.sh data-spf/spf.tst + +#todo a specfic test +#DATA = chkaddr.spf.example.com 127.0.1.255 + +#-------------------------------------------------------------------- +#preparing a test area +newtest : deltest + @ mkdir -p $(TESTDIR)/var/run + @ mkdir -p $(TESTDIR)/$(SBINDIR) + @ mkdir -p $(TESTDIR)/etc/$(APPNAME) + @ mkdir -p $(TESTDIR)/usr/share/$(APPNAME) + @ mkdir -p $(TESTDIR)/var/spool/$(APPNAME)/queue + @ mkdir -p $(TESTDIR)/var/spool/$(APPNAME)/mails + @ mkdir -p $(TESTDIR)/usr + @ cp -a \ + conf/* \ + $(TESTDIR)/etc/$(APPNAME) + @ cp -a \ + sql \ + $(TESTDIR)/usr/share/$(APPNAME)/ + @ $(MAKE) -s -C sql prepdb + +deltest : + @ rm -fr $(TESTDIR) + +#-------------------------------------------------------------------- +#Installation procedure +#-------------------------------------------------------------------- +install : + @ # Creating all needed system directory + @ install -d $(DESTDIR)/$(BINDIR)/ + @ install -d $(DESTDIR)/$(DATADIR)/$(APPN)/ + @ install -d $(DESTDIR)/$(ETCDIR)/$(APPN)/ + @ install -d $(DESTDIR)/$(ETCDIR)/pki/$(APPN)/ + @ install -d $(DESTDIR)/$(ETCDIR)/sysconfig/ + @ install -d $(DESTDIR)/$(ETCDIR)/httpd/conf.d/ + @ install -d $(DESTDIR)/$(ETCDIR)/cron.d/ + @ install -d $(DESTDIR)/$(LIBDIR)/$(APPN)/ + @ install -d $(DESTDIR)/$(LIBDIR)/$(APPN)/tools + @ install -d $(DESTDIR)/$(EXECDIR)/$(APPN)/ + @ install -d $(DESTDIR)/$(SPOOLDIR)/$(APPN)/mails + @ install -d $(DESTDIR)/$(SPOOLDIR)/$(APPN)/queue + @ install -d $(DESTDIR)/var/www/$(APPN)/ + @ cp -a \ + bin-*/ \ + $(DESTDIR)/$(EXECDIR)/$(APPN) + #set some utilities + @ ln -s \ + $(EXECDIR)/$(APPN)/bin-utils/chkspf \ + $(DESTDIR)/$(BINDIR)/ + # + @ cp -a \ + conf/$(APPN).conf \ + conf/relayed.conf \ + conf/blacklister.conf \ + $(DESTDIR)/$(ETCDIR)/$(APPN) + @ cp -a \ + conf/dovecot \ + $(DESTDIR)/$(ETCDIR)/ + @ cp -a \ + certs/root-safe_CA.pem \ + $(DESTDIR)/$(ETCDIR)/pki/$(APPN)/ + @ cp -a \ + linux \ + $(DESTDIR)/$(DATADIR)/$(APPN)/ + @ cp -a \ + shell \ + support \ + $(DESTDIR)/$(LIBDIR)/$(APPN)/ + @ cp -a \ + sysconfig \ + $(DESTDIR)/$(ETCDIR)/ + @ cp -a \ + cron/$(APPN).cron \ + $(DESTDIR)/$(ETCDIR)/cron.d/ + @ cp -a \ + sql \ + $(DESTDIR)/$(DATADIR)/$(APPN)/ + @ cp -a \ + tools/genpsdusr.sh \ + $(DESTDIR)/$(LIBDIR)/$(APPN)/tools + @ cp -a \ + www/* \ + $(DESTDIR)/var/www/$(APPN)/ + + +#-------------------------------------------------------------------- +SUBDIR = \ + lib \ + app \ + tools \ + sql \ + +#-------------------------------------------------------------------- +#definitions globale +APPNAME = mailleur +#-------------------------------------------------------------------- +#to set the compiled default library +ifeq ($(strip $(DB)),) +DB=0 +endif +#-------------------------------------------------------------------- +#Managing testarea +LIBDIR = /usr/lib +DATADIR = /usr/share +BINDIR = /usr/bin +SBINDIR = /usr/sbin +SPOOLDIR= /var/spool +EXECDIR = /usr/libexec +ETCDIR = /etc +CURDIR = $(shell pwd) +#-------------------------------------------------------------------- +.PHONY: clean cleanrpm +#=================================================================== diff --git a/Makefile.dbg b/Makefile.dbg new file mode 100644 index 0000000..d2b5932 --- /dev/null +++ b/Makefile.dbg @@ -0,0 +1,243 @@ +#=================================================================== +#debug area definition +SBINDIR = usr/sbin +DATATST = data-feed +LOCKDIR = $(TESTDIR)/var/run/$(APPNAME) + +#managing debugging test +TESTDIR = $(CURDIR)/test_area +TESTSRV = mailleur.example.com +TESTIP = 127.127.10.25 +TESTPORT= 1025 +#TESTPROT= smtps +EXTIP = safemail3.safe.ca +EXTPORT = 25 +TESTITER= 2 + +DBGPAR = \ + -r $(TESTDIR) \ + -c ./conf/$(APPNAME).conf.dvl \ + -d 2 \ + +EMLPAR = \ + $(DBGPAR) \ + "$(TESTPROT)|$(TESTIP)|$(TESTPORT)|" + +#==================================================================== +#area to start components receiver,sorter,sender once at a time +#-------------------------------------------------------------------- +stdrcvr : clean debug + @ \ + ./bin/receiver \ + $(EMLPAR)$(TESTITER) + +gorcvr : clean debug + @ \ + ./bin/receiver \ + -f \ + $(EMLPAR)$(TESTITER) + +digest : clean debug + gdb \ + --args \ + \ + ./bin/receiver \ + -f \ + -r $(TESTDIR) \ + -c ./conf/$(APPNAME).conf.dvl \ + -d 9 \ + "|devel5.safe.ca|1025|1" + +valdigest: clean debug + valgrind \ + --leak-check=full \ + --show-leak-kinds=$(VALKIND) \ + \ + ./bin/receiver \ + -f \ + -r $(TESTDIR) \ + -c ./conf/$(APPNAME).conf.dvl \ + -d 9 \ + "|devel5.safe.ca|1025|1" + +# "|127.127.10.25|1025|1" + +onercvr : clean debug + @ \ + ./bin/receiver \ + -f \ + $(EMLPAR)$(TESTITER) + +onescar: clean debug + @ echo "Starting scanner" + @ \ + bin/scanner \ + -f \ + $(DBGPAR) + +onefeed : debug + @ \ + bin-utils/feeder \ + -f \ + -c ./conf/$(APPNAME).conf.dvl \ + $(TESTIP) \ + $(TESTPORT) \ + ./$(DATATST)/$(ONEFEED).tst + +onesendr: debug + @ \ + ./bin/sender \ + -f \ + -d 2 \ + -c ./conf/mailleur.conf.dvl \ + -r $(TESTDIR) \ + +onesortr: debug + @ \ + bin/sorter \ + -f \ + -d 9 \ + -c ./conf/mailleur.conf.dvl \ + -r $(TESTDIR) + +#-------------------------------------------------------------------- +#procedure to start all needed components to have +#a full complete test + +restart : killall dosortr dorcvr doscarmt dosendr + @ echo "Restart completed" + +actions : killall debug newtest restart + +dosortr : + @ echo "Starting Sorter" + @ \ + bin/sorter \ + -d 2 \ + -c ./conf/mailleur.conf.dvl \ + -r $(TESTDIR) + + +dorcvr : + @ echo "Starting receiver" + @ \ + bin/receiver \ + $(EMLPAR)$(TESTITER) + +dosendr: debug + @ echo "Starting sender" + @ \ + ./bin/sender \ + -d 2 \ + -c ./conf/mailleur.conf.dvl \ + -r $(TESTDIR) \ + +doscarmt: + @ echo "Starting scanner" + @ \ + bin/scanner \ + $(DBGPAR) + +#to kill all remaining mailleur process +killall : + - kill -TERM receiver + - kill -TERM sender + - kill -TERM sorter + - kill -TERM scanner + +#-------------------------------------------------------------------- +#procedure to call debugger for each main component + +dbgrcvr : clean debug + @ \ + gdb \ + --args \ + bin/receiver \ + -f \ + $(EMLPAR)$(TESTITER) + +dbgsortr: clean debug + @ \ + gdb \ + --args \ + bin/sorter \ + -f \ + -d 2 \ + -c ./conf/mailleur.conf.dvl \ + -r $(TESTDIR) + +dbgscar: clean debug + @ \ + gdb \ + --args \ + bin/scanner \ + -f \ + $(DBGPAR) + +valscar: clean debug + @ \ + valgrind \ + --leak-check=full \ + --show-leak-kinds=$(VALKIND) \ + \ + bin/scanner \ + -f \ + $(DBGPAR) + +TODO = `basename -a \ + $(TESTDIR)/var/spool/$(APPNAME)/queue/*.todo|\ + tr '\\n' ' ' ` + +dbgsendr: clean debug + @ \ + gdb \ + --args \ + bin/sender \ + -f \ + -d2 \ + -c ./conf/mailleur.conf.dvl \ + -r $(TESTDIR) \ + +#-------------------------------------------------------------------- +#procedure to check programe against valgrind +#VALKIND= "definite,possible,indirect,reachable" +VALKIND = "definite,possible,indirect" + +valrcvr : debug + @ \ + valgrind \ + --leak-check=full \ + --show-leak-kinds=$(VALKIND) \ + bin/receiver \ + -f \ + $(EMLPAR)$(TESTITER) + +valsortr: debug + @ \ + valgrind \ + --leak-check=full \ + bin/sorter \ + -f \ + -d 2 \ + -c ./conf/mailleur.conf.dvl \ + -r $(TESTDIR) + +valsendr: debug + @ \ + valgrind \ + --leak-check=full \ + --show-leak-kinds=$(VALKIND) \ + ./bin/sender \ + -f \ + -d 2 \ + -c ./conf/mailleur.conf.dvl \ + -r $(TESTDIR) \ + `basename -a $(TESTDIR)/var/spool/$(APPNAME)/queue/*.todo | \ + tr '\\n' ' ' ` + +#-------------------------------------------------------------------- +#to Specify FEED +ONEFEED=$(FEED) +ifeq ($(strip $(FEED)),) +ONEFEED=feed002 +endif diff --git a/Makefile.dist b/Makefile.dist new file mode 100644 index 0000000..767b79a --- /dev/null +++ b/Makefile.dist @@ -0,0 +1,106 @@ +#==================================================================== +#Makefile with all necessary to build distribution RPM +APPN = mailleur +#==================================================================== +binary : rpm + @ echo "'$(APLV)' RPM binary file, building" + @ rpmbuild \ + --quiet \ + --noclean \ + --rebuild \ + --define "_topdir $(RPMDIR)" \ + --target `uname -m` \ + $(SRPM)/$(APPN)-$(VERSION).$(RELEASE)-*.src.rpm + @ echo "'$(APLV)' RPM binary file, ready" + +rpm : cleanrpm tarfile spec + @ echo "'$(APLV)' RPM source file, building" + @ mkdir -p $(SRPM) + @ rpmbuild -bs \ + --quiet \ + --define "_topdir $(RPMDIR)" \ + --define "_source_filedigest_algorithm md5" \ + --define "_binary_filedigest_algorithm md5" \ + spec + @ echo "'$(APLV)' RPM source file, ready" + +tarfile : clean + @ mkdir -p $(SRC) + @ echo "'$(APLV)' tar file, building" + @ mkdir -p \ + $(APLV)/app \ + $(APLV)/certs \ + $(APLV)/conf \ + $(APLV)/bin \ + $(APLV)/lib \ + $(APLV)/linux \ + $(APLV)/shell \ + $(APLV)/sysconfig \ + $(APLV)/support \ + $(APLV)/sql \ + $(APLV)/tools \ + $(APLV)/www \ + $(APLV) + @ date > $(APLV)/$(APLV).build_date + @ cp -a Makefile* $(APLV)/ + @ cp -a app/*.c $(APLV)/app/ + @ cp -a \ + certs/root-safe_CA.pem \ + $(APLV)/certs/ + @ cp -a \ + conf/*.conf \ + dovecot \ + $(APLV)/conf/ + @ cp -a lib/{*.c,*.h} $(APLV)/lib/ + @ cp -a linux/* $(APLV)/linux/ + @ cp -a \ + shell/getsysos.sh \ + $(APLV)/shell/ + @ cp -a \ + cron/ \ + tools/ \ + $(APLV)/ + @ cp -a \ + www/*.php \ + www/reg-icons \ + $(APLV)/www + @ cp -a support/*.sh \ + $(APLV)/support + @ cp -a sysconfig/* \ + $(APLV)/sysconfig + @ cp -a \ + sql/$(APPN).sql \ + sql/preset.sql \ + sql/datatest.* \ + sql/Makefile \ + $(APLV)/sql + @ cp -a app/Makefile $(APLV)/app/Makefile + @ cp -a lib/Makefile $(APLV)/lib/Makefile + @ tar zcf $(SRC)/$(APLV).tar.gz $(APLV) + @ rm -fr $(APLV) + @ echo "'$(APLV)' tar file, ready" + +spec : $(APPN).spec.in + @ sed \ + -e 's/@@DIST@@/dvl/g' \ + -e 's/@@APPN@@/$(APPN)/g' \ + -e 's/@@VERSION@@/$(VERSION).$(RELEASE)/g' \ + -e 's/@@RELEASE@@//g' \ + < $< > $@ + + + +cleanrpm: + @ rm -fr $(RPMDIR)/* spec + +#==================================================================== +#rpm definitions +RPMDIR = $(CURDIR)/rpmbuild +SRC = $(RPMDIR)/SOURCES +SRPM = $(RPMDIR)/SRPMS +#==================================================================== +VERSION = $(shell echo `grep VERSION lib/numver.h | cut -d '"' -f2`) +RELEASE = $(shell echo `grep RELEASE lib/numver.h | cut -d '"' -f2`) +APPV = $(VERSION).$(RELEASE) +APLV = $(APPN)-$(APPV) +#==================================================================== diff --git a/Notes b/Notes new file mode 100644 index 0000000..33bbff0 --- /dev/null +++ b/Notes @@ -0,0 +1,19 @@ +Versions: + +#----------------------------------------------------------- +MA-0.6-dvl, certificat exchange is working properly +#----------------------------------------------------------- +#Format for trans file +status date delta session from rcpt +Char long int char * char * char * +status can be: + C completed ;email dispatched + D default ;email can not be dispatched + L local ;Email stay on local serveur + R Remote ;email is to be sent on remote site +#----------------------------------------------------------- +#b64 Exchange +cmVhbG09Im1haWxsZXVyLWVtYWlsIixub25jZT0iTVd0dlVIWlZhVzV3ZDJSWGJFZEtTWEJGTVZSbFRHbGljazVpYTIxQiIscW9wPWF1dGgsYWxnb3JpdGhtPW1kNS1zZXNzLGNoYXJzZXQ9dXRmLTg= + +dXNlcm5hbWU9ImRpZ2kiLHJlYWxtPSJtYWlsbGV1ci1lbWFpbCIsbm9uY2U9Ik1XdHZVSFpWYVc1d2QyUlhiRWRLU1hCRk1WUmxUR2xpY2s1aWEyMUIiLGNub25jZT0iNU1TQ2Z5YUN0WWxES2c2YkVhK0kiLG5jPTAwMDAwMDAxLHFvcD0iYXV0aCIsZGlnZXN0LXVyaT0ic210cC8xOTIuMjE5LjI1NC4xODEiLHJlc3BvbnNlPWQxYTFlOGFmMDUzZmJhNmQzY2NhMzg3NmQ2YWY1N2ExLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz +#----------------------------------------------------------- diff --git a/app/Makefile b/app/Makefile new file mode 100644 index 0000000..d3d4f25 --- /dev/null +++ b/app/Makefile @@ -0,0 +1,167 @@ +#-------------------------------------------------------------------- +#Executable generation area +#-------------------------------------------------------------------- +debug : + @ $(MAKE) OPTIME="-g" DEBUG="-DDEBUG" exe + @ echo "application compiled in '$@' mode now ready" + +prod : + @ $(MAKE) OPTIME="-g -O2" exe + @ echo "application compiled in '$@' mode now ready" + +exe : + $(MAKE) $(EXE) + + +clean : + - rm -fr *.o $(EXE) + - rm -fr ../bin-* + +allclean: clean + - rm -fr *.d + +#-------------------------------------------------------------------- +#Equivalences +#-------------------------------------------------------------------- +EXE = \ + chkspf \ + feeder \ + receiver \ + scanner \ + sender \ + sorter \ + +SRC = \ + chkspf.c \ + feeder.c \ + receiver.c \ + scanner.c \ + sender.c \ + sorter.c \ + +OBJS = \ + chkspf.o \ + feeder.o \ + receiver.o \ + scanner.o \ + sorter.o \ + sender.o \ + +#-------------------------------------------------------------------- +#definitions +#-------------------------------------------------------------------- +CC = gcc +LD = gcc -g +CFLAGS = -I ../lib -Wall $(OPTIME) +LIBMAIL = ../lib/libmail.a + +LIBS = $(LIBMAIL) \ + -luuid \ + -lcrypto \ + -lcrypt \ + -lssl \ + +#-------------------------------------------------------------------- +#Dependances +#-------------------------------------------------------------------- +chkspf \ +feeder \ + : toremake $(OBJS) + @ $(LD) $(LDFLAGS) -o ../bin-utils/$@ $@.o $(LIBS) + +receiver \ +scanner \ +sender \ +sorter \ + : toremake $(OBJS) + @ $(LD) $(LDFLAGS) \ + -o ../bin-posql/$@ $@.o \ + $(LIBS) \ + ../lib/libpos.a \ + -lpq + @ $(LD) $(LDFLAGS) \ + -o ../bin-mysql/$@ $@.o \ + $(LIBS) \ + ../lib/libmar.a \ + -lmysqlclient + + +chkspf.o: chkspf.c \ + ../lib/unidns.h \ + ../lib/subafn.h \ + ../lib/subrou.h + +receiver.o:receiver.c \ + ../lib/modrec.h \ + ../lib/gessql.h \ + ../lib/devsql.h \ + ../lib/unitls.h \ + ../lib/unisig.h \ + ../lib/uniprc.h \ + ../lib/unipar.h \ + ../lib/unidns.h \ + ../lib/subrou.h + +feeder.o: feeder.c \ + ../lib/gestcp.h \ + ../lib/devsoc.h \ + ../lib/unieml.h \ + ../lib/unipar.h \ + ../lib/subrou.h + +sorter.o: sorter.c \ + ../lib/geseml.h \ + ../lib/unisig.h \ + ../lib/uniprc.h \ + ../lib/unipar.h \ + ../lib/unieml.h \ + ../lib/unidns.h \ + ../lib/subrou.h + +scanner.o: scanner.c \ + ../lib/devlog.h \ + ../lib/devsql.h \ + ../lib/gessql.h \ + ../lib/unidns.h \ + ../lib/unipar.h \ + ../lib/uniprc.h \ + ../lib/unisig.h \ + ../lib/subafn.h \ + ../lib/subrou.h + +sender.o: sender.c \ + ../lib/lvleml.h \ + ../lib/geseml.h \ + ../lib/unieml.h \ + ../lib/unipar.h \ + ../lib/uniprc.h \ + ../lib/unisig.h \ + ../lib/subrou.h + +toremake: Makefile + touch toremake + @ - mkdir -p ../bin-utils + @ - mkdir -p ../bin-posql + @ - mkdir -p ../bin-mysql + @ # - rm -f $(EXE) *.o + +#-------------------------------------------------------------------- +#to manage dependencies +%.d: %.c + @ set -e; rm -f $@; \ + $(CC) -I ../lib -M $(CPPFLAGS) $< > $@.$$$$; \ + sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +sources = \ + chkspf.c \ + feeder.c \ + receiver.c \ + scanner.c \ + sender.c \ + sorter.c \ + +include $(sources:.c=.d) +#-------------------------------------------------------------------- +.PHONY: toremake clean allclean +#-------------------------------------------------------------------- diff --git a/app/chkspf.c b/app/chkspf.c new file mode 100644 index 0000000..7dac2ac --- /dev/null +++ b/app/chkspf.c @@ -0,0 +1,107 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Validation program to check SPF extraction */ +/* library. */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "subafn.h" +#include "unidns.h" +#include "unipar.h" +#include "uniprc.h" +#include "gesspf.h" + +#define CHKSPF "chkspf" //application name + +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to check SPF domain/peerip status */ +/* return the SPF status as an ascii. */ +/* */ +/********************************************************/ +static void checkstatus(char *domain,char *peerip) + +{ +int try; +SPFENU spf; +AFNTYP **afns; + +try=0; +afns=afn_getipnums(peerip); +if (afns!=(AFNTYP **)0) { + for (int i=0;afns[i]!=(AFNTYP *)0;i++) { + spf=spf_getstatus(&try,domain,afns[i]); + (void) fprintf(stdout,"%s\n",spf_spfASCII(spf)); + } + afns=(AFNTYP **)rou_freelist((void **)afns,(genfree_t)afn_freeipnum); + } +} +/* + +*/ +/********************************************************/ +/* */ +/* Main routine */ +/* Return an SPF status according arguments*/ +/* 1 - Domain name */ +/* 2 - IP */ +/* */ +/********************************************************/ +int main(int argc,char *argv[]) + +{ +int status; +int phase; +ARGTYP *params; +_Bool proceed; + +status=0; +params=(ARGTYP *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //checking parameters + if ((params=par_getparams(argc,argv,"d:hr:v"))==(ARGTYP *)0) + phase=999; //no need to go further + break; + case 1 : //check if we have file to scan + if (params->argc!=2) { + (void) fprintf(stderr,"Unable to proceed with test\n"); + (void) fprintf(stderr,"\tthe test pattern number should be 2\n"); + status=-1; + phase=999; + } + break; + case 2 : + (void) rou_modesubrou(true); + (void) rou_setappname(CHKSPF); + (void) prc_preptitle(argc,argv,environ); + foreground=true; + break; + case 3 : //doing main task + (void) checkstatus(params->argv[0],params->argv[1]); + break; + case 4 : //task completed + (void) prc_cleantitle(); + params=par_freeparams(params); + (void) rou_modesubrou(false); + break; + default : //end of task + proceed=false; + break; + } + phase++; + } +(void) exit(status); +} diff --git a/app/chkspf.d b/app/chkspf.d new file mode 100644 index 0000000..6f2e3af --- /dev/null +++ b/app/chkspf.d @@ -0,0 +1,60 @@ +chkspf.o chkspf.d : chkspf.c /usr/include/stdc-predef.h /usr/include/errno.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/stdio.h \ + /usr/include/bits/libc-header-start.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/types/__fpos_t.h \ + /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/stdlib.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/sys/types.h /usr/include/bits/types/clock_t.h \ + /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/byteswap.h \ + /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \ + /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/string.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/strings.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h \ + ../lib/subrou.h /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h ../lib/subafn.h \ + /usr/include/netdb.h /usr/include/netinet/in.h \ + /usr/include/bits/stdint-uintn.h /usr/include/sys/socket.h \ + /usr/include/bits/types/struct_iovec.h /usr/include/bits/socket.h \ + /usr/include/bits/socket_type.h /usr/include/bits/sockaddr.h \ + /usr/include/asm/socket.h /usr/include/asm-generic/socket.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/bits/in.h \ + /usr/include/rpc/netdb.h /usr/include/bits/netdb.h ../lib/unidns.h \ + ../lib/subafn.h ../lib/unipar.h ../lib/uniprc.h ../lib/subrou.h \ + ../lib/gesspf.h ../lib/gesspf.h diff --git a/app/feeder.c b/app/feeder.c new file mode 100644 index 0000000..e5c7fd0 --- /dev/null +++ b/app/feeder.c @@ -0,0 +1,862 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* SMTP protocol feeder. */ +/* Used to transmit data to remote SMTP server. */ +/* */ +/* Format is: */ +/* feeder ip port [file1 file2...] */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "unipar.h" +#include "unieml.h" +#include "devsoc.h" +#include "gestcp.h" + +#define FNAME "feeder" + +#define WRESP 30 //wait 30 sec for SMTP server + //to answer + +static char titre[100]; //test title +static char testname[300]; //test description + +typedef struct { + char *destip; //IP to connect to + char *destport; //Port to connect to + char *srcip; //IP to be used as source + _Bool commented; //feed in comment mode + FILE *datatst; //reference to the data-tst file + SOCPTR *socptr; //connection socket + }FEEDTYP; + +typedef enum { //List of command + cmd_comment, //Test sequence in int/out comment mode + cmd_connect, //Start connection with smtp server + cmd_data, //start the SMTP data sequence + cmd_gotls, //going in tls mode + cmd_orgn, //Change peer IP origin + cmd_restart, //restart connection with remote server + cmd_wait, //delay exchange with remote + cmd_unknown + }CMDTYP; +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to display feeder usage */ +/* */ +/********************************************************/ +static void usage(const char *name) + +{ +(void) fprintf(stderr,"usage:\n "); +(void) fprintf(stderr,"%s\t" + "[-d debug] " + "[-h] " + "remote_name port [filename1 filename2...]\n",name); +(void) fprintf(stderr,"\twhere:\n"); +(void) fprintf(stderr,"\t\t-d level\t: debug level [1-10]\n"); +(void) fprintf(stderr,"\t\t-h\t\t: print this help message\n"); +(void) fprintf(stderr,"\t\t:remote_name, fully qualified domain name\n"); +(void) fprintf(stderr,"\t\t:port, remote acces port to access\n"); +(void) fprintf(stderr,"\t\t:filenames, a set a filename to be feed to remote\n"); +} +/* + +*/ +/********************************************************/ +/* */ +/* Reporting a problem with parsing test */ +/* */ +/********************************************************/ +static void report(int numline,char *line,char *trouble) + + +{ +(void) rou_alert(0,"line %d %s",numline,trouble); +(void) rou_alert(0,"\t'%s'",line); +} +/* +^L +*/ +/************************************************/ +/* */ +/* Send transmission out */ +/* */ +/************************************************/ +static int sendout(SOCPTR *socptr,char *line) + +{ +int taille; + +taille=tcp_write(socptr,line); +taille+=tcp_write(socptr,CRLF); +return taille; +} +/* +^L +*/ +/************************************************/ +/* */ +/* procedure to set feed scan in comment */ +/* mode. */ +/* */ +/************************************************/ +static _Bool setcomment(FEEDTYP *fd,char *action) + +{ +_Bool done; +_Bool flag; + +done=false; +flag=false; +if (strcmp("START",action)==0) + flag=true; +if (flag!=fd->commented) { + fd->commented=flag; + done=true; + } +return done; +} +/* +^L +*/ +/************************************************/ +/* */ +/* procedure to send data to remote SMTP */ +/* server. */ +/* */ +/************************************************/ +static _Bool dosenddata(FEEDTYP *fd,int *numline,char *expected) + +{ +#define OPEP "feeder.c:dosenddata," + +int status; +char *line; +char *action; +int numdata; +char data[300]; +int phase; +_Bool proceed; + +status=false; +line=(char *)0; +action="DATA"; +numdata=0; +(void) strcpy(data,""); +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //Transmit "DATA" to remote + if (sendout(fd->socptr,action)!=(strlen(action)+2)) + phase=999; //Unable to send STARTTLS sequence + break; + case 1 : //Get DATA command status + if (tcp_getline(fd->socptr,WRESP,&line)<0) + phase=999; //Didn't get signon + break; + case 2 : //did we received the Proper "proceed" acknoledge + if (expected==(char *)0) + expected="Nothing?"; + if (strcmp(line,expected)!=0) { + (void) rou_alert(0,"expecting\t'%s'",expected); + (void) rou_alert(0,"found\t\t'%s'",line); + phase=999; //did NOT get proper signon + } + break; + case 3 : // + while (fgets(data,sizeof(data),fd->datatst)!=(char *)0) { + _Bool completed; + + completed=false; + numdata++; + (*numline)++; + (void) eml_removecrlf(data); + if (data[1]!=':') { + (void) rou_alert(0,"%s Unexpected data type <%s> (Bug?)", + OPEP,data); + continue; + } + switch (data[0]) { + case 'D' : //pure data + if (data[2]=='.') { + (void) memmove(data+3,data+2,strlen(data+2)); + } + (void) sendout(fd->socptr,data+2); + break; + case 'C' : //data marker + switch (data[2]) { + case '.' : //end of data marker + if (numdata>1) //could be empty data + (void) sendout(fd->socptr,"."); + completed=true; + break; + case 'T' : //timer data + time_t isnow; + char ed[100]; + + isnow=time((time_t *)0); + (void) snprintf(ed,sizeof(ed),"Date: %s",rou_ascsysstamp(isnow)); + (void) sendout(fd->socptr,ed); + break; + default : //unexpected data marker + (void) rou_alert(0,"%s Unexpected data marker <%s> (Bug?)", + OPEP,data); + break; + } + break; + default : + (void) rou_alert(0,"%s Unexpected data to be send <%s> (Bug?)", + OPEP,data); + break; + } + if (completed==true) { + status=true; + break; //All data sent. + } + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return status; +#undef OPEP +} +/* +^L +*/ +/************************************************/ +/* */ +/* procedure to set the link in TLS mode */ +/* */ +/************************************************/ +static _Bool gomodetls(SOCPTR *socptr) + +{ +#define OPEP "feeder.c:gomodetls," + +_Bool status; +char *got; +char *action; +int phase; +_Bool proceed; + +status=false; +got=(char *)0; +action="starttls"; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"%s JMPDBG phase='%d' status='%d'",OPEP,phase,status); + switch (phase) { + case 0 : //Sending START TLS command + if (sendout(socptr,action)!=(strlen(action)+2)) + phase=999; //Unable to send STARTTLS sequence + break; + case 1 : //Get STARTTLS command status + if (tcp_getline(socptr,WRESP,&got)<=0) + phase=999; //Didn't get signon + break; + case 2 : //did we received the signon + if (got!=(char *)0) { //Always + int code; + + code=0; + (void) sscanf(got,"%d",&code); + if (code!=SIGNON) + phase=999; + got=rou_freestr(got); + } + break; + case 3 : //initiating TLS-Crypted in client mode + if (soc_starttls(socptr,false)==false) + phase=999; + break; + case 4 : //everything is fine SOC in crypted mode + (void) usleep(10000); //sleep 10 millisec + status=true; + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return status; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to connect to SMTP server if NOT YET */ +/* connected */ +/* */ +/********************************************************/ +static _Bool doconnect(FEEDTYP *fd) + +{ +#define OPEP "feeder.c:doconnect" + +_Bool isopen; +int phase; +_Bool proceed; + +isopen=true; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //is the connection really open + if (fd->socptr==(SOCPTR *)0) { + fd->socptr=soc_openfeedsock(pro_smtp,fd->srcip,fd->destip,fd->destport); + if (fd->socptr==(SOCPTR *)0) { + (void) rou_alert(0,"%s Unable to open link to [%s:%s]", + OPEP,fd->destip,fd->destport); + isopen=false; + phase=999; + } + } + break; + case 1 : //is the connect really open + (void) usleep(100000); //let wait form remote disconnect + if (soc_waitforchar(fd->socptr,10*1000)>=0) { + phase=999; //Yes no need to go further + } + break; + case 2 : //the remote just disconnect + fd->socptr=soc_closefeedsock(fd->socptr); //let clean the link + fd->socptr=soc_openfeedsock(pro_smtp,fd->srcip,fd->destip,fd->destport); + if (soc_waitforchar(fd->socptr,10*1000)<0) { + (void) rou_alert(0,"%s Unable to re-open link to [%s:%s]", + OPEP,fd->destip,fd->destport); + isopen=false; + phase=999; + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return isopen; + +#undef OPEP +} +/* +^L +*/ +/************************************************/ +/* */ +/* procedure to to restart link with a */ +/* new source IP. */ +/* */ +/************************************************/ +static _Bool dorestart(FEEDTYP *fd,char *newip) + +{ +_Bool status; + +status=true; +if ((newip!=(char *)0)&&(strlen(newip)>0)) { + fd->srcip=rou_freestr(fd->srcip); + fd->srcip=strdup(newip); + } +fd->socptr=soc_closefeedsock(fd->socptr); +(void) usleep(100000); //wait 10 millisec +fd->socptr=soc_openfeedsock(pro_smtp,fd->srcip,fd->destip,fd->destport); +if (fd->socptr==(SOCPTR *)0) + status=false; +return status; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to execute a command to test SMTP */ +/* protocol. */ +/* */ +/********************************************************/ +static int getcmd(const char *command) + + +{ +static struct { + int code; + const char *cmd; + }cmdavail[]={ + {cmd_comment,"COMMENT"}, + {cmd_connect,"CONNECT"}, + {cmd_data,"DATA"}, + {cmd_gotls,"GOTLS"}, + {cmd_orgn,"ORGN:"}, + {cmd_restart,"RESTART"}, + {cmd_wait,"WAIT"}, + {cmd_unknown,(const char *)0} + }; + +int code; + +code=cmd_unknown; +for (int i=0;cmdavail[i].cmd!=(const char *)0;i++) { + if (strcasecmp(cmdavail[i].cmd,command)==0) { + code=cmdavail[i].code; + break; //Code found + } + } +return code; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to execute a command to test SMTP */ +/* protocol. */ +/* */ +/********************************************************/ +static _Bool docommand(FEEDTYP *fd,int *numline,char *line) + +{ +#define OPEP "docommand" + +_Bool status; +char *param; + +status=true; +if ((param=strchr(line,' '))!=(char *)0) { + *param='\000'; //cut line + param++; //pointer on parameter + } +switch (getcmd(line)) { + case cmd_comment : //detect comment flag + if (setcomment(fd,param)==false) + (void) report(*numline,line,"Unable to set comment mode"); + break; + case cmd_connect : //start link connection + if (doconnect(fd)==false) { + (void) report(*numline,line,"Unable connect!"); + status=false; + } + break; + case cmd_data : //sending email content to remote + if ((status=dosenddata(fd,numline,param))==false) + (void) report(*numline,line,"Unable to fully send data"); + break; + case cmd_gotls : //GOTLS + if ((status=gomodetls(fd->socptr))==false) + (void) report(*numline,line,"Unable to set TLS mode"); + break; + case cmd_orgn : //send command to override client IP + if (param!=(char *)0) { + char cmd[100]; + + (void) snprintf(cmd,sizeof(cmd)-1,"%s %s",line,param); + (void) sendout(fd->socptr,cmd); + } + else { + (void) report(*numline,line,"Missing new PEER IP value"); + status=false; + } + break; + case cmd_restart : //restart link + if ((status=dorestart(fd,(char *)0))==false) + (void) report(*numline,line,"Unable to restart feed socket!"); + break; + case cmd_wait : //SLEEP mode + if (param!=(char *)0) + (void) sleep(atoi(param)); + else { + (void) report(*numline,line,"Missing 'seconds' parameters"); + status=false; + } + break; + case cmd_unknown : + default : + (void) report(*numline,line,"Unknown command"); + status=false; + break; + } +return status; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to compare incoming data with expected*/ +/* */ +/********************************************************/ +static _Bool doincoming(SOCPTR *socptr,int numline,char *line) + +{ +#define OPEP "feeder.c:doincoming" +#define STRETC "..." + +_Bool status; +int got; +char *received; +int tocheck; +int phase; +_Bool proceed; + +status=false; +got=0; +received=(char *)0; +tocheck=strlen(line); +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 "..." sequence at the end + if (tocheck>0) { + char *ptr; + + if ((ptr=strstr(line,STRETC))!=(char *)0) { + if (strlen(ptr)==strlen(STRETC)) { + tocheck-=strlen(STRETC); + } + } + } + break; + case 1 : //waiting for a line with CRLF + received=(char *)0; + got=tcp_getline(socptr,WAITRMT,&received); + (void) rou_alert(3,"%s, received=<%s>",OPEP,received); + switch (got) { + case 0 : //Reading timeout + (void) rou_alert(0,"Unable to receive line in due time"); + phase=999; //No need to go further + break; + case -1 : //signal received + (void) rou_alert(0,"A Signal was received"); + phase=999; //No need to go further + break; + case -2 : //remote is disconnected + received=rou_freestr(received); + received=strdup("Disconnected"); + break; + default : //got a good line + break; + } + break; + case 2 : //get available character + if (strcmp(line,received)==0) + phase++; //ligne is equal, good + else { //small check? + if ((tocheck OK!",line); + status=true; + break; + default : //SAFE Guard + received=rou_freestr(received); + proceed=false; + break; + } + phase++; + } +return status; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Scanning one line from test file */ +/* */ +/********************************************************/ +static _Bool scanline(FEEDTYP *fd,int *numline,char *line) + +{ +#define OPEP "feeder.c:scanline" + +_Bool status; +char action; +int phase; +_Bool proceed; + +status=true; +action='\000'; +phase=0; +proceed=true; +(void) rou_alert(3,"%s line=<%s>",OPEP,line); +while (proceed==true) { + switch (phase) { + case 0 : //removing first space + while ((line[0]==' ')||(line[0]=='\t')) + (void) memmove(line,line+1,(strlen(line+1)+1)); + if (line[0]=='#') { //line is a comment. + proceed=false;; //discarding line + (*numline)++; + } + break; + case 1 : //checking if test file format is OK + if (line[1]!=':') { + (void) report(*numline,line,"Malformed test data"); + status=false; + proceed=false; //discarding line + } + action=line[0]; + line+=2; + break; + case 2 : //check open version action + switch (action) { + case 'R' : //wait Receiving line + case 'S' : //Sending line + break; + default : //Nothing to do + break; + } + break; + case 3 : //discarding comment + switch (action) { + case 'C' : //command to execute + status=docommand(fd,numline,line); + break; + case 'R' : //Receiving data + status=doincoming(fd->socptr,*numline,line); + break; + case 'S' : //sending data + (void) sendout(fd->socptr,line); + break; + case 'T' : //Get the test titre + (void) memset(testname,'\000',sizeof(testname)); + status=snprintf(testname,sizeof(testname)-1,"%s",line); + break; + default : //Unexpected + line-=2; + (void) report(*numline,line,"Unexpected directive"); + status=false; + break; + } + (*numline)++; + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return status; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Scanning data file. */ +/* */ +/********************************************************/ +static _Bool scanonefile(FEEDTYP *fd,const char *filename) + +{ +_Bool status; +int numline; +char line[3000]; +int phase; +_Bool proceed; + +status=false; +(void) strcpy(testname,""); +numline=1; +(void) strcpy(line,""); +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG scanfile phase='%d'",phase); + switch (phase) { + case 0 : //checking parameters + (void) rou_alert(0,"Scanning file <%s>",filename); + if (filename!=(char *)0) { + const char *ptr; + + if ((ptr=strrchr(filename,'/'))!=(const char *)0) + ptr++; + else + ptr=filename; + (void) snprintf(titre,sizeof(titre),"%s:",ptr); + } + if ((fd->datatst=fopen(filename,"r"))==(FILE *)0) { + (void) rou_alert(0,"Unable to open file <%s> (error=<%s>", + filename,strerror(errno)); + proceed=false; + } + break; + case 1 : //Opening the socket (obsolete) + break; + case 2 : //reading line; + while (fgets(line,sizeof(line),fd->datatst)!=(char *)0) { + char *ptr; + + (void) rou_alert(5,"%s num='%02d' <%s>","feeder",numline,line); + while ((ptr=strrchr(line,'\n'))!=(char *)0) + *ptr='\000'; + if ((fd->commented==true)&&(strncmp(line,"C:",2)!=0)) { + numline++; + continue; + } + if (scanline(fd,&numline,line)==false) { + phase=999; //Trouble trouble exiting + break; + } + } + break; + case 3 : //scanning went well + status=true; + break; + default : //SAFE Guard + fd->socptr=soc_closefeedsock(fd->socptr); + (void) fclose(fd->datatst); + fd->datatst=(FILE *)0; + proceed=false; + break; + } + phase++; + } +if (status==true) + (void) rou_alert(2,"Scanning file <%s> was completed OK",filename); +return status; +} +/********************************************************/ +/* */ +/* procedure to scan all files */ +/* */ +/********************************************************/ +static int scanallfiles(int argc,char *argv[]) + +{ +int numfile; +FEEDTYP *feed; + +int next; +int phase; + +numfile=0; +feed=(FEEDTYP *)calloc(1,sizeof(FEEDTYP)); +feed->srcip=strdup(srcip); +feed->destip=strdup(argv[0]); +feed->destport=strdup(argv[1]); +next=2; +phase=0; +while (nextdestport=rou_freestr(feed->destport); +feed->destip=rou_freestr(feed->destip); +feed->srcip=rou_freestr(feed->srcip); +(void) free(feed); +return numfile; +} +/* + +*/ +/********************************************************/ +/* */ +/* Main routine */ +/* Start a channel to a remote ip.port */ +/* read file and transmit contecnts to */ +/* remote SMTP server. */ +/* */ +/********************************************************/ +int main(int argc,char *argv[]) + +{ +int status; +ARGTYP *params; +int numfile; +int phase; +_Bool proceed; + +status=0; +params=(ARGTYP *)0; +foreground=true; +numfile=0; +phase=0; +proceed=true; +while (proceed==true) { + //(void) fprintf(stdout,"JMPDBG main phase='%d'\n",phase); + switch (phase) { + case 0 : //checking parameters + if ((params=par_getparams(argc,argv,"c:d:fhi:r:v"))==(ARGTYP *)0) { + proceed=false; //no need to go further + } + break; + case 1 : //initialising process + if (params->argc<2) { + (void) fprintf(stdout,"Error, missing! remote_name? port?\n"); + (void) usage("feeder"); + phase=999; //can not go further + } + break; + case 2 : //opening remote channel + (void) rou_loadconfig(config,true); + (void) openlog("feeder",LOG_NDELAY|LOG_PID,LOG_DAEMON); + numfile=scanallfiles(params->argc,params->argv); + if (numfile==(params->argc-2)) + (void) rou_alert(0,"%d file successfully submitted to <%s.%s>", + numfile,params->argv[0],params->argv[1]); + (void) closelog(); + break; + default : //end of task + params=par_freeparams(params); + (void) rou_loadconfig(config,false); + proceed=false; + break; + } + phase++; + } +(void) exit(status); +} diff --git a/app/feeder.d b/app/feeder.d new file mode 100644 index 0000000..291315d --- /dev/null +++ b/app/feeder.d @@ -0,0 +1,119 @@ +feeder.o feeder.d : feeder.c /usr/include/stdc-predef.h /usr/include/errno.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/signal.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/signum-generic.h \ + /usr/include/bits/signum-arch.h /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timespec.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/types/stack_t.h /usr/include/sys/ucontext.h \ + /usr/include/bits/sigstack.h /usr/include/bits/sigstksz.h \ + /usr/include/bits/ss_flags.h /usr/include/bits/types/struct_sigstack.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h /usr/include/stdlib.h \ + /usr/include/bits/libc-header-start.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/sys/types.h \ + /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/byteswap.h \ + /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/struct_timeval.h \ + /usr/include/alloca.h /usr/include/bits/stdlib-float.h \ + /usr/include/stdio.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/string.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/strings.h /usr/include/syslog.h /usr/include/sys/syslog.h \ + /usr/include/bits/syslog-path.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h \ + ../lib/subrou.h /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h ../lib/unipar.h \ + ../lib/unieml.h ../lib/subafn.h /usr/include/netdb.h \ + /usr/include/netinet/in.h /usr/include/bits/stdint-uintn.h \ + /usr/include/sys/socket.h /usr/include/bits/types/struct_iovec.h \ + /usr/include/bits/socket.h /usr/include/bits/socket_type.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm-generic/socket.h /usr/include/asm/sockios.h \ + /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/bits/in.h \ + /usr/include/rpc/netdb.h /usr/include/bits/netdb.h ../lib/devsoc.h \ + ../lib/unitls.h /usr/include/openssl/ssl.h /usr/include/openssl/macros.h \ + /usr/include/openssl/opensslconf.h /usr/include/openssl/configuration.h \ + /usr/include/openssl/opensslv.h /usr/include/openssl/e_os2.h \ + /usr/include/inttypes.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdint.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/bits/stdint-least.h /usr/include/openssl/e_ostime.h \ + /usr/include/sys/time.h /usr/include/openssl/comp.h \ + /usr/include/openssl/crypto.h /usr/include/openssl/safestack.h \ + /usr/include/openssl/stack.h /usr/include/openssl/types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/limits.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h /usr/include/bits/posix2_lim.h \ + /usr/include/openssl/cryptoerr.h /usr/include/openssl/symhacks.h \ + /usr/include/openssl/cryptoerr_legacy.h /usr/include/openssl/core.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include-fixed/pthread.h \ + /usr/include/sched.h /usr/include/bits/sched.h \ + /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \ + /usr/include/bits/setjmp.h \ + /usr/include/bits/types/struct___jmp_buf_tag.h \ + /usr/include/openssl/comperr.h /usr/include/openssl/bio.h \ + /usr/include/openssl/bioerr.h /usr/include/openssl/x509.h \ + /usr/include/openssl/buffer.h /usr/include/openssl/buffererr.h \ + /usr/include/openssl/evp.h /usr/include/openssl/core_dispatch.h \ + /usr/include/openssl/indicator.h /usr/include/openssl/params.h \ + /usr/include/openssl/bn.h /usr/include/openssl/bnerr.h \ + /usr/include/openssl/evperr.h /usr/include/openssl/objects.h \ + /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \ + /usr/include/openssl/asn1err.h /usr/include/openssl/objectserr.h \ + /usr/include/openssl/ec.h /usr/include/openssl/ecerr.h \ + /usr/include/openssl/rsa.h /usr/include/openssl/rsaerr.h \ + /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \ + /usr/include/openssl/dherr.h /usr/include/openssl/dsaerr.h \ + /usr/include/openssl/sha.h /usr/include/openssl/x509err.h \ + /usr/include/openssl/x509_vfy.h /usr/include/openssl/lhash.h \ + /usr/include/openssl/pkcs7.h /usr/include/openssl/pkcs7err.h \ + /usr/include/openssl/http.h /usr/include/openssl/conf.h \ + /usr/include/openssl/conferr.h /usr/include/openssl/conftypes.h \ + /usr/include/openssl/pem.h /usr/include/openssl/pemerr.h \ + /usr/include/openssl/hmac.h /usr/include/openssl/async.h \ + /usr/include/openssl/asyncerr.h /usr/include/openssl/ct.h \ + /usr/include/openssl/cterr.h /usr/include/openssl/sslerr.h \ + /usr/include/openssl/sslerr_legacy.h /usr/include/openssl/prov_ssl.h \ + /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \ + /usr/include/openssl/tls1.h /usr/include/openssl/dtls1.h \ + /usr/include/openssl/srtp.h /usr/include/openssl/quic.h ../lib/gestcp.h \ + ../lib/subrou.h ../lib/unidns.h ../lib/devlog.h ../lib/devsoc.h diff --git a/app/receiver.c b/app/receiver.c new file mode 100644 index 0000000..f126022 --- /dev/null +++ b/app/receiver.c @@ -0,0 +1,110 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Email Receiver */ +/* SMTP Daemon dedicated to receive Email. */ +/* */ +/********************************************************/ +#include +#include +#include +#include + +#include "subrou.h" +#include "unipar.h" +#include "uniprc.h" +#include "unisig.h" +#include "unitls.h" +#include "devsql.h" +#include "gessql.h" +#include "modrec.h" + +#define RECNAME "receiver" + +//port listening format is "IP:PORT NUMBER:num iteration" +/* + +*/ +/********************************************************/ +/* */ +/* Main routine */ +/* Start multiple SMTP daemon and make */ +/* sure there always ready to answer to */ +/* SMTP request. */ +/* */ +/********************************************************/ +int main(int argc,char *argv[]) + +{ +int status; +ARGTYP *params; +SQLPTR *sqlptr; +int phase; +_Bool proceed; + +status=0; +params=(ARGTYP *)0; +sqlptr=(SQLPTR *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //checking parameters + if ((params=par_getparams(argc,argv,"c:d:D:fhr:v"))==(ARGTYP *)0) { + phase=999; //no need to go further + } + break; + case 1 : //initialising process + //changing the working ID if started as root + if (foreground==true) + (void) fprintf(stdout,"Running application in foreground\n"); + (void) prc_preptitle(argc,argv,environ); + (void) rou_setappname(RECNAME); + (void) rou_modesubrou(true); + (void) prc_chgid(argv[0]); + (void) rou_loadconfig(config,true); + (void) prc_modeuniprc(true); + (void) sig_modeunisig(true); + (void) tls_modeunitls(true); + (void) sig_trapsignal(true,sig_alrm); + break; + case 2 : //sett lock + if (foreground==false) { + if (prc_divedivedive()!=0) + phase=999; //direct exit + } + break; + case 3 : //opening data base + if ((sqlptr=sql_opensql())==(SQLPTR *)0) { + (void) fprintf(stdout,"Unable to reach database server (aborting!)\n"); + phase=999; //Aborting + } + break; + case 4 : //make sur link are all zero in DB + (void) sql_droplinks(sqlptr); + sqlptr=sql_closesql(sqlptr); + break; + case 5 : //doing main task + if (prc_locking(appname,true,5)==false) + phase=999; //Trouble trouble + break; + case 6 : //doing main task + (void) rec_handlesmtp(params->argc,params->argv); + (void) prc_locking(appname,false,1); + break; + default : //end of task + params=par_freeparams(params); + (void) rou_loadconfig(config,false); + (void) sig_trapsignal(false,sig_alrm); + (void) tls_modeunitls(false); + (void) sig_modeunisig(false); + (void) prc_modeuniprc(false); + (void) rou_modesubrou(false); + (void) prc_cleantitle(); + proceed=false; + break; + } + phase++; + } +(void) exit(status); +} diff --git a/app/receiver.d b/app/receiver.d new file mode 100644 index 0000000..57ba83d --- /dev/null +++ b/app/receiver.d @@ -0,0 +1,116 @@ +receiver.o receiver.d : receiver.c /usr/include/stdc-predef.h /usr/include/signal.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/signum-generic.h \ + /usr/include/bits/signum-arch.h /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timespec.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/types/stack_t.h /usr/include/sys/ucontext.h \ + /usr/include/bits/sigstack.h /usr/include/bits/sigstksz.h \ + /usr/include/bits/ss_flags.h /usr/include/bits/types/struct_sigstack.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h /usr/include/stdlib.h \ + /usr/include/bits/libc-header-start.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/sys/types.h \ + /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/byteswap.h \ + /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/struct_timeval.h \ + /usr/include/alloca.h /usr/include/bits/stdlib-float.h \ + /usr/include/stdio.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h \ + ../lib/subrou.h /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + ../lib/unipar.h ../lib/uniprc.h ../lib/subrou.h ../lib/unisig.h \ + ../lib/unitls.h /usr/include/openssl/ssl.h /usr/include/openssl/macros.h \ + /usr/include/openssl/opensslconf.h /usr/include/openssl/configuration.h \ + /usr/include/openssl/opensslv.h /usr/include/openssl/e_os2.h \ + /usr/include/inttypes.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdint.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/bits/stdint-uintn.h /usr/include/bits/stdint-least.h \ + /usr/include/openssl/e_ostime.h /usr/include/sys/time.h \ + /usr/include/openssl/comp.h /usr/include/openssl/crypto.h \ + /usr/include/openssl/safestack.h /usr/include/openssl/stack.h \ + /usr/include/openssl/types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/limits.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h /usr/include/bits/posix2_lim.h \ + /usr/include/openssl/cryptoerr.h /usr/include/openssl/symhacks.h \ + /usr/include/openssl/cryptoerr_legacy.h /usr/include/openssl/core.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include-fixed/pthread.h \ + /usr/include/sched.h /usr/include/bits/sched.h \ + /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \ + /usr/include/bits/setjmp.h \ + /usr/include/bits/types/struct___jmp_buf_tag.h \ + /usr/include/openssl/comperr.h /usr/include/openssl/bio.h \ + /usr/include/openssl/bioerr.h /usr/include/openssl/x509.h \ + /usr/include/openssl/buffer.h /usr/include/openssl/buffererr.h \ + /usr/include/openssl/evp.h /usr/include/openssl/core_dispatch.h \ + /usr/include/openssl/indicator.h /usr/include/openssl/params.h \ + /usr/include/openssl/bn.h /usr/include/openssl/bnerr.h \ + /usr/include/openssl/evperr.h /usr/include/openssl/objects.h \ + /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \ + /usr/include/openssl/asn1err.h /usr/include/openssl/objectserr.h \ + /usr/include/openssl/ec.h /usr/include/string.h /usr/include/strings.h \ + /usr/include/openssl/ecerr.h /usr/include/openssl/rsa.h \ + /usr/include/openssl/rsaerr.h /usr/include/openssl/dsa.h \ + /usr/include/openssl/dh.h /usr/include/openssl/dherr.h \ + /usr/include/openssl/dsaerr.h /usr/include/openssl/sha.h \ + /usr/include/openssl/x509err.h /usr/include/openssl/x509_vfy.h \ + /usr/include/openssl/lhash.h /usr/include/openssl/pkcs7.h \ + /usr/include/openssl/pkcs7err.h /usr/include/openssl/http.h \ + /usr/include/openssl/conf.h /usr/include/openssl/conferr.h \ + /usr/include/openssl/conftypes.h /usr/include/openssl/pem.h \ + /usr/include/openssl/pemerr.h /usr/include/openssl/hmac.h \ + /usr/include/openssl/async.h /usr/include/openssl/asyncerr.h \ + /usr/include/openssl/ct.h /usr/include/openssl/cterr.h \ + /usr/include/openssl/sslerr.h /usr/include/openssl/sslerr_legacy.h \ + /usr/include/openssl/prov_ssl.h /usr/include/openssl/ssl2.h \ + /usr/include/openssl/ssl3.h /usr/include/openssl/tls1.h \ + /usr/include/openssl/dtls1.h /usr/include/openssl/srtp.h \ + /usr/include/openssl/quic.h ../lib/subafn.h /usr/include/netdb.h \ + /usr/include/netinet/in.h /usr/include/sys/socket.h \ + /usr/include/bits/types/struct_iovec.h /usr/include/bits/socket.h \ + /usr/include/bits/socket_type.h /usr/include/bits/sockaddr.h \ + /usr/include/asm/socket.h /usr/include/asm-generic/socket.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/bits/in.h \ + /usr/include/rpc/netdb.h /usr/include/bits/netdb.h ../lib/devsql.h \ + ../lib/unisql.h ../lib/gessql.h ../lib/unieml.h ../lib/devsql.h \ + ../lib/modrec.h diff --git a/app/scanner.c b/app/scanner.c new file mode 100644 index 0000000..a9a566a --- /dev/null +++ b/app/scanner.c @@ -0,0 +1,398 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Handle all remote IP credibility level */ +/* By scanning database for new entry within */ +/* database tables remotes and try to establish */ +/* remote server "credibility" according remote IP.*/ +/* */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include + +#include "devsql.h" +#include "devlog.h" +#include "gessql.h" +#include "unidns.h" +#include "unipar.h" +#include "uniprc.h" +#include "unisig.h" +#include "subafn.h" +#include "subrou.h" + +#define SCANNER "scanner" //application name + +typedef struct { + LOGPTR *logptr; //session log refrence pointer + SQLPTR *sqlptr; //sesion database reference pointer + }SCATYP; +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to check the remote ip credibility */ +/* remote ip credibility. */ +/* */ +/********************************************************/ +static void check_credibility(SCATYP *scanref,BLKTYP **dnsblk,int num,char *rmtip) + +{ +#define OPEP "scanner.c:check_credibilty," + +SRVTYP *srv; +AFNTYP *afn; +char *reversip; +int phase; +_Bool proceed; + +srv=(SRVTYP *)0; +afn=(AFNTYP *)0; +reversip=(char *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //get the remoteip AFN + if ((afn=afn_getoneipnum(rmtip))==(AFNTYP *)0) { + (void) rou_alert(0,"%s Unable to get afn data for remote <%s> (WRONG IP?)", + OPEP,rmtip); + (void) sql_mngremote(scanref->sqlptr,sql_delete,rmtip,&srv); + phase=999; //Trouble trouble + } + break; + case 1 : //loading rmtip record + if (sql_mngremote(scanref->sqlptr,sql_select,rmtip,&srv)==false) { + (void) rou_alert(0,"%s Unable to get remote <%s> data (database?)", + OPEP,rmtip); + phase=999; //Trouble trouble + } + break; + case 2 : //getting the reverss-address + reversip=afn_reversipnum(afn); + srv->reverse=rou_freestr(srv->reverse); + srv->reverse=dns_get_reverse_addr(reversip); + break; + case 3 : //updating record according blacklisting + srv->lastscan=time((time_t *)0); + if (dnsblk!=(BLKTYP **)0) { + int delta; + char *bank; + + delta=0; + bank=(char *)0; + while (*dnsblk!=(BLKTYP *)0) { + char *report; + char *listed; + char cst[100]; + + report=(char *)0; + listed=dns_is_blacklisted(*dnsblk,reversip); + (void) snprintf(cst,sizeof(cst),"IP[%02d]: %s\t",num,rmtip); + if (listed!=(char *)0) { + delta+=(*dnsblk)->delta; + (void) rou_asprintf(&report,"%s%s",cst,listed); + if (srv->listing==(char *)0) + srv->listing=strdup(listed); + } + else + (void) rou_asprintf(&report,"%s%s -> NOT listed",cst, + (*dnsblk)->sitename); + (void) log_fprintlog(scanref->logptr,true,report); + report=rou_freestr(report); + listed=rou_freestr(listed); + dnsblk++; + } + srv->credit+=delta; + bank=eml_showcredit(rmtip,srv->reverse,delta,srv->credit); + (void) log_fprintlog(scanref->logptr,true,"IP[%02d]: %s",num,bank); + (void) log_fprintlog(scanref->logptr,false,""); + bank=rou_freestr(bank); + } + break; + case 4 : //updating record + if (sql_mngremote(scanref->sqlptr,sql_update,rmtip,&srv)==false) { + (void) rou_alert(0,"%s Unable to update remote <%s> data (database?)", + OPEP,rmtip); + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +srv=sql_freesrv(srv); +reversip=rou_freestr(reversip); +afn=afn_freeipnum(afn); + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to load the list of dnsbls server */ +/* remote ip credibility. */ +/* */ +/********************************************************/ +static BLKTYP **load_dnsbls() + +{ +#define OPEP "scanner.c:load_dnsbls," + +const char *blcklist="BLACKLISTER"; + +BLKTYP **dnsblk; +FILE *blkfile; +const char *filename; +int phase; +_Bool proceed; + +dnsblk=(BLKTYP **)0; +blkfile=(FILE *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Getting dnsbls server list filename + if ((filename=getenv(blcklist))==(char *)0) { + (void) rou_alert(0,"%s <%s> env variable missing (config?!)", + OPEP,blcklist); + phase=999; //no need to go further + } + break; + case 1 : //opening the file + if (filename!=(char *)0) { //always + char *fullpath; + + fullpath=rou_apppath(filename); + if ((blkfile=fopen(fullpath,"r"))==(FILE *)0) { + (void) rou_alert(0,"%s Unable to open file <%s> (error=<%s>)", + OPEP,fullpath,strerror(errno)); + phase=999; //trouble trouble + } + fullpath=rou_freestr(fullpath); + } + break; + case 2 : //scaning file + if (blkfile!=(FILE *)0) { //always + char line[300]; + + while (fgets(line,sizeof(line)-1,blkfile)!=(char *)0) { + (void) rou_clean_conf_line(line); + dnsblk=dns_addblklist(dnsblk,line); + } + (void) fclose(blkfile); + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return dnsblk; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to check database and check new */ +/* remote ip credibility. */ +/* */ +/********************************************************/ +static void doscanning(int frequency) + +{ +#define OPEP "scanner.c:doscanning," + +unsigned long cycle; +SCATYP scanref; +BLKTYP **dnsblk; +char **rmtip; +int delay; +int phase; +_Bool proceed; + +cycle=0; +(void) memset(&scanref,'\000',sizeof(scanref)); +dnsblk=load_dnsbls(); +rmtip=(char **)0; +delay=60; //60 second sleeping time +if (debug>0) + delay/=10; +phase=0; +proceed=(dnsblk!=(BLKTYP **)0); +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //locking access + if (prc_locking(appname,true,5)==false) { + (void) rou_alert(0,"%s Unable to lock %s exclusif acccess (system?)", + OPEP,appname); + proceed=false; + } + break; + case 1 : //check about signal + cycle++; + (void) prc_settitle("%s:%s, sleeping mode (cycle=%08d)", + APPNAME,appname,cycle); + (void) sleep(delay); + break; + case 2 : //double check signal + if ((hangup==true)||((reload==true))) { + (void) rou_alert(0,"%s got hangup or reload signal",OPEP); + phase=999; + } + break; + case 3 : //refreshing the dnsbls list + if ((cycle%100)==0) { + dnsblk=(BLKTYP **)rou_freelist((void **)dnsblk,(genfree_t)dns_freeblk); + dnsblk=load_dnsbls(); + } + proceed=(dnsblk!=(BLKTYP **)0); + break; + case 4 : //opening database + if ((scanref.sqlptr=sql_opensql())==(SQLPTR *)0) { + (void) rou_alert(0,"%s Unable to open database (Config?)",OPEP); + phase=999; //Trouble trouble + } + break; + case 5 : //check for new entry + if ((rmtip=sql_getnewrmtip(scanref.sqlptr,frequency))==(char **)0) { + scanref.sqlptr=sql_closesql(scanref.sqlptr); + phase=0; //nothing to be done + } + break; + case 6 : { //opening log + char *sessid; + int numip; + char cmt[200]; + + sessid=eml_getmainsesid(); + numip=rou_nbrlist((void **)rmtip); + (void) snprintf(cmt,sizeof(cmt),"%d remote IP to scan",numip); + if ((scanref.logptr=log_openlog(sessid,cmt))==(LOGPTR *)0) { + (void) rou_alert(0,"%s Unable to open log file (Bug?)",OPEP); + rmtip=(char **)rou_freelist((void **)rmtip,(genfree_t)rou_freestr); + phase=999; + } + sessid=rou_freestr(sessid); + } + break; + case 7 : //check entries + for (int i=0;rmtip[i]!=(char *)0;i++) { + (void) check_credibility(&scanref,dnsblk,i+1,rmtip[i]); + if ((hangup==true)||((reload==true))) + break; //No need to check other remote + } + rmtip=(char **)rou_freelist((void **)rmtip,(genfree_t)rou_freestr); + break; + case 8 : //updating logs + if (scanref.logptr!=(LOGPTR *)0) { + long debut; + long fin; + + scanref.logptr=log_closelog(scanref.logptr,&debut,&fin); + } + break; + case 9 : //let continue + scanref.sqlptr=sql_closesql(scanref.sqlptr); + if (foreground==false) + phase=1; //looping quickly to do next batch + break; + default : //SAFE Guard + (void) prc_locking(appname,false,1); + proceed=false; + break; + } + phase++; + } +dnsblk=(BLKTYP **)rou_freelist((void **)dnsblk,(genfree_t)dns_freeblk); + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Main routine */ +/* Start a channel to a remote ip.port */ +/* read file and transmit contecnts to */ +/* remote SMTP server. */ +/* */ +/********************************************************/ +int main(int argc,char *argv[]) + +{ +#define OPEP "scanner.c:main," +#ifdef MODEDEBUG +#define DOITAGAIN -(60*10) //10 minutes in seconds +#else +#define DOITAGAIN -(3600*24) //1 day in seconds +#endif + +int status; +ARGTYP *params; +int phase; +_Bool proceed; + +status=0; +params=(ARGTYP *)0; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //checking parameters + if ((params=par_getparams(argc,argv,"c:d:D:fhi:r:v"))==(ARGTYP *)0) { + proceed=false; //no need to go further + } + break; + case 1 : //Preparing scan + (void) prc_preptitle(argc,argv,environ); + (void) rou_setappname(SCANNER); + (void) rou_modesubrou(true); + (void) prc_chgid(argv[0]); + (void) sig_modeunisig(true); + (void) sig_trapsignal(true,sig_alrm); + (void) rou_loadconfig(config,true); + break; + case 2 : //checking if we need to go background + if (foreground==false) { + if (prc_divedivedive()!=0) + phase=999; //direct exit + } + break; + case 3 : //do program main purpose + (void) doscanning(DOITAGAIN); + break; + default : //end of task + params=par_freeparams(params); + (void) rou_loadconfig(config,false); + (void) sig_trapsignal(false,sig_alrm); + (void) sig_modeunisig(false); + (void) rou_modesubrou(false); + (void) prc_cleantitle(); + (void) closelog(); + proceed=false; + break; + } + phase++; + } +(void) exit(status); + +#undef TSLEEP +#undef OPEP +} diff --git a/app/scanner.d b/app/scanner.d new file mode 100644 index 0000000..617fd51 --- /dev/null +++ b/app/scanner.d @@ -0,0 +1,76 @@ +scanner.o scanner.d : scanner.c /usr/include/stdc-predef.h /usr/include/dirent.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/dirent.h \ + /usr/include/bits/posix1_lim.h /usr/include/bits/local_lim.h \ + /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/dirent_ext.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/stdlib.h \ + /usr/include/bits/libc-header-start.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/sys/types.h \ + /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/time_t.h /usr/include/bits/types/timer_t.h \ + /usr/include/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/endianness.h \ + /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/string.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/strings.h /usr/include/syslog.h /usr/include/sys/syslog.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/syslog-path.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h \ + ../lib/devsql.h ../lib/unisql.h ../lib/devlog.h /usr/include/stdio.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h ../lib/gessql.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + ../lib/unieml.h ../lib/subafn.h /usr/include/netdb.h \ + /usr/include/netinet/in.h /usr/include/bits/stdint-uintn.h \ + /usr/include/sys/socket.h /usr/include/bits/types/struct_iovec.h \ + /usr/include/bits/socket.h /usr/include/bits/socket_type.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm-generic/socket.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h /usr/include/asm/posix_types.h \ + /usr/include/asm/posix_types_64.h /usr/include/asm-generic/posix_types.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/bits/in.h \ + /usr/include/rpc/netdb.h /usr/include/bits/netdb.h ../lib/devsql.h \ + ../lib/unidns.h ../lib/unipar.h ../lib/uniprc.h ../lib/subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h ../lib/unisig.h \ + /usr/include/signal.h /usr/include/bits/signum-generic.h \ + /usr/include/bits/signum-arch.h /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h /usr/include/bits/types/stack_t.h \ + /usr/include/sys/ucontext.h /usr/include/bits/sigstack.h \ + /usr/include/bits/sigstksz.h /usr/include/bits/ss_flags.h \ + /usr/include/bits/types/struct_sigstack.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h ../lib/subafn.h ../lib/subrou.h diff --git a/app/sender.c b/app/sender.c new file mode 100644 index 0000000..c519459 --- /dev/null +++ b/app/sender.c @@ -0,0 +1,373 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* SMTP protocol sender. */ +/* Take a a file with todo email to send. */ +/* */ +/* Format is: */ +/* sender [trans1 trabs2...] */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "unieml.h" +#include "unipar.h" +#include "uniprc.h" +#include "unisig.h" +#include "geseml.h" +#include "gessql.h" +#include "lvleml.h" + +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to update the database with respond */ +/* Record associated with TRA. */ +/* Return the number of record stored within the */ +/* database. */ +/* */ +/********************************************************/ +static int update_tradb(TRATYP **tra) + +{ +#define OPEP "geseml.c:eml_update_tradb," + +int num; + +num=0; +if (tra!=(TRATYP **)0) { + SQLPTR *sqlptr; + int phase; + _Bool proceed; + + sqlptr=(SQLPTR *)0; + phase=0; + proceed=(*tra!=(TRATYP *)0); + while (proceed==true) { + switch (phase) { + case 0 : //opening the database + if ((sqlptr=sql_opensql())==(SQLPTR *)0) { + (void) rou_alert(0,"%s Unable to open database (system?)",OPEP); + phase=999; + } + break; + case 1 : //checking all transation + (void) sql_update_tradb(sqlptr,tra); + break; + case 2 : //closing the database + sqlptr=sql_closesql(sqlptr); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } + } +return num; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to dispatch email */ +/* */ +/********************************************************/ +static _Bool dispatcher(TRATYP **tra) + +{ +#define OPEP "sender.c:dispatcher," +_Bool status; + +status=true; +if (tra!=(TRATYP **)0) { + switch ((*tra)->code) { + case 'L' : //local delivery + (void) eml_local_email(tra); + break; + case 'R' : //Remote delivery + (void) eml_remote_email(tra); + break; + case 'W' : //Remote delivery + (void) eml_rebounce_email(*tra); + break; + default : + (void) rou_alert(0,"%s unexpected code '%c'",OPEP,(*tra)->code); + status=false; + break; + } + } +return status; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to scan all files */ +/* */ +/********************************************************/ +static _Bool scantodo(char *fname) + +{ +#define OPEP "sender.c:scantodo," + +_Bool status; +FILE *qfile; +TRATYP **tra; +int phase; +_Bool proceed; + +status=false; +qfile=(FILE *)0; +tra=(TRATYP **)0; +phase=0; +proceed=true; +while (proceed==true) { + //(void) fprintf(stdout,"%s JMPDBG phase='%d'\n",OPEP,phase); + switch (phase) { + case 0 : //Getting the list of file + if (eml_renameqfile(fname,EXTODO,EXDOING)==false) { + (void) rou_alert(0,"%s Unable to rename file <%s.%s>",OPEP,fname,EXDOING); + phase=999; //No need to go further + } + break; + case 1 : //Building the "trans" list + if ((qfile=eml_openqfile(fname,EXDOING))==(FILE *)0) { + (void) rou_alert(0,"%s Unable to open file <%s.%s>",OPEP,fname,EXDOING); + phase=999; //No need to go further + } + break; + case 2 : //reading the todo file + tra=eml_scanqfile(tra,qfile); + if (tra==(TRATYP **)0) { //No record found + (void) rou_alert(0,"%s No transport directive within <%s.%s> (Bug?)", + OPEP,fname,EXDOING); + phase=999; + } + break; + case 3 : //dispatching email + if (dispatcher(tra)==false) { //trouble backtracking file + (void) rou_alert(0,"%s JMPDBG <%s> dispatcher FALSE (Bug?)",OPEP,fname); + + (void)eml_renameqfile(fname,EXDOING,EXTODO); + phase=999; //No need to go further + } + break; + case 4 : //rewinding file before update + if (fseek(qfile,0,SEEK_SET)<0) { + (void) rou_alert(0,"%s Unable to rewing fname file <%s> (error=<%s> Bug?)", + OPEP,fname,strerror(errno)); + phase=999; //Trouble trouble + } + break; + case 5 : //updating transfile + (void) eml_dump_list_tra(qfile,tra); + (void) update_tradb(tra); + tra=eml_freeall_tra(tra); + break; + case 6 : //closing file + qfile=eml_closeqfile(qfile); + break; + case 7 : //job completed renameing file + if (eml_renameqfile(fname,EXDOING,EXDONE)==false) { + (void) rou_alert(0,"%s Unable to rename file <%s.%s>",OPEP,fname,EXDONE); + phase=999; //No need to go further + } + break; + case 8 : //job fully compltedt, good + status=true; + break; + default : //SAFE Guard + qfile=eml_closeqfile(qfile); + proceed=false; + break; + } + phase++; + } +return status; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to can a list of todo file. */ +/* */ +/********************************************************/ +static void sending(int argc,char *argv[]) + +{ +#define OPEP "sender.c:sending," +#define TODO "todo" + +unsigned long cycle; +char **list; +int delay; +int phase; +_Bool proceed; + +cycle=0; +list=(char **)0; +delay=20; +if (debug>0) + delay/=10; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Build list from argv; + if (argc>0) { + for (int i=0;i",APPNAME,appname,fname); + (void) rou_alert(0,"%s fname file <%s>",OPEP,fname); + if ((ptr=strrchr(fname,'.'))==(char *)0) { + (void) rou_alert(0,"%s unable to find <%s> extension",OPEP,fname); + break; + } + *ptr='\000'; + ptr++; + if (strcmp(ptr,EXTODO)!=0) { + (void) rou_alert(0,"%s wrong extension for file <%s.%s>", + OPEP,fname,ptr); + break; + } + (void) rou_alert(0,"%s scanning file <%s>",appname,fname); + if (scantodo(fname)==false) + break; + scan++; + num++; + } + list=(char **)rou_freelist((void **)list,(genfree_t)rou_freestr); + (void) rou_alert(0,"%s Scanned '%d' files",OPEP,num); + (void) usleep(10000); + phase=0; + } + break; + case 3 : //do we need to loop again + phase=0; //Lets say looping requested + cycle++; + (void) prc_settitle("%s:%s, sleeping mode (cycle=%08d)", + APPNAME,appname,cycle); + (void) sleep(delay); + if ((hangup==true)||((reload==true))) { + (void) rou_alert(0,"%s got hangup or reload signal",OPEP); + phase=999; + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } + +#undef TODO +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Main routine */ +/* Start a channel to a remote ip.port */ +/* read file and transmit contecnts to */ +/* remote SMTP server. */ +/* */ +/********************************************************/ +int main(int argc,char *argv[]) + +{ +#define OPEP "sender.c:main," + +int status; +ARGTYP *params; +int phase; +_Bool proceed; + +status=0; +params=(ARGTYP *)0; +foreground=false; +phase=0; +proceed=true; +while (proceed==true) { + //(void) fprintf(stdout,"%s (pid=%08d) JMPDBG phase='%d'\n",OPEP,getpid(),phase); + switch (phase) { + case 0 : //checking parameters + if ((params=par_getparams(argc,argv,"c:d:D:fh:r:v"))==(ARGTYP *)0) { + proceed=false; //no need to go further + } + break; + case 1 : //Preparing scan + (void) prc_preptitle(argc,argv,environ); + (void) rou_setappname(SENDER); + (void) rou_modesubrou(true); + (void) sig_modeunisig(true); + (void) prc_chgid(argv[0]); + (void) rou_loadconfig(config,true); + if (foreground==false) { + if (prc_divedivedive()!=0) + phase=999; //direct exit + } + break; + case 2 : //locking process + if (prc_locking(appname,true,5)==false) { + (void) rou_alert(0,"%s Unable to lock %s exclusif acccess (system?)", + OPEP,appname); + proceed=false; + } + break; + case 3 : //sending email + (void) sending(params->argc,params->argv); + break; + case 4 : //Unlocking access + (void) prc_locking(appname,false,1); + break; + default : //end of task + (void) prc_cleantitle(); + params=par_freeparams(params); + (void) rou_loadconfig(config,false); + (void) sig_modeunisig(false); + (void) rou_modesubrou(false); + proceed=false; + break; + } + phase++; + } +(void) exit(status); +} diff --git a/app/sender.d b/app/sender.d new file mode 100644 index 0000000..ad26278 --- /dev/null +++ b/app/sender.d @@ -0,0 +1,123 @@ +sender.o sender.d : sender.c /usr/include/stdc-predef.h /usr/include/dirent.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/dirent.h \ + /usr/include/bits/posix1_lim.h /usr/include/bits/local_lim.h \ + /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/dirent_ext.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/stdlib.h \ + /usr/include/bits/libc-header-start.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/sys/types.h \ + /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/time_t.h /usr/include/bits/types/timer_t.h \ + /usr/include/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/endianness.h \ + /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/stdio.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/string.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/strings.h /usr/include/syslog.h /usr/include/sys/syslog.h \ + /usr/include/bits/syslog-path.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h \ + ../lib/subrou.h /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h ../lib/unieml.h \ + ../lib/subafn.h /usr/include/netdb.h /usr/include/netinet/in.h \ + /usr/include/bits/stdint-uintn.h /usr/include/sys/socket.h \ + /usr/include/bits/types/struct_iovec.h /usr/include/bits/socket.h \ + /usr/include/bits/socket_type.h /usr/include/bits/sockaddr.h \ + /usr/include/asm/socket.h /usr/include/asm-generic/socket.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/bits/in.h \ + /usr/include/rpc/netdb.h /usr/include/bits/netdb.h ../lib/unipar.h \ + ../lib/uniprc.h ../lib/subrou.h ../lib/unisig.h /usr/include/signal.h \ + /usr/include/bits/signum-generic.h /usr/include/bits/signum-arch.h \ + /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h /usr/include/bits/types/stack_t.h \ + /usr/include/sys/ucontext.h /usr/include/bits/sigstack.h \ + /usr/include/bits/sigstksz.h /usr/include/bits/ss_flags.h \ + /usr/include/bits/types/struct_sigstack.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h ../lib/geseml.h ../lib/unisql.h \ + ../lib/gessql.h ../lib/unieml.h ../lib/devsql.h ../lib/lvleml.h \ + ../lib/devsoc.h ../lib/unitls.h /usr/include/openssl/ssl.h \ + /usr/include/openssl/macros.h /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/configuration.h /usr/include/openssl/opensslv.h \ + /usr/include/openssl/e_os2.h /usr/include/inttypes.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdint.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/bits/stdint-least.h /usr/include/openssl/e_ostime.h \ + /usr/include/sys/time.h /usr/include/openssl/comp.h \ + /usr/include/openssl/crypto.h /usr/include/openssl/safestack.h \ + /usr/include/openssl/stack.h /usr/include/openssl/types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/limits.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix2_lim.h \ + /usr/include/openssl/cryptoerr.h /usr/include/openssl/symhacks.h \ + /usr/include/openssl/cryptoerr_legacy.h /usr/include/openssl/core.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include-fixed/pthread.h \ + /usr/include/sched.h /usr/include/bits/sched.h \ + /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \ + /usr/include/bits/setjmp.h \ + /usr/include/bits/types/struct___jmp_buf_tag.h \ + /usr/include/openssl/comperr.h /usr/include/openssl/bio.h \ + /usr/include/openssl/bioerr.h /usr/include/openssl/x509.h \ + /usr/include/openssl/buffer.h /usr/include/openssl/buffererr.h \ + /usr/include/openssl/evp.h /usr/include/openssl/core_dispatch.h \ + /usr/include/openssl/indicator.h /usr/include/openssl/params.h \ + /usr/include/openssl/bn.h /usr/include/openssl/bnerr.h \ + /usr/include/openssl/evperr.h /usr/include/openssl/objects.h \ + /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \ + /usr/include/openssl/asn1err.h /usr/include/openssl/objectserr.h \ + /usr/include/openssl/ec.h /usr/include/openssl/ecerr.h \ + /usr/include/openssl/rsa.h /usr/include/openssl/rsaerr.h \ + /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \ + /usr/include/openssl/dherr.h /usr/include/openssl/dsaerr.h \ + /usr/include/openssl/sha.h /usr/include/openssl/x509err.h \ + /usr/include/openssl/x509_vfy.h /usr/include/openssl/lhash.h \ + /usr/include/openssl/pkcs7.h /usr/include/openssl/pkcs7err.h \ + /usr/include/openssl/http.h /usr/include/openssl/conf.h \ + /usr/include/openssl/conferr.h /usr/include/openssl/conftypes.h \ + /usr/include/openssl/pem.h /usr/include/openssl/pemerr.h \ + /usr/include/openssl/hmac.h /usr/include/openssl/async.h \ + /usr/include/openssl/asyncerr.h /usr/include/openssl/ct.h \ + /usr/include/openssl/cterr.h /usr/include/openssl/sslerr.h \ + /usr/include/openssl/sslerr_legacy.h /usr/include/openssl/prov_ssl.h \ + /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \ + /usr/include/openssl/tls1.h /usr/include/openssl/dtls1.h \ + /usr/include/openssl/srtp.h /usr/include/openssl/quic.h ../lib/gestcp.h \ + ../lib/unidns.h ../lib/devlog.h ../lib/gesspf.h ../lib/geseml.h diff --git a/app/sorter.c b/app/sorter.c new file mode 100644 index 0000000..2c0e19f --- /dev/null +++ b/app/sorter.c @@ -0,0 +1,236 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* SMTP protocol domain destination sorter */ +/* Used to take the trans directive and generate */ +/* a todo list a email to be send. */ +/* */ +/* */ +/********************************************************/ +#include +#include +#include +#include + +#include "subrou.h" +#include "unidns.h" +#include "unieml.h" +#include "unipar.h" +#include "uniprc.h" +#include "unisig.h" +#include "geseml.h" + +/* + +*/ +/********************************************************/ +/* */ +/* procedure to scan all files */ +/* */ +/********************************************************/ +static _Bool scantrans(const char *ext,_Bool todo) + +{ +#define OPEP "sorter.c:scantrans," + +_Bool action; +char **fname; +TRATYP **trans; +int phase; +_Bool proceed; + +action=false; +fname=(char **)0; +trans=(TRATYP **)0; +phase=0; +proceed=true; +while (proceed==true) { + //(void) fprintf(stdout,"%s JMPDBG phase='%d' ext=<%s>\n",OPEP,phase,ext); + switch (phase) { + case 0 : //Getting the list of file + (void) prc_settitle("%s:%s, scanning ext=%s",APPNAME,appname,ext); + fname=eml_getqfilelist(fname,ext); + if (fname==(char **)0) + phase=999; //Nothing to do + break; + case 1 : //Building the "trans" list + action=true; + if (fname!=(char **)0) { //always + char **ptr; + + ptr=fname; + while (*ptr!=(char *)0) { + FILE *qfile; + + (void) rou_alert(5,"%s fame=<%s>",OPEP,*ptr); + if ((qfile=eml_openqfile(*ptr,(const char *)0))!=(FILE *)0) { + trans=eml_scanqfile(trans,qfile); + (void) eml_closeqfile(qfile); + (void) eml_deleteqfile(*ptr); + } + ptr++; + } + fname=(char **)rou_freelist((void *)fname,(genfree_t)rou_freestr); + } + break; + case 2 : //scanning translit + switch (todo) { + case true : //Doing todo file + (void) eml_todoqfile(trans); + break; + case false : + (void) eml_doneqfile(trans); + break; + } + trans=eml_freeall_tra(trans); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +#undef OPEP +return action; +} +/* + +*/ +/********************************************************/ +/* */ +/* sorter central task */ +/* */ +/********************************************************/ +static void sorting() + +{ +#define OPEP "sorter.c:sorting," +#define TSLEEP 10 + +unsigned long cycle; +_Bool action; +int delay; +int phase; +_Bool proceed; + +cycle=0; +action=false; +delay=1; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //Locking access + if (prc_locking(appname,true,5)==false) { + (void) rou_alert(0,"%s Unable to lock %s exclusif acccess (system?)", + OPEP,appname); + proceed=false; + } + break; + case 1 : //got signal + action=false; + if ((hangup==true)||((reload==true))) { + (void) rou_alert(0,"%s got hangup or reload signal",OPEP); + phase=999; + } + break; + case 2 : //got signal + action|=scantrans(EXTRANS,true); + break; + case 3 : //got signal + action|=scantrans(EXDONE,false); + break; + case 4 : //one passe only? + if (foreground==true) + phase=999; //Immediate ending + break; + case 5 : //lets time pass according "busy" + cycle++; + delay=TSLEEP; + if (action==true) + delay=1; + (void) prc_settitle("%s:%s, sleeping mode (cycle=%08d)", + APPNAME,appname,cycle); + (void) sleep(delay); + phase=0; //Looping + break; + default : //SAFE Guard + (void) prc_locking(appname,false,1); + proceed=false; + break; + } + phase++; + } + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Main routine */ +/* Start a channel to a remote ip.port */ +/* read file and transmit contecnts to */ +/* remote SMTP server. */ +/* */ +/********************************************************/ +int main(int argc,char *argv[]) + +{ +#define OPEP "sorter.c:main," + +int status; +ARGTYP *params; +int phase; +_Bool proceed; + +status=0; +params=(ARGTYP *)0; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //checking parameters + if ((params=par_getparams(argc,argv,"c:d:D:fhi:r:v"))==(ARGTYP *)0) { + proceed=false; //no need to go further + } + break; + case 1 : //Preparing scan + (void) prc_preptitle(argc,argv,environ); + (void) rou_setappname(SORTER); + (void) rou_modesubrou(true); + (void) prc_chgid(argv[0]); + (void) sig_modeunisig(true); + (void) sig_trapsignal(true,sig_alrm); + (void) rou_loadconfig(config,true); + break; + case 2 : //checking if we need to go background + if (foreground==false) { + if (prc_divedivedive()!=0) + phase=999; //direct exit + } + break; + case 3 : //do program main purpose + (void) sorting(); + break; + default : //end of task + (void) prc_cleantitle(); + params=par_freeparams(params); + (void) rou_loadconfig(config,false); + (void) sig_trapsignal(false,sig_alrm); + (void) sig_modeunisig(false); + (void) rou_modesubrou(false); + (void) closelog(); + proceed=false; + break; + } + phase++; + } +(void) exit(status); + +#undef TSLEEP +#undef OPEP +} diff --git a/app/sorter.d b/app/sorter.d new file mode 100644 index 0000000..5a087d6 --- /dev/null +++ b/app/sorter.d @@ -0,0 +1,74 @@ +sorter.o sorter.d : sorter.c /usr/include/stdc-predef.h /usr/include/dirent.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/dirent.h \ + /usr/include/bits/posix1_lim.h /usr/include/bits/local_lim.h \ + /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/dirent_ext.h /usr/include/stdlib.h \ + /usr/include/bits/libc-header-start.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/sys/types.h \ + /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/time_t.h /usr/include/bits/types/timer_t.h \ + /usr/include/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/endianness.h \ + /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/syslog.h \ + /usr/include/sys/syslog.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/syslog-path.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h \ + ../lib/subrou.h /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + ../lib/unidns.h ../lib/subafn.h /usr/include/netdb.h \ + /usr/include/netinet/in.h /usr/include/bits/stdint-uintn.h \ + /usr/include/sys/socket.h /usr/include/bits/types/struct_iovec.h \ + /usr/include/bits/socket.h /usr/include/bits/socket_type.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm-generic/socket.h /usr/include/asm/sockios.h \ + /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/bits/in.h \ + /usr/include/rpc/netdb.h /usr/include/bits/netdb.h ../lib/unieml.h \ + /usr/include/stdio.h /usr/include/bits/types/__fpos_t.h \ + /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h ../lib/unipar.h ../lib/uniprc.h \ + ../lib/subrou.h ../lib/unisig.h /usr/include/signal.h \ + /usr/include/bits/signum-generic.h /usr/include/bits/signum-arch.h \ + /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h /usr/include/bits/types/stack_t.h \ + /usr/include/sys/ucontext.h /usr/include/bits/sigstack.h \ + /usr/include/bits/sigstksz.h /usr/include/bits/ss_flags.h \ + /usr/include/bits/types/struct_sigstack.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h ../lib/geseml.h ../lib/unisql.h diff --git a/app/toremake b/app/toremake new file mode 100644 index 0000000..e69de29 diff --git a/bin b/bin new file mode 120000 index 0000000..a311833 --- /dev/null +++ b/bin @@ -0,0 +1 @@ +bin-posql \ No newline at end of file diff --git a/certs/localhost-cert.pem b/certs/localhost-cert.pem new file mode 100644 index 0000000..12e130d --- /dev/null +++ b/certs/localhost-cert.pem @@ -0,0 +1,147 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2a:01:e0:a5:fb:80:80:00:00:00:29 + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=CA, O=SAFE Inc., OU=Digital Certificate Signing, CN=SAFE Midle Ground CA (2024) - SHA384 - 3 + Validity + Not Before: Apr 6 13:59:06 2025 GMT + Not After : Apr 6 13:59:06 2050 GMT + Subject: C=CA, ST=Quebec, L=Montreal, O=SAFE Inc., OU=Mailleur email developpement test, CN=localhost.localdomain + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:ba:5f:35:d2:04:d5:f4:da:f0:b1:99:6f:f3:42: + 42:0e:59:8d:7b:6c:24:97:6d:24:df:e8:fa:83:7c: + ae:92:fd:d1:58:1c:14:7e:20:71:5e:44:5a:b0:e8: + 7a:ce:45:33:95:aa:27:ef:52:fe:bd:5a:23:7b:4f: + 8b:24:4d:0b:f7:9c:99:25:b8:b9:af:8c:46:f7:a9: + 6c:18:ff:39:7c:a9:ff:9a:f5:f0:d7:d7:ca:dc:6c: + 5d:c7:09:02:83:87:37:1a:2f:f7:05:b8:39:af:9f: + ab:24:3b:24:48:e6:72:af:36:10:0d:c6:dc:bd:c2: + de:05:4f:4a:fd:d8:5b:35:24:b9:bc:ce:ab:37:3a: + f9:ff:2d:44:c2:33:f2:52:4a:36:5c:5f:80:a7:cd: + f7:1b:6d:55:b7:d6:13:25:72:d5:55:4d:54:ff:a1: + 1e:7d:85:8b:e0:e2:16:d1:d1:22:21:07:99:ad:9a: + 51:25:02:71:7b:56:e5:77:16:07:18:c6:fd:de:c4: + e0:e5:55:01:78:f6:3c:53:ab:35:1d:44:f8:26:af: + c3:11:a2:2d:63:73:29:c5:bd:b4:17:f7:83:7e:0d: + d9:0a:d9:a1:27:f2:7c:bc:ee:95:76:68:ec:c4:7f: + 35:64:44:d4:6d:43:46:99:40:52:cd:b4:c0:11:3a: + d7:ab:7c:cf:87:b5:41:32:a4:23:2d:3f:cc:fa:b2: + 6b:5b:dd:a5:58:14:7a:24:cb:3a:26:04:49:8f:07: + 8b:5b:d0:be:c2:ee:24:de:d1:74:cb:04:48:be:f9: + 74:5a:17:52:1e:0e:c0:ea:02:d1:7a:1e:e7:a2:95: + b4:77:1a:96:6d:34:80:78:85:0f:84:e6:3b:60:27: + 75:5d:33:60:6d:6b:d9:da:b9:af:a9:cf:bc:ae:c3: + 29:ca:a3:1b:4f:3b:7f:fa:ba:d6:01:f0:07:3f:7d: + 00:45:e6:6e:7f:aa:67:ad:90:db:1d:2a:eb:e4:be: + 43:13:5e:2e:dc:de:a1:36:fd:20:90:1f:ac:8c:3c: + c9:0e:32:96:ef:a8:19:1d:30:87:d1:f2:42:c7:55: + e7:46:24:9c:d2:4a:1f:42:01:f7:eb:68:5f:d6:b5: + 9a:3a:e2:51:90:94:59:9d:bc:83:dd:d8:89:e9:34: + af:d6:43:66:8f:87:85:2b:c6:b1:43:b6:09:92:ba: + f4:e3:d6:3b:c1:5b:2d:76:cd:56:ac:7f:bb:fb:60: + 30:a5:13:76:73:35:5e:67:df:dd:c5:fe:ab:e5:4f: + dd:80:56:19:a6:e0:d8:53:b2:20:5c:5c:34:2f:a1: + 31:0b:12:27:71:b6:ea:5b:2e:fa:a3:88:2f:f7:24: + 5b:93:0d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + Authority Information Access: + CA Issuers - URI:http://certificates.safe.ca/cacert/safeMDL.pem + OCSP - URI:http://certificates/safe.ca/chkcertstats + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.7438.1.2 + CPS: http://certificates.safe.ca/policies + Policy: 2.23.140.1.1 + X509v3 Basic Constraints: + CA:FALSE + X509v3 CRL Distribution Points: + Full Name: + URI:http://certificates.safe.ca/repository/revoklist.pem + X509v3 Subject Alternative Name: + DNS:localhost.localdomain, IP Address:127.127.0.1 + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication, E-mail Protection + X509v3 Subject Key Identifier: + 2D:BD:65:E1:4E:2B:7D:E0:80:3E:D2:66:6E:ED:81:87:4A:52:CD:6C + X509v3 Authority Key Identifier: + 9C:BE:0B:C0:22:76:F5:CF:BC:FD:78:9A:92:77:20:FE:BF:96:1E:D8 + Signature Algorithm: sha384WithRSAEncryption + Signature Value: + ac:e8:1e:50:ec:0e:b8:02:c6:ac:70:19:ee:37:7f:53:24:69: + cc:ca:6e:34:6b:9b:14:cf:71:67:bb:7d:f9:60:a7:92:59:9b: + de:56:8b:86:9a:8e:59:da:ad:4a:90:a4:2e:2d:c4:a0:17:01: + 18:84:c4:dd:5c:93:97:dd:d9:ad:d4:0d:63:33:3b:4e:3f:24: + 0e:6c:13:6c:3f:3b:5e:ca:27:a1:5a:1c:30:e4:eb:da:d0:e5: + b1:4f:ce:fb:c4:8c:76:da:e6:f6:00:a5:03:58:9b:6d:79:84: + 92:2c:10:66:96:b9:7f:73:57:97:7e:6a:f2:74:d3:ac:0a:3e: + b2:11:c4:f5:1e:4d:87:1f:8e:6d:29:ed:ef:97:8f:70:f7:37: + 61:3e:ae:4a:d6:6d:6e:80:c5:bb:de:9b:bd:06:bb:a8:94:28: + ed:f6:c9:4a:7f:e2:9a:44:e1:96:07:25:60:74:19:d1:fb:86: + 32:16:1c:c4:99:dd:de:ab:fe:7a:88:af:8e:3a:fa:36:c3:92: + b3:82:ba:50:18:02:42:2c:b4:6a:d2:ba:a3:8e:fb:72:6a:d1: + 8a:b4:3f:b3:9e:27:90:18:b8:50:04:b8:1e:14:d6:e1:98:ff: + ed:78:5d:5e:76:b0:6e:8d:e0:ea:e3:00:5e:c7:f3:eb:ed:71: + c6:c0:de:f1:e2:bb:03:14:f1:27:0f:a6:2e:6c:38:0a:ca:3e: + ef:e1:4c:d8:a4:dc:7d:6a:ec:e5:3e:b5:a7:53:7b:2a:32:76: + da:a8:e1:1b:8c:76:6b:8b:b8:75:51:65:25:e0:c2:31:c7:0b: + b1:a6:a2:10:b7:45:4d:fc:69:67:84:c6:81:c8:e7:5e:b8:fc: + fb:8d:64:e3:28:dc:b3:41:be:8e:58:7a:8e:9e:89:ee:51:f1: + bf:5e:82:a6:29:a8:98:fe:ef:fb:7c:70:f7:8c:ee:4e:07:47: + 10:4e:75:ad:21:a2:ad:9a:4e:e7:3a:01:2e:bc:81:63:b7:7c: + 4c:ea:32:4c:12:78:20:81:9d:f2:8d:5f:1f:4b:82:67:55:1f: + 95:ff:d8:7f:5b:50:74:fd:18:4c:74:3e:4e:cf:5b:26:d6:73: + 29:ea:dd:9b:a0:a5:0b:5d:5e:0d:36:fd:f5:d1:d0:91:9a:6e: + 81:b9:4a:93:d7:94:bb:75:e5:fa:ff:9f:5f:1e:f4:d3:63:9e: + 09:03:00:b5:aa:77:0d:9f:2f:25:41:99:f3:52:04:08:3d:f4: + d5:ab:37:3a:0c:1b:fe:db:66:45:8b:b3:88:7e:1d:9c:98:98: + a7:f7:00:30:06:78:f6:0e:ea:aa:e6:24:3d:3f:31:39:80:3e: + a8:74:a2:1e:42:51:d7:13 +-----BEGIN CERTIFICATE----- +MIIHZDCCBUygAwIBAgILKgHgpfuAgAAAACkwDQYJKoZIhvcNAQEMBQAwejELMAkG +A1UEBhMCQ0ExEjAQBgNVBAoMCVNBRkUgSW5jLjEkMCIGA1UECwwbRGlnaXRhbCBD +ZXJ0aWZpY2F0ZSBTaWduaW5nMTEwLwYDVQQDDChTQUZFIE1pZGxlIEdyb3VuZCBD +QSAoMjAyNCkgLSBTSEEzODQgLSAzMCAXDTI1MDQwNjEzNTkwNloYDzIwNTAwNDA2 +MTM1OTA2WjCBkTELMAkGA1UEBhMCQ0ExDzANBgNVBAgMBlF1ZWJlYzERMA8GA1UE +BwwITW9udHJlYWwxEjAQBgNVBAoMCVNBRkUgSW5jLjEqMCgGA1UECwwhTWFpbGxl +dXIgZW1haWwgZGV2ZWxvcHBlbWVudCB0ZXN0MR4wHAYDVQQDDBVsb2NhbGhvc3Qu +bG9jYWxkb21haW4wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC6XzXS +BNX02vCxmW/zQkIOWY17bCSXbSTf6PqDfK6S/dFYHBR+IHFeRFqw6HrORTOVqifv +Uv69WiN7T4skTQv3nJkluLmvjEb3qWwY/zl8qf+a9fDX18rcbF3HCQKDhzcaL/cF +uDmvn6skOyRI5nKvNhANxty9wt4FT0r92Fs1JLm8zqs3Ovn/LUTCM/JSSjZcX4Cn +zfcbbVW31hMlctVVTVT/oR59hYvg4hbR0SIhB5mtmlElAnF7VuV3FgcYxv3exODl +VQF49jxTqzUdRPgmr8MRoi1jcynFvbQX94N+DdkK2aEn8ny87pV2aOzEfzVkRNRt +Q0aZQFLNtMAROterfM+HtUEypCMtP8z6smtb3aVYFHokyzomBEmPB4tb0L7C7iTe +0XTLBEi++XRaF1IeDsDqAtF6HueilbR3GpZtNIB4hQ+E5jtgJ3VdM2Bta9naua+p +z7yuwynKoxtPO3/6utYB8Ac/fQBF5m5/qmetkNsdKuvkvkMTXi7c3qE2/SCQH6yM +PMkOMpbvqBkdMIfR8kLHVedGJJzSSh9CAffraF/WtZo64lGQlFmdvIPd2InpNK/W +Q2aPh4UrxrFDtgmSuvTj1jvBWy12zVasf7v7YDClE3ZzNV5n393F/qvlT92AVhmm +4NhTsiBcXDQvoTELEidxtupbLvqjiC/3JFuTDQIDAQABo4IBzzCCAcswDgYDVR0P +AQH/BAQDAgWgMIGABggrBgEFBQcBAQR0MHIwOgYIKwYBBQUHMAKGLmh0dHA6Ly9j +ZXJ0aWZpY2F0ZXMuc2FmZS5jYS9jYWNlcnQvc2FmZU1ETC5wZW0wNAYIKwYBBQUH +MAGGKGh0dHA6Ly9jZXJ0aWZpY2F0ZXMvc2FmZS5jYS9jaGtjZXJ0c3RhdHMwUwYD +VR0gBEwwSjA/BgkrBgEEAboOAQIwMjAwBggrBgEFBQcCARYkaHR0cDovL2NlcnRp +ZmljYXRlcy5zYWZlLmNhL3BvbGljaWVzMAcGBWeBDAEBMAkGA1UdEwQCMAAwRQYD +VR0fBD4wPDA6oDigNoY0aHR0cDovL2NlcnRpZmljYXRlcy5zYWZlLmNhL3JlcG9z +aXRvcnkvcmV2b2tsaXN0LnBlbTAmBgNVHREEHzAdghVsb2NhbGhvc3QubG9jYWxk +b21haW6HBH9/AAEwJwYDVR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEF +BQcDBDAdBgNVHQ4EFgQULb1l4U4rfeCAPtJmbu2Bh0pSzWwwHwYDVR0jBBgwFoAU +nL4LwCJ29c+8/Xiakncg/r+WHtgwDQYJKoZIhvcNAQEMBQADggIBAKzoHlDsDrgC +xqxwGe43f1MkaczKbjRrmxTPcWe7fflgp5JZm95Wi4aajlnarUqQpC4txKAXARiE +xN1ck5fd2a3UDWMzO04/JA5sE2w/O17KJ6FaHDDk69rQ5bFPzvvEjHba5vYApQNY +m215hJIsEGaWuX9zV5d+avJ006wKPrIRxPUeTYcfjm0p7e+Xj3D3N2E+rkrWbW6A +xbvem70Gu6iUKO32yUp/4ppE4ZYHJWB0GdH7hjIWHMSZ3d6r/nqIr446+jbDkrOC +ulAYAkIstGrSuqOO+3Jq0Yq0P7OeJ5AYuFAEuB4U1uGY/+14XV52sG6N4OrjAF7H +8+vtccbA3vHiuwMU8ScPpi5sOArKPu/hTNik3H1q7OU+tadTeyoydtqo4RuMdmuL +uHVRZSXgwjHHC7GmohC3RU38aWeExoHI5164/PuNZOMo3LNBvo5Yeo6eie5R8b9e +gqYpqJj+7/t8cPeM7k4HRxBOda0hoq2aTuc6AS68gWO3fEzqMkwSeCCBnfKNXx9L +gmdVH5X/2H9bUHT9GEx0Pk7PWybWcynq3ZugpQtdXg02/fXR0JGaboG5SpPXlLt1 +5fr/n18e9NNjngkDALWqdw2fLyVBmfNSBAg99NWrNzoMG/7bZkWLs4h+HZyYmKf3 +ADAGePYO6qrmJD0/MTmAPqh0oh5CUdcT +-----END CERTIFICATE----- diff --git a/certs/localhost-chain-cert.pem b/certs/localhost-chain-cert.pem new file mode 100644 index 0000000..89ac0c5 --- /dev/null +++ b/certs/localhost-chain-cert.pem @@ -0,0 +1,257 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2a:01:e0:a5:fb:80:80:00:00:00:29 + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=CA, O=SAFE Inc., OU=Digital Certificate Signing, CN=SAFE Midle Ground CA (2024) - SHA384 - 3 + Validity + Not Before: Apr 6 13:59:06 2025 GMT + Not After : Apr 6 13:59:06 2050 GMT + Subject: C=CA, ST=Quebec, L=Montreal, O=SAFE Inc., OU=Mailleur email developpement test, CN=localhost.localdomain + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:ba:5f:35:d2:04:d5:f4:da:f0:b1:99:6f:f3:42: + 42:0e:59:8d:7b:6c:24:97:6d:24:df:e8:fa:83:7c: + ae:92:fd:d1:58:1c:14:7e:20:71:5e:44:5a:b0:e8: + 7a:ce:45:33:95:aa:27:ef:52:fe:bd:5a:23:7b:4f: + 8b:24:4d:0b:f7:9c:99:25:b8:b9:af:8c:46:f7:a9: + 6c:18:ff:39:7c:a9:ff:9a:f5:f0:d7:d7:ca:dc:6c: + 5d:c7:09:02:83:87:37:1a:2f:f7:05:b8:39:af:9f: + ab:24:3b:24:48:e6:72:af:36:10:0d:c6:dc:bd:c2: + de:05:4f:4a:fd:d8:5b:35:24:b9:bc:ce:ab:37:3a: + f9:ff:2d:44:c2:33:f2:52:4a:36:5c:5f:80:a7:cd: + f7:1b:6d:55:b7:d6:13:25:72:d5:55:4d:54:ff:a1: + 1e:7d:85:8b:e0:e2:16:d1:d1:22:21:07:99:ad:9a: + 51:25:02:71:7b:56:e5:77:16:07:18:c6:fd:de:c4: + e0:e5:55:01:78:f6:3c:53:ab:35:1d:44:f8:26:af: + c3:11:a2:2d:63:73:29:c5:bd:b4:17:f7:83:7e:0d: + d9:0a:d9:a1:27:f2:7c:bc:ee:95:76:68:ec:c4:7f: + 35:64:44:d4:6d:43:46:99:40:52:cd:b4:c0:11:3a: + d7:ab:7c:cf:87:b5:41:32:a4:23:2d:3f:cc:fa:b2: + 6b:5b:dd:a5:58:14:7a:24:cb:3a:26:04:49:8f:07: + 8b:5b:d0:be:c2:ee:24:de:d1:74:cb:04:48:be:f9: + 74:5a:17:52:1e:0e:c0:ea:02:d1:7a:1e:e7:a2:95: + b4:77:1a:96:6d:34:80:78:85:0f:84:e6:3b:60:27: + 75:5d:33:60:6d:6b:d9:da:b9:af:a9:cf:bc:ae:c3: + 29:ca:a3:1b:4f:3b:7f:fa:ba:d6:01:f0:07:3f:7d: + 00:45:e6:6e:7f:aa:67:ad:90:db:1d:2a:eb:e4:be: + 43:13:5e:2e:dc:de:a1:36:fd:20:90:1f:ac:8c:3c: + c9:0e:32:96:ef:a8:19:1d:30:87:d1:f2:42:c7:55: + e7:46:24:9c:d2:4a:1f:42:01:f7:eb:68:5f:d6:b5: + 9a:3a:e2:51:90:94:59:9d:bc:83:dd:d8:89:e9:34: + af:d6:43:66:8f:87:85:2b:c6:b1:43:b6:09:92:ba: + f4:e3:d6:3b:c1:5b:2d:76:cd:56:ac:7f:bb:fb:60: + 30:a5:13:76:73:35:5e:67:df:dd:c5:fe:ab:e5:4f: + dd:80:56:19:a6:e0:d8:53:b2:20:5c:5c:34:2f:a1: + 31:0b:12:27:71:b6:ea:5b:2e:fa:a3:88:2f:f7:24: + 5b:93:0d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + Authority Information Access: + CA Issuers - URI:http://certificates.safe.ca/cacert/safeMDL.pem + OCSP - URI:http://certificates/safe.ca/chkcertstats + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.7438.1.2 + CPS: http://certificates.safe.ca/policies + Policy: 2.23.140.1.1 + X509v3 Basic Constraints: + CA:FALSE + X509v3 CRL Distribution Points: + Full Name: + URI:http://certificates.safe.ca/repository/revoklist.pem + X509v3 Subject Alternative Name: + DNS:localhost.localdomain, IP Address:127.127.0.1 + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication, E-mail Protection + X509v3 Subject Key Identifier: + 2D:BD:65:E1:4E:2B:7D:E0:80:3E:D2:66:6E:ED:81:87:4A:52:CD:6C + X509v3 Authority Key Identifier: + 9C:BE:0B:C0:22:76:F5:CF:BC:FD:78:9A:92:77:20:FE:BF:96:1E:D8 + Signature Algorithm: sha384WithRSAEncryption + Signature Value: + ac:e8:1e:50:ec:0e:b8:02:c6:ac:70:19:ee:37:7f:53:24:69: + cc:ca:6e:34:6b:9b:14:cf:71:67:bb:7d:f9:60:a7:92:59:9b: + de:56:8b:86:9a:8e:59:da:ad:4a:90:a4:2e:2d:c4:a0:17:01: + 18:84:c4:dd:5c:93:97:dd:d9:ad:d4:0d:63:33:3b:4e:3f:24: + 0e:6c:13:6c:3f:3b:5e:ca:27:a1:5a:1c:30:e4:eb:da:d0:e5: + b1:4f:ce:fb:c4:8c:76:da:e6:f6:00:a5:03:58:9b:6d:79:84: + 92:2c:10:66:96:b9:7f:73:57:97:7e:6a:f2:74:d3:ac:0a:3e: + b2:11:c4:f5:1e:4d:87:1f:8e:6d:29:ed:ef:97:8f:70:f7:37: + 61:3e:ae:4a:d6:6d:6e:80:c5:bb:de:9b:bd:06:bb:a8:94:28: + ed:f6:c9:4a:7f:e2:9a:44:e1:96:07:25:60:74:19:d1:fb:86: + 32:16:1c:c4:99:dd:de:ab:fe:7a:88:af:8e:3a:fa:36:c3:92: + b3:82:ba:50:18:02:42:2c:b4:6a:d2:ba:a3:8e:fb:72:6a:d1: + 8a:b4:3f:b3:9e:27:90:18:b8:50:04:b8:1e:14:d6:e1:98:ff: + ed:78:5d:5e:76:b0:6e:8d:e0:ea:e3:00:5e:c7:f3:eb:ed:71: + c6:c0:de:f1:e2:bb:03:14:f1:27:0f:a6:2e:6c:38:0a:ca:3e: + ef:e1:4c:d8:a4:dc:7d:6a:ec:e5:3e:b5:a7:53:7b:2a:32:76: + da:a8:e1:1b:8c:76:6b:8b:b8:75:51:65:25:e0:c2:31:c7:0b: + b1:a6:a2:10:b7:45:4d:fc:69:67:84:c6:81:c8:e7:5e:b8:fc: + fb:8d:64:e3:28:dc:b3:41:be:8e:58:7a:8e:9e:89:ee:51:f1: + bf:5e:82:a6:29:a8:98:fe:ef:fb:7c:70:f7:8c:ee:4e:07:47: + 10:4e:75:ad:21:a2:ad:9a:4e:e7:3a:01:2e:bc:81:63:b7:7c: + 4c:ea:32:4c:12:78:20:81:9d:f2:8d:5f:1f:4b:82:67:55:1f: + 95:ff:d8:7f:5b:50:74:fd:18:4c:74:3e:4e:cf:5b:26:d6:73: + 29:ea:dd:9b:a0:a5:0b:5d:5e:0d:36:fd:f5:d1:d0:91:9a:6e: + 81:b9:4a:93:d7:94:bb:75:e5:fa:ff:9f:5f:1e:f4:d3:63:9e: + 09:03:00:b5:aa:77:0d:9f:2f:25:41:99:f3:52:04:08:3d:f4: + d5:ab:37:3a:0c:1b:fe:db:66:45:8b:b3:88:7e:1d:9c:98:98: + a7:f7:00:30:06:78:f6:0e:ea:aa:e6:24:3d:3f:31:39:80:3e: + a8:74:a2:1e:42:51:d7:13 +-----BEGIN CERTIFICATE----- +MIIHZDCCBUygAwIBAgILKgHgpfuAgAAAACkwDQYJKoZIhvcNAQEMBQAwejELMAkG +A1UEBhMCQ0ExEjAQBgNVBAoMCVNBRkUgSW5jLjEkMCIGA1UECwwbRGlnaXRhbCBD +ZXJ0aWZpY2F0ZSBTaWduaW5nMTEwLwYDVQQDDChTQUZFIE1pZGxlIEdyb3VuZCBD +QSAoMjAyNCkgLSBTSEEzODQgLSAzMCAXDTI1MDQwNjEzNTkwNloYDzIwNTAwNDA2 +MTM1OTA2WjCBkTELMAkGA1UEBhMCQ0ExDzANBgNVBAgMBlF1ZWJlYzERMA8GA1UE +BwwITW9udHJlYWwxEjAQBgNVBAoMCVNBRkUgSW5jLjEqMCgGA1UECwwhTWFpbGxl +dXIgZW1haWwgZGV2ZWxvcHBlbWVudCB0ZXN0MR4wHAYDVQQDDBVsb2NhbGhvc3Qu +bG9jYWxkb21haW4wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC6XzXS +BNX02vCxmW/zQkIOWY17bCSXbSTf6PqDfK6S/dFYHBR+IHFeRFqw6HrORTOVqifv +Uv69WiN7T4skTQv3nJkluLmvjEb3qWwY/zl8qf+a9fDX18rcbF3HCQKDhzcaL/cF +uDmvn6skOyRI5nKvNhANxty9wt4FT0r92Fs1JLm8zqs3Ovn/LUTCM/JSSjZcX4Cn +zfcbbVW31hMlctVVTVT/oR59hYvg4hbR0SIhB5mtmlElAnF7VuV3FgcYxv3exODl +VQF49jxTqzUdRPgmr8MRoi1jcynFvbQX94N+DdkK2aEn8ny87pV2aOzEfzVkRNRt +Q0aZQFLNtMAROterfM+HtUEypCMtP8z6smtb3aVYFHokyzomBEmPB4tb0L7C7iTe +0XTLBEi++XRaF1IeDsDqAtF6HueilbR3GpZtNIB4hQ+E5jtgJ3VdM2Bta9naua+p +z7yuwynKoxtPO3/6utYB8Ac/fQBF5m5/qmetkNsdKuvkvkMTXi7c3qE2/SCQH6yM +PMkOMpbvqBkdMIfR8kLHVedGJJzSSh9CAffraF/WtZo64lGQlFmdvIPd2InpNK/W +Q2aPh4UrxrFDtgmSuvTj1jvBWy12zVasf7v7YDClE3ZzNV5n393F/qvlT92AVhmm +4NhTsiBcXDQvoTELEidxtupbLvqjiC/3JFuTDQIDAQABo4IBzzCCAcswDgYDVR0P +AQH/BAQDAgWgMIGABggrBgEFBQcBAQR0MHIwOgYIKwYBBQUHMAKGLmh0dHA6Ly9j +ZXJ0aWZpY2F0ZXMuc2FmZS5jYS9jYWNlcnQvc2FmZU1ETC5wZW0wNAYIKwYBBQUH +MAGGKGh0dHA6Ly9jZXJ0aWZpY2F0ZXMvc2FmZS5jYS9jaGtjZXJ0c3RhdHMwUwYD +VR0gBEwwSjA/BgkrBgEEAboOAQIwMjAwBggrBgEFBQcCARYkaHR0cDovL2NlcnRp +ZmljYXRlcy5zYWZlLmNhL3BvbGljaWVzMAcGBWeBDAEBMAkGA1UdEwQCMAAwRQYD +VR0fBD4wPDA6oDigNoY0aHR0cDovL2NlcnRpZmljYXRlcy5zYWZlLmNhL3JlcG9z +aXRvcnkvcmV2b2tsaXN0LnBlbTAmBgNVHREEHzAdghVsb2NhbGhvc3QubG9jYWxk +b21haW6HBH9/AAEwJwYDVR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEF +BQcDBDAdBgNVHQ4EFgQULb1l4U4rfeCAPtJmbu2Bh0pSzWwwHwYDVR0jBBgwFoAU +nL4LwCJ29c+8/Xiakncg/r+WHtgwDQYJKoZIhvcNAQEMBQADggIBAKzoHlDsDrgC +xqxwGe43f1MkaczKbjRrmxTPcWe7fflgp5JZm95Wi4aajlnarUqQpC4txKAXARiE +xN1ck5fd2a3UDWMzO04/JA5sE2w/O17KJ6FaHDDk69rQ5bFPzvvEjHba5vYApQNY +m215hJIsEGaWuX9zV5d+avJ006wKPrIRxPUeTYcfjm0p7e+Xj3D3N2E+rkrWbW6A +xbvem70Gu6iUKO32yUp/4ppE4ZYHJWB0GdH7hjIWHMSZ3d6r/nqIr446+jbDkrOC +ulAYAkIstGrSuqOO+3Jq0Yq0P7OeJ5AYuFAEuB4U1uGY/+14XV52sG6N4OrjAF7H +8+vtccbA3vHiuwMU8ScPpi5sOArKPu/hTNik3H1q7OU+tadTeyoydtqo4RuMdmuL +uHVRZSXgwjHHC7GmohC3RU38aWeExoHI5164/PuNZOMo3LNBvo5Yeo6eie5R8b9e +gqYpqJj+7/t8cPeM7k4HRxBOda0hoq2aTuc6AS68gWO3fEzqMkwSeCCBnfKNXx9L +gmdVH5X/2H9bUHT9GEx0Pk7PWybWcynq3ZugpQtdXg02/fXR0JGaboG5SpPXlLt1 +5fr/n18e9NNjngkDALWqdw2fLyVBmfNSBAg99NWrNzoMG/7bZkWLs4h+HZyYmKf3 +ADAGePYO6qrmJD0/MTmAPqh0oh5CUdcT +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2a:01:e0:a5:fb:80:10:00:00:00:02 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=CA, L=Montreal, ST=Quebec, O=SAFE Inc., OU=Digital Certificate Signing, CN=SAFE Root CA 1 + Validity + Not Before: Jan 20 17:19:55 2024 GMT + Not After : Jun 7 17:19:55 2051 GMT + Subject: C=CA, O=SAFE Inc., OU=Digital Certificate Signing, CN=SAFE Midle Ground CA (2024) - SHA384 - 3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d1:52:9b:dc:10:57:6d:9a:0e:09:5b:1b:aa:fb: + 76:8c:65:b3:f2:ca:75:36:8f:c0:cb:82:d8:2f:5b: + 0e:25:0c:5f:fc:18:94:41:87:5d:75:eb:92:ec:2a: + 87:14:ec:5f:cc:f6:8f:bf:db:4e:a3:07:aa:ec:90: + 3a:48:43:b9:01:84:42:fb:34:0b:06:5f:d8:e4:6d: + e7:55:8f:f6:ad:98:c4:7d:6f:a8:39:de:f8:70:94: + 71:f3:2f:24:1b:3b:ab:42:70:d8:6c:06:ef:81:af: + fa:f7:68:77:66:0e:60:12:df:80:bb:b4:92:4a:1f: + 3e:52:2d:f5:9a:e3:ba:26:d3:88:68:aa:11:88:0f: + b8:be:7e:e3:d7:88:ce:86:09:1a:a3:2c:ce:74:c1: + d7:d6:7a:c4:b5:04:1e:25:ef:b7:15:6a:16:27:4d: + 0f:ed:af:46:fc:a0:57:a2:6d:fe:91:c3:c7:1f:87: + 06:fe:5a:e2:a8:de:33:67:ae:6d:06:84:f2:15:1d: + 9d:ff:11:cf:be:6f:a9:a5:13:13:0b:ef:67:19:1f: + ea:a8:ed:f0:db:f2:1f:ba:8c:a5:1e:b3:54:b7:68: + c3:37:85:db:01:2e:83:4d:e0:06:be:93:54:b0:dc: + 31:23:98:15:b7:ec:b5:82:57:7a:7c:34:6c:3b:2b: + 3b:fa:b3:12:9a:63:63:d9:54:fd:bf:a1:ee:3c:a4: + 47:83:04:60:b9:9b:74:8f:f7:92:93:1d:f5:ea:98: + 87:c4:c9:de:d6:b8:5f:bf:fc:2e:41:e0:55:38:65: + 80:54:02:c6:d9:bd:7d:51:96:ba:55:ad:bf:01:ce: + 31:21:54:1e:56:16:79:7b:97:1a:53:92:86:80:54: + ef:e9:75:ad:21:45:37:82:54:52:ed:c3:37:8c:11: + ab:63:dd:64:ae:15:b4:f5:cc:02:2f:61:ab:42:d6: + c5:a1:c0:dd:19:ef:70:f1:7f:6d:31:af:4e:60:bb: + 83:a1:f7:49:a5:de:94:dd:31:c1:74:4b:11:73:da: + 4d:f4:4e:90:9e:ae:dd:c0:61:d6:6b:54:3f:3a:78: + c3:8b:e4:0e:ba:c6:9c:f3:3f:fb:6c:34:7c:ff:3d: + 65:d7:0b:ec:4c:19:37:51:37:c5:3b:34:7e:55:85: + 10:82:33:30:7f:ff:95:63:5b:45:3c:45:90:34:fb: + 1c:5e:ef:64:a3:a7:a8:58:0f:d0:97:6a:de:5a:8f: + 29:51:6b:14:01:b1:ec:59:74:47:0e:d9:d0:1a:78: + df:16:e5:fe:5b:8b:95:48:0f:26:20:58:ef:14:6a: + 97:ca:c0:b3:7d:ac:7f:8a:6c:59:be:1b:fc:a0:47: + e7:57:b1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + CA Issuers - URI:http://certificates.safe.ca/cacert/safeMDL.pem + OCSP - URI:http://certificates/safe.ca/chkcertstats + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.7438.1.1 + CPS: http://certificates.safe.ca/repository/ + Policy: 2.23.140.1.2.1 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + Full Name: + URI:http://certificates.safe.ca/repository/revoklist.pem + X509v3 Subject Alternative Name: + DNS:certificates.safe.ca, IP Address:192.219.254.53 + X509v3 Authority Key Identifier: + 87:DD:FB:32:49:26:5E:13:F8:B7:F2:DF:EF:9C:F6:85:34:37:7A:D9 + X509v3 Subject Key Identifier: + 9C:BE:0B:C0:22:76:F5:CF:BC:FD:78:9A:92:77:20:FE:BF:96:1E:D8 + Signature Algorithm: ecdsa-with-SHA384 + Signature Value: + 30:46:02:21:00:ff:21:78:ff:d7:43:e7:9d:7d:dd:e6:f1:89: + f9:39:8a:14:e0:46:ca:b2:f2:59:a1:09:70:a0:2d:8b:66:a1: + 65:02:21:00:d6:cf:8e:54:06:f0:d3:4c:23:f6:9d:a7:d5:b7: + 23:6d:b9:c8:18:15:63:a3:92:98:3c:dc:25:18:71:1c:74:68 +-----BEGIN CERTIFICATE----- +MIIFejCCBR+gAwIBAgILKgHgpfuAEAAAAAIwCgYIKoZIzj0EAwMwgYQxCzAJBgNV +BAYTAkNBMREwDwYDVQQHDAhNb250cmVhbDEPMA0GA1UECAwGUXVlYmVjMRIwEAYD +VQQKDAlTQUZFIEluYy4xJDAiBgNVBAsMG0RpZ2l0YWwgQ2VydGlmaWNhdGUgU2ln +bmluZzEXMBUGA1UEAwwOU0FGRSBSb290IENBIDEwIBcNMjQwMTIwMTcxOTU1WhgP +MjA1MTA2MDcxNzE5NTVaMHoxCzAJBgNVBAYTAkNBMRIwEAYDVQQKDAlTQUZFIElu +Yy4xJDAiBgNVBAsMG0RpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzExMC8GA1UE +AwwoU0FGRSBNaWRsZSBHcm91bmQgQ0EgKDIwMjQpIC0gU0hBMzg0IC0gMzCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANFSm9wQV22aDglbG6r7doxls/LK +dTaPwMuC2C9bDiUMX/wYlEGHXXXrkuwqhxTsX8z2j7/bTqMHquyQOkhDuQGEQvs0 +CwZf2ORt51WP9q2YxH1vqDne+HCUcfMvJBs7q0Jw2GwG74Gv+vdod2YOYBLfgLu0 +kkofPlIt9ZrjuibTiGiqEYgPuL5+49eIzoYJGqMsznTB19Z6xLUEHiXvtxVqFidN +D+2vRvygV6Jt/pHDxx+HBv5a4qjeM2eubQaE8hUdnf8Rz75vqaUTEwvvZxkf6qjt +8NvyH7qMpR6zVLdowzeF2wEug03gBr6TVLDcMSOYFbfstYJXenw0bDsrO/qzEppj +Y9lU/b+h7jykR4MEYLmbdI/3kpMd9eqYh8TJ3ta4X7/8LkHgVThlgFQCxtm9fVGW +ulWtvwHOMSFUHlYWeXuXGlOShoBU7+l1rSFFN4JUUu3DN4wRq2PdZK4VtPXMAi9h +q0LWxaHA3RnvcPF/bTGvTmC7g6H3SaXelN0xwXRLEXPaTfROkJ6u3cBh1mtUPzp4 +w4vkDrrGnPM/+2w0fP89ZdcL7EwZN1E3xTs0flWFEIIzMH//lWNbRTxFkDT7HF7v +ZKOnqFgP0Jdq3lqPKVFrFAGx7Fl0Rw7Z0Bp43xbl/luLlUgPJiBY7xRql8rAs32s +f4psWb4b/KBH51exAgMBAAGjggGyMIIBrjAOBgNVHQ8BAf8EBAMCAQYwgYAGCCsG +AQUFBwEBBHQwcjA6BggrBgEFBQcwAoYuaHR0cDovL2NlcnRpZmljYXRlcy5zYWZl +LmNhL2NhY2VydC9zYWZlTURMLnBlbTA0BggrBgEFBQcwAYYoaHR0cDovL2NlcnRp +ZmljYXRlcy9zYWZlLmNhL2Noa2NlcnRzdGF0czBXBgNVHSAEUDBOMEIGCSsGAQQB +ug4BATA1MDMGCCsGAQUFBwIBFidodHRwOi8vY2VydGlmaWNhdGVzLnNhZmUuY2Ev +cmVwb3NpdG9yeS8wCAYGZ4EMAQIBMBIGA1UdEwEB/wQIMAYBAf8CAQAwRQYDVR0f +BD4wPDA6oDigNoY0aHR0cDovL2NlcnRpZmljYXRlcy5zYWZlLmNhL3JlcG9zaXRv +cnkvcmV2b2tsaXN0LnBlbTAlBgNVHREEHjAcghRjZXJ0aWZpY2F0ZXMuc2FmZS5j +YYcEwNv+NTAfBgNVHSMEGDAWgBSH3fsySSZeE/i38t/vnPaFNDd62TAdBgNVHQ4E +FgQUnL4LwCJ29c+8/Xiakncg/r+WHtgwCgYIKoZIzj0EAwMDSQAwRgIhAP8heP/X +Q+edfd3m8Yn5OYoU4EbKsvJZoQlwoC2LZqFlAiEA1s+OVAbw00wj9p2n1bcjbbnI +GBVjo5KYPNwlGHEcdGg= +-----END CERTIFICATE----- diff --git a/certs/localhost-key.pem b/certs/localhost-key.pem new file mode 100644 index 0000000..bc8f96b --- /dev/null +++ b/certs/localhost-key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQC6XzXSBNX02vCx +mW/zQkIOWY17bCSXbSTf6PqDfK6S/dFYHBR+IHFeRFqw6HrORTOVqifvUv69WiN7 +T4skTQv3nJkluLmvjEb3qWwY/zl8qf+a9fDX18rcbF3HCQKDhzcaL/cFuDmvn6sk +OyRI5nKvNhANxty9wt4FT0r92Fs1JLm8zqs3Ovn/LUTCM/JSSjZcX4CnzfcbbVW3 +1hMlctVVTVT/oR59hYvg4hbR0SIhB5mtmlElAnF7VuV3FgcYxv3exODlVQF49jxT +qzUdRPgmr8MRoi1jcynFvbQX94N+DdkK2aEn8ny87pV2aOzEfzVkRNRtQ0aZQFLN +tMAROterfM+HtUEypCMtP8z6smtb3aVYFHokyzomBEmPB4tb0L7C7iTe0XTLBEi+ ++XRaF1IeDsDqAtF6HueilbR3GpZtNIB4hQ+E5jtgJ3VdM2Bta9naua+pz7yuwynK +oxtPO3/6utYB8Ac/fQBF5m5/qmetkNsdKuvkvkMTXi7c3qE2/SCQH6yMPMkOMpbv +qBkdMIfR8kLHVedGJJzSSh9CAffraF/WtZo64lGQlFmdvIPd2InpNK/WQ2aPh4Ur +xrFDtgmSuvTj1jvBWy12zVasf7v7YDClE3ZzNV5n393F/qvlT92AVhmm4NhTsiBc +XDQvoTELEidxtupbLvqjiC/3JFuTDQIDAQABAoICAAgIP3EQPUpivzngQ4dn5SHq +MSNPG1qdXRf7WgSdtIZoQwP5ndZ7vncSGhiCxHwsVldOcI8rdAgkIOBZIsWLPodK +6/zIs9QBhzN4TUzcfxVE3FvI2rrqtXb/gqEn3cBebP0HcS2BbZcImh8jH2K2791m +RpXZar0Q73GqI7DCCNhG/2xIOe/U7l5VjJ+UDo8GXMZpZUmWIl6/vRCBvOyBwPj+ +rrmfr4k4Xrlv9QzQ5xgmVDS7sGCYdNycd6JExESImvtlX83ydnBIqHvwpobe6JT+ +QTl61FrzZSr9DIx14ehmX2LM01m95StdWvqx9fZYByyNnNwiqKHFOGxeLGLxtsa9 +8q9r2NlCWISUrZxs8DJUqOEHBVexocFzoYHTj023nb78LqBIyESnphOQaAXiaFSq +0IWCh7/5BZsG5jcQaDkWBHbv2XcYFtiS8tQ4AvacE77SINWtmcCtYb5e3Zn3oB/r +i20AiQ3CWe5zO5Q9DfJJRj2k+UPXphkuu6uYbATxwYgfpHLeCwWGp10ABBt52Osn +4pyCKY4B6aEDfMY2eta/J/dUHN/0091u7tg7jvgwaJ7ZMR2vAGczLt0nkWFuKyVY +QAdlv1ebBN0jnhYFkELMKJJNYOJom7TaXLlqeGvKfjSavT5ZIBlZb3Hv0JYCZFP4 +L66kGMTD08hjsNg6SWCRAoIBAQDfV1gzXmUt9wgelo9QncIwbEegEC94QwVFNDXH +n90ityNd/6g8dqKcMnOS3m2R08eiFtGTjlokXTv0zL118pu4UN83ee4Lx0p/jfS2 +TWPKYOzltMIKcaSyBF+P4fdMe2QWOYvnhqWDv4hIDuomezuwgB6U+BTC+v3Vihtz +6IAOBfhGh40POC50I++ps2yfANcc4w0/a99tEUp3Pchsiw263w1f0OJZ7yBQL6fA +LeKBRxrljKRFIFCP0JM8XnxyQLz872kaqSwkmu0m+/ickD9Sr+8Gict9EVmuQKBF +e1TW+Kg1Pxi+L/n3csN4RxA+ZBJWKC77yly69W93b+2omiQJAoIBAQDVn/Drra44 +VXtC0irMvfD4v6Qb64wwcBLMgE1qaopso7vZDTKlzQoBgxVK+q8q4kGn4KyHQc94 +Prc/lgVEcxoyxD7GaQwKROTeBapN7WmzYtK9Tp/yqZegoRzkXjO0RxxcQLA5h/Yo +l7k1O8kewfOCrmLx9KUSzo6jWVzB/j5/8Qw1XA6WNvUSnUR61H4LFDwndypzd+V5 +RB3QolRDnz0eDZcSEDdutJ8NcK/Xs2eSGcUgawkD7mbifa96L+JFC+ds9ZrWg9KW +A66KSD7ooPBbU0LP3U/N3KAn9ESoZD+K4qkAvLpsNo9WRcks7lyz7yddc1XI0bKJ +irwzzgwwyl/lAoIBAQCSz4+i9MH93QzxTncWvx0PR54tkXYiz6t/Ojq/5k4uq8QL +3ipw1Gs/0co3GQ9ddKEd43IQVNrcXI009gD0r229UyvoA7Z+95n5Dw91ZpnaRqxy +ssd6pgllG4rVwewV0maQVXOp1dCnMhgbhfJVKVyrQQzZT9oV8Xc6D3bMUmEa1sHF +WwVWo8+leJnqK4+TVbIRww7KSdask1kn2O0OrLlxxX29JkokZBQRocHbik4CPQNp +MXIqHnvWjXy7ikCzueqBOb8VT289ALozjh52jDuT1yKAYcPpiqYw7Tptcgzq4rlv +hvJ00oS2LDJhthTvbki/adq4mOUr4HpNQL4wvmJBAoIBADvxs5MOm3KnWf04KFZn +fjTu4cgL4ry81imYXyDbYJh3oYCYmXu4+3PNKq5thbXM44uOGhuiNeuR/a3UFQpO +Gi3gr5TRaVWAW5CJmm5fjmeN9YC1jWB0gl3Kl+blIDEYOzcP1+Ns6YAegxQTAK6m +0gP7lzw54BBU8eWYb9Tn2PXh2AEpIda4+TAN/WdSNUQ6m16fq8PXAwdyO8ONqYOI +LYg/XALvlf50pKUK1+z5JLj0jkI4hsEZprkrd5Ab26xwWLJUgOxs9SyvP80B1NVG +Q+v8gyT8/yXPIQnVG2b9Km94ht/0FYPEE5ir4HXBNTYwh6VLdejyHt1FluYajYUr +ZJkCggEAaDYyDksmSEb14qAZzTYU2DIi2CglhOvEs8QSObR3KPYBD5roROIVat3X +LEtnnoNkCWGAnSC8PH3iNxh6EqA6Csjf2B/UKBYPy6jyV9HTkKa9aUOMoVYpzhMM +qzo4mCO7n2SKqlNzSLkzNLG5pcyOvVKkW9kEr6ruC3LG/Qd2Nx6xfF+Ien+YAwvP +W+17N2lDDdoa1YlXxIHu/DW5gCskF+WqkcsZAStsK01n1Tb9NcJiVC4QEPu8y57O +RulAtP4OgwwFhzQ1dhT92UFZrH+W28l3F571Nvx5ADPnRtLOB4umT0styUKm322Q +yVX+KcXoeFoZZcQR5s0qu1ZkJNhizw== +-----END PRIVATE KEY----- diff --git a/certs/mailleur_server-cert_x509.pem b/certs/mailleur_server-cert_x509.pem new file mode 100644 index 0000000..0ae6ef6 --- /dev/null +++ b/certs/mailleur_server-cert_x509.pem @@ -0,0 +1,147 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2a:01:e0:a5:fb:80:80:00:00:00:28 + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=CA, O=SAFE Inc., OU=Digital Certificate Signing, CN=SAFE Midle Ground CA (2024) - SHA384 - 3 + Validity + Not Before: Apr 6 11:54:45 2025 GMT + Not After : Apr 6 11:54:45 2050 GMT + Subject: C=CA, ST=Quebec, L=Montreal, O=SAFE Inc., OU=Mailleur email developpement test, CN=mailleur.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:b2:6e:35:f7:8c:eb:07:0d:a1:f8:10:fd:dd:8d: + d9:9e:cf:9f:4b:39:4d:ee:81:5e:b3:5e:a2:67:81: + 9e:b7:ec:b8:bb:08:12:5d:07:01:23:bc:3d:24:82: + a7:b0:a6:b1:56:57:6e:e6:b9:95:8f:fb:7f:12:fd: + ec:91:4b:81:6d:e8:8f:5d:33:c3:e6:db:24:66:f5: + f2:cd:1e:86:8f:23:b6:38:2e:46:c9:94:cd:4c:b6: + 37:41:44:5f:8f:08:36:f7:90:77:97:f6:1d:81:a8: + 44:94:23:30:a8:19:41:bc:b8:d4:52:d9:4c:57:45: + ea:1e:2e:a8:60:9b:c7:34:6d:81:66:5d:68:f8:a5: + 67:31:5a:49:14:13:7c:68:af:d0:ab:6e:e5:2c:da: + 5c:b1:20:78:ff:4b:3c:1e:5a:81:a0:91:66:7f:a9: + 6c:2d:df:b6:4f:89:53:db:62:40:01:ea:ab:d8:9f: + 1d:4b:5c:dc:2d:95:83:73:a2:77:c8:3f:ce:fe:39: + 11:2e:b2:38:17:3d:bc:50:73:50:d0:1a:5b:76:9e: + 44:76:6d:c9:14:53:61:05:31:a6:66:1d:ba:a9:88: + 52:bb:28:a9:bb:de:3e:05:3f:11:6b:ee:14:0b:0f: + f2:79:6a:3c:56:c9:f6:78:0f:d5:2f:8b:7b:ad:23: + 75:f3:53:e7:b4:ab:82:c4:8d:f1:84:f8:82:3e:97: + a6:85:84:18:fc:89:e7:12:95:c9:ed:28:c5:6c:d8: + 84:de:f7:d5:fd:a8:c1:e6:2d:55:75:14:9c:1b:5f: + 89:91:0a:58:0e:ff:92:67:2e:f0:9e:c4:48:30:1a: + be:1d:64:35:ba:87:92:ae:d7:24:5f:08:28:37:b2: + ec:c9:5a:36:84:66:1e:f2:94:73:bc:7e:83:3e:0c: + da:ff:8f:ea:1c:13:94:53:d6:71:8f:a1:52:27:c5: + 0f:31:0b:7d:3a:96:23:f5:cc:bf:4a:9b:8e:08:5a: + 15:ec:4a:6b:db:25:16:21:2c:9b:52:4d:71:d3:6c: + 6f:55:63:cc:28:37:23:58:cf:63:dd:38:79:24:ab: + 46:f9:96:20:6b:b1:77:b4:b8:f1:cf:1e:7e:ae:f5: + 8b:5b:89:98:e5:df:71:d1:b5:66:cd:6f:b6:c2:8f: + 0e:75:59:e1:5f:cf:ab:b3:87:ce:6d:c1:ba:44:68: + 79:70:ae:0b:07:1f:d5:7a:33:0b:13:fd:39:98:5b: + 46:19:e4:a2:bf:f4:06:48:12:01:c7:fc:c8:cc:15: + 81:d6:2e:82:3f:7e:57:b8:a8:06:d8:70:81:f7:c3: + 42:4c:af:48:7a:26:38:96:e2:6f:fc:b3:e6:9f:b8: + 6f:2b:0d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + Authority Information Access: + CA Issuers - URI:http://certificates.safe.ca/cacert/safeMDL.pem + OCSP - URI:http://certificates/safe.ca/chkcertstats + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.7438.1.2 + CPS: http://certificates.safe.ca/policies + Policy: 2.23.140.1.1 + X509v3 Basic Constraints: + CA:FALSE + X509v3 CRL Distribution Points: + Full Name: + URI:http://certificates.safe.ca/repository/revoklist.pem + X509v3 Subject Alternative Name: + DNS:mailleur.example.com, IP Address:127.127.10.25 + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication, E-mail Protection + X509v3 Subject Key Identifier: + 89:FC:FA:27:85:1A:75:70:74:B6:47:9C:2A:B6:1F:90:58:BF:C5:C1 + X509v3 Authority Key Identifier: + 9C:BE:0B:C0:22:76:F5:CF:BC:FD:78:9A:92:77:20:FE:BF:96:1E:D8 + Signature Algorithm: sha384WithRSAEncryption + Signature Value: + 68:21:b6:11:60:a6:ea:31:af:9a:31:64:be:88:f9:60:17:d7: + 4b:d5:95:a8:cd:bd:04:10:2a:3d:f9:61:25:e1:44:87:5d:53: + 81:47:a5:d4:46:32:a8:ef:f3:be:1c:36:71:19:77:4a:f8:15: + 43:38:c5:61:62:09:7c:1e:d6:0c:72:b9:9c:97:eb:c2:ce:b6: + d0:14:0b:7c:01:8c:1d:05:bf:7e:29:09:9f:13:e2:e5:1d:d8: + 89:78:0e:f8:af:87:2b:94:dc:c3:27:9c:cd:db:33:f7:60:7c: + 9a:0f:ab:09:79:dd:5f:b4:b2:60:54:a5:88:9c:76:3f:6e:cc: + 91:b3:a6:13:63:64:be:b0:2e:37:9c:80:db:e1:95:11:12:e8: + 0a:5b:bd:b0:b9:49:ee:cd:6c:34:64:ef:85:57:39:d7:2f:8d: + a5:b6:4d:98:8f:c5:2e:2d:d5:97:8b:cc:49:84:ba:29:a9:e9: + 40:b7:2a:56:f4:0f:cb:02:d2:2f:ec:5d:4c:2c:6b:88:e1:b6: + 01:cb:2c:6e:c8:49:a6:2c:48:d3:81:9c:0d:6f:07:c5:56:7e: + 47:f4:7d:14:81:62:e1:29:b6:28:91:7f:db:fc:47:7c:7f:e1: + fe:9c:08:ab:64:22:f8:cf:bb:8f:9e:75:1e:07:ac:dd:56:88: + 95:ca:84:42:1f:b0:90:ca:3a:7b:24:00:43:44:57:3a:83:67: + f7:15:65:14:bf:96:85:39:d9:53:6c:e3:f2:dc:0f:e2:bb:d7: + 0f:81:71:00:16:bd:1f:82:2b:af:f7:2b:49:04:9f:1c:fe:3b: + bb:da:26:a9:ba:8b:5f:70:f4:68:a3:fc:88:4b:cf:34:47:54: + eb:3a:65:4d:24:c7:66:60:61:55:03:81:10:a4:b3:30:3e:40: + ca:e8:0c:e8:24:9f:0e:20:5c:1f:ea:65:bd:5b:23:cd:95:f8: + 1c:74:ef:25:2c:55:7a:d8:85:eb:33:fe:98:8e:cd:bc:d1:6e: + f9:38:71:5f:8b:cb:09:2e:3d:78:b4:37:4b:70:60:60:85:f0: + 34:78:e7:4c:05:47:a7:ba:46:58:7b:4a:2e:8c:03:5f:49:ea: + a8:c4:81:4e:08:c7:50:e2:43:b2:22:d2:cb:6a:e6:69:71:4e: + a5:f5:49:a5:fd:03:07:25:e8:43:2e:fd:fa:1d:f5:9c:24:90: + 7d:29:e7:40:f8:e5:b0:ea:02:a4:c5:e5:3a:f8:d0:a7:88:31: + 1a:3d:8d:3a:fd:ac:cd:02:6a:4a:08:d4:dd:a9:a3:76:45:2a: + d1:43:3a:17:be:75:50:33:43:66:7b:1c:a6:cc:0e:0d:90:5c: + 85:7d:6c:cc:b0:56:44:45 +-----BEGIN CERTIFICATE----- +MIIHYjCCBUqgAwIBAgILKgHgpfuAgAAAACgwDQYJKoZIhvcNAQEMBQAwejELMAkG +A1UEBhMCQ0ExEjAQBgNVBAoMCVNBRkUgSW5jLjEkMCIGA1UECwwbRGlnaXRhbCBD +ZXJ0aWZpY2F0ZSBTaWduaW5nMTEwLwYDVQQDDChTQUZFIE1pZGxlIEdyb3VuZCBD +QSAoMjAyNCkgLSBTSEEzODQgLSAzMCAXDTI1MDQwNjExNTQ0NVoYDzIwNTAwNDA2 +MTE1NDQ1WjCBkDELMAkGA1UEBhMCQ0ExDzANBgNVBAgMBlF1ZWJlYzERMA8GA1UE +BwwITW9udHJlYWwxEjAQBgNVBAoMCVNBRkUgSW5jLjEqMCgGA1UECwwhTWFpbGxl +dXIgZW1haWwgZGV2ZWxvcHBlbWVudCB0ZXN0MR0wGwYDVQQDDBRtYWlsbGV1ci5l +eGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALJuNfeM +6wcNofgQ/d2N2Z7Pn0s5Te6BXrNeomeBnrfsuLsIEl0HASO8PSSCp7CmsVZXbua5 +lY/7fxL97JFLgW3oj10zw+bbJGb18s0eho8jtjguRsmUzUy2N0FEX48INveQd5f2 +HYGoRJQjMKgZQby41FLZTFdF6h4uqGCbxzRtgWZdaPilZzFaSRQTfGiv0Ktu5Sza +XLEgeP9LPB5agaCRZn+pbC3ftk+JU9tiQAHqq9ifHUtc3C2Vg3Oid8g/zv45ES6y +OBc9vFBzUNAaW3aeRHZtyRRTYQUxpmYduqmIUrsoqbvePgU/EWvuFAsP8nlqPFbJ +9ngP1S+Le60jdfNT57SrgsSN8YT4gj6XpoWEGPyJ5xKVye0oxWzYhN731f2oweYt +VXUUnBtfiZEKWA7/kmcu8J7ESDAavh1kNbqHkq7XJF8IKDey7MlaNoRmHvKUc7x+ +gz4M2v+P6hwTlFPWcY+hUifFDzELfTqWI/XMv0qbjghaFexKa9slFiEsm1JNcdNs +b1VjzCg3I1jPY904eSSrRvmWIGuxd7S48c8efq71i1uJmOXfcdG1Zs1vtsKPDnVZ +4V/Pq7OHzm3BukRoeXCuCwcf1XozCxP9OZhbRhnkor/0BkgSAcf8yMwVgdYugj9+ +V7ioBthwgffDQkyvSHomOJbib/yz5p+4bysNAgMBAAGjggHOMIIByjAOBgNVHQ8B +Af8EBAMCBaAwgYAGCCsGAQUFBwEBBHQwcjA6BggrBgEFBQcwAoYuaHR0cDovL2Nl +cnRpZmljYXRlcy5zYWZlLmNhL2NhY2VydC9zYWZlTURMLnBlbTA0BggrBgEFBQcw +AYYoaHR0cDovL2NlcnRpZmljYXRlcy9zYWZlLmNhL2Noa2NlcnRzdGF0czBTBgNV +HSAETDBKMD8GCSsGAQQBug4BAjAyMDAGCCsGAQUFBwIBFiRodHRwOi8vY2VydGlm +aWNhdGVzLnNhZmUuY2EvcG9saWNpZXMwBwYFZ4EMAQEwCQYDVR0TBAIwADBFBgNV +HR8EPjA8MDqgOKA2hjRodHRwOi8vY2VydGlmaWNhdGVzLnNhZmUuY2EvcmVwb3Np +dG9yeS9yZXZva2xpc3QucGVtMCUGA1UdEQQeMByCFG1haWxsZXVyLmV4YW1wbGUu +Y29thwR/fwoZMCcGA1UdJQQgMB4GCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUH +AwQwHQYDVR0OBBYEFIn8+ieFGnVwdLZHnCq2H5BYv8XBMB8GA1UdIwQYMBaAFJy+ +C8AidvXPvP14mpJ3IP6/lh7YMA0GCSqGSIb3DQEBDAUAA4ICAQBoIbYRYKbqMa+a +MWS+iPlgF9dL1ZWozb0EECo9+WEl4USHXVOBR6XURjKo7/O+HDZxGXdK+BVDOMVh +Ygl8HtYMcrmcl+vCzrbQFAt8AYwdBb9+KQmfE+LlHdiJeA74r4crlNzDJ5zN2zP3 +YHyaD6sJed1ftLJgVKWInHY/bsyRs6YTY2S+sC43nIDb4ZUREugKW72wuUnuzWw0 +ZO+FVznXL42ltk2Yj8UuLdWXi8xJhLopqelAtypW9A/LAtIv7F1MLGuI4bYByyxu +yEmmLEjTgZwNbwfFVn5H9H0UgWLhKbYokX/b/Ed8f+H+nAirZCL4z7uPnnUeB6zd +VoiVyoRCH7CQyjp7JABDRFc6g2f3FWUUv5aFOdlTbOPy3A/iu9cPgXEAFr0fgiuv +9ytJBJ8c/ju72iapuotfcPRoo/yIS880R1TrOmVNJMdmYGFVA4EQpLMwPkDK6Azo +JJ8OIFwf6mW9WyPNlfgcdO8lLFV62IXrM/6Yjs280W75OHFfi8sJLj14tDdLcGBg +hfA0eOdMBUenukZYe0oujANfSeqoxIFOCMdQ4kOyItLLauZpcU6l9Uml/QMHJehD +Lv36HfWcJJB9KedA+OWw6gKkxeU6+NCniDEaPY06/azNAmpKCNTdqaN2RSrRQzoX +vnVQM0NmexymzA4NkFyFfWzMsFZERQ== +-----END CERTIFICATE----- diff --git a/certs/mailleur_server-chain-cert_x509.pem b/certs/mailleur_server-chain-cert_x509.pem new file mode 100644 index 0000000..ddd18fa --- /dev/null +++ b/certs/mailleur_server-chain-cert_x509.pem @@ -0,0 +1,257 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2a:01:e0:a5:fb:80:80:00:00:00:28 + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=CA, O=SAFE Inc., OU=Digital Certificate Signing, CN=SAFE Midle Ground CA (2024) - SHA384 - 3 + Validity + Not Before: Apr 6 11:54:45 2025 GMT + Not After : Apr 6 11:54:45 2050 GMT + Subject: C=CA, ST=Quebec, L=Montreal, O=SAFE Inc., OU=Mailleur email developpement test, CN=mailleur.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:b2:6e:35:f7:8c:eb:07:0d:a1:f8:10:fd:dd:8d: + d9:9e:cf:9f:4b:39:4d:ee:81:5e:b3:5e:a2:67:81: + 9e:b7:ec:b8:bb:08:12:5d:07:01:23:bc:3d:24:82: + a7:b0:a6:b1:56:57:6e:e6:b9:95:8f:fb:7f:12:fd: + ec:91:4b:81:6d:e8:8f:5d:33:c3:e6:db:24:66:f5: + f2:cd:1e:86:8f:23:b6:38:2e:46:c9:94:cd:4c:b6: + 37:41:44:5f:8f:08:36:f7:90:77:97:f6:1d:81:a8: + 44:94:23:30:a8:19:41:bc:b8:d4:52:d9:4c:57:45: + ea:1e:2e:a8:60:9b:c7:34:6d:81:66:5d:68:f8:a5: + 67:31:5a:49:14:13:7c:68:af:d0:ab:6e:e5:2c:da: + 5c:b1:20:78:ff:4b:3c:1e:5a:81:a0:91:66:7f:a9: + 6c:2d:df:b6:4f:89:53:db:62:40:01:ea:ab:d8:9f: + 1d:4b:5c:dc:2d:95:83:73:a2:77:c8:3f:ce:fe:39: + 11:2e:b2:38:17:3d:bc:50:73:50:d0:1a:5b:76:9e: + 44:76:6d:c9:14:53:61:05:31:a6:66:1d:ba:a9:88: + 52:bb:28:a9:bb:de:3e:05:3f:11:6b:ee:14:0b:0f: + f2:79:6a:3c:56:c9:f6:78:0f:d5:2f:8b:7b:ad:23: + 75:f3:53:e7:b4:ab:82:c4:8d:f1:84:f8:82:3e:97: + a6:85:84:18:fc:89:e7:12:95:c9:ed:28:c5:6c:d8: + 84:de:f7:d5:fd:a8:c1:e6:2d:55:75:14:9c:1b:5f: + 89:91:0a:58:0e:ff:92:67:2e:f0:9e:c4:48:30:1a: + be:1d:64:35:ba:87:92:ae:d7:24:5f:08:28:37:b2: + ec:c9:5a:36:84:66:1e:f2:94:73:bc:7e:83:3e:0c: + da:ff:8f:ea:1c:13:94:53:d6:71:8f:a1:52:27:c5: + 0f:31:0b:7d:3a:96:23:f5:cc:bf:4a:9b:8e:08:5a: + 15:ec:4a:6b:db:25:16:21:2c:9b:52:4d:71:d3:6c: + 6f:55:63:cc:28:37:23:58:cf:63:dd:38:79:24:ab: + 46:f9:96:20:6b:b1:77:b4:b8:f1:cf:1e:7e:ae:f5: + 8b:5b:89:98:e5:df:71:d1:b5:66:cd:6f:b6:c2:8f: + 0e:75:59:e1:5f:cf:ab:b3:87:ce:6d:c1:ba:44:68: + 79:70:ae:0b:07:1f:d5:7a:33:0b:13:fd:39:98:5b: + 46:19:e4:a2:bf:f4:06:48:12:01:c7:fc:c8:cc:15: + 81:d6:2e:82:3f:7e:57:b8:a8:06:d8:70:81:f7:c3: + 42:4c:af:48:7a:26:38:96:e2:6f:fc:b3:e6:9f:b8: + 6f:2b:0d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + Authority Information Access: + CA Issuers - URI:http://certificates.safe.ca/cacert/safeMDL.pem + OCSP - URI:http://certificates/safe.ca/chkcertstats + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.7438.1.2 + CPS: http://certificates.safe.ca/policies + Policy: 2.23.140.1.1 + X509v3 Basic Constraints: + CA:FALSE + X509v3 CRL Distribution Points: + Full Name: + URI:http://certificates.safe.ca/repository/revoklist.pem + X509v3 Subject Alternative Name: + DNS:mailleur.example.com, IP Address:127.127.10.25 + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication, E-mail Protection + X509v3 Subject Key Identifier: + 89:FC:FA:27:85:1A:75:70:74:B6:47:9C:2A:B6:1F:90:58:BF:C5:C1 + X509v3 Authority Key Identifier: + 9C:BE:0B:C0:22:76:F5:CF:BC:FD:78:9A:92:77:20:FE:BF:96:1E:D8 + Signature Algorithm: sha384WithRSAEncryption + Signature Value: + 68:21:b6:11:60:a6:ea:31:af:9a:31:64:be:88:f9:60:17:d7: + 4b:d5:95:a8:cd:bd:04:10:2a:3d:f9:61:25:e1:44:87:5d:53: + 81:47:a5:d4:46:32:a8:ef:f3:be:1c:36:71:19:77:4a:f8:15: + 43:38:c5:61:62:09:7c:1e:d6:0c:72:b9:9c:97:eb:c2:ce:b6: + d0:14:0b:7c:01:8c:1d:05:bf:7e:29:09:9f:13:e2:e5:1d:d8: + 89:78:0e:f8:af:87:2b:94:dc:c3:27:9c:cd:db:33:f7:60:7c: + 9a:0f:ab:09:79:dd:5f:b4:b2:60:54:a5:88:9c:76:3f:6e:cc: + 91:b3:a6:13:63:64:be:b0:2e:37:9c:80:db:e1:95:11:12:e8: + 0a:5b:bd:b0:b9:49:ee:cd:6c:34:64:ef:85:57:39:d7:2f:8d: + a5:b6:4d:98:8f:c5:2e:2d:d5:97:8b:cc:49:84:ba:29:a9:e9: + 40:b7:2a:56:f4:0f:cb:02:d2:2f:ec:5d:4c:2c:6b:88:e1:b6: + 01:cb:2c:6e:c8:49:a6:2c:48:d3:81:9c:0d:6f:07:c5:56:7e: + 47:f4:7d:14:81:62:e1:29:b6:28:91:7f:db:fc:47:7c:7f:e1: + fe:9c:08:ab:64:22:f8:cf:bb:8f:9e:75:1e:07:ac:dd:56:88: + 95:ca:84:42:1f:b0:90:ca:3a:7b:24:00:43:44:57:3a:83:67: + f7:15:65:14:bf:96:85:39:d9:53:6c:e3:f2:dc:0f:e2:bb:d7: + 0f:81:71:00:16:bd:1f:82:2b:af:f7:2b:49:04:9f:1c:fe:3b: + bb:da:26:a9:ba:8b:5f:70:f4:68:a3:fc:88:4b:cf:34:47:54: + eb:3a:65:4d:24:c7:66:60:61:55:03:81:10:a4:b3:30:3e:40: + ca:e8:0c:e8:24:9f:0e:20:5c:1f:ea:65:bd:5b:23:cd:95:f8: + 1c:74:ef:25:2c:55:7a:d8:85:eb:33:fe:98:8e:cd:bc:d1:6e: + f9:38:71:5f:8b:cb:09:2e:3d:78:b4:37:4b:70:60:60:85:f0: + 34:78:e7:4c:05:47:a7:ba:46:58:7b:4a:2e:8c:03:5f:49:ea: + a8:c4:81:4e:08:c7:50:e2:43:b2:22:d2:cb:6a:e6:69:71:4e: + a5:f5:49:a5:fd:03:07:25:e8:43:2e:fd:fa:1d:f5:9c:24:90: + 7d:29:e7:40:f8:e5:b0:ea:02:a4:c5:e5:3a:f8:d0:a7:88:31: + 1a:3d:8d:3a:fd:ac:cd:02:6a:4a:08:d4:dd:a9:a3:76:45:2a: + d1:43:3a:17:be:75:50:33:43:66:7b:1c:a6:cc:0e:0d:90:5c: + 85:7d:6c:cc:b0:56:44:45 +-----BEGIN CERTIFICATE----- +MIIHYjCCBUqgAwIBAgILKgHgpfuAgAAAACgwDQYJKoZIhvcNAQEMBQAwejELMAkG +A1UEBhMCQ0ExEjAQBgNVBAoMCVNBRkUgSW5jLjEkMCIGA1UECwwbRGlnaXRhbCBD +ZXJ0aWZpY2F0ZSBTaWduaW5nMTEwLwYDVQQDDChTQUZFIE1pZGxlIEdyb3VuZCBD +QSAoMjAyNCkgLSBTSEEzODQgLSAzMCAXDTI1MDQwNjExNTQ0NVoYDzIwNTAwNDA2 +MTE1NDQ1WjCBkDELMAkGA1UEBhMCQ0ExDzANBgNVBAgMBlF1ZWJlYzERMA8GA1UE +BwwITW9udHJlYWwxEjAQBgNVBAoMCVNBRkUgSW5jLjEqMCgGA1UECwwhTWFpbGxl +dXIgZW1haWwgZGV2ZWxvcHBlbWVudCB0ZXN0MR0wGwYDVQQDDBRtYWlsbGV1ci5l +eGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALJuNfeM +6wcNofgQ/d2N2Z7Pn0s5Te6BXrNeomeBnrfsuLsIEl0HASO8PSSCp7CmsVZXbua5 +lY/7fxL97JFLgW3oj10zw+bbJGb18s0eho8jtjguRsmUzUy2N0FEX48INveQd5f2 +HYGoRJQjMKgZQby41FLZTFdF6h4uqGCbxzRtgWZdaPilZzFaSRQTfGiv0Ktu5Sza +XLEgeP9LPB5agaCRZn+pbC3ftk+JU9tiQAHqq9ifHUtc3C2Vg3Oid8g/zv45ES6y +OBc9vFBzUNAaW3aeRHZtyRRTYQUxpmYduqmIUrsoqbvePgU/EWvuFAsP8nlqPFbJ +9ngP1S+Le60jdfNT57SrgsSN8YT4gj6XpoWEGPyJ5xKVye0oxWzYhN731f2oweYt +VXUUnBtfiZEKWA7/kmcu8J7ESDAavh1kNbqHkq7XJF8IKDey7MlaNoRmHvKUc7x+ +gz4M2v+P6hwTlFPWcY+hUifFDzELfTqWI/XMv0qbjghaFexKa9slFiEsm1JNcdNs +b1VjzCg3I1jPY904eSSrRvmWIGuxd7S48c8efq71i1uJmOXfcdG1Zs1vtsKPDnVZ +4V/Pq7OHzm3BukRoeXCuCwcf1XozCxP9OZhbRhnkor/0BkgSAcf8yMwVgdYugj9+ +V7ioBthwgffDQkyvSHomOJbib/yz5p+4bysNAgMBAAGjggHOMIIByjAOBgNVHQ8B +Af8EBAMCBaAwgYAGCCsGAQUFBwEBBHQwcjA6BggrBgEFBQcwAoYuaHR0cDovL2Nl +cnRpZmljYXRlcy5zYWZlLmNhL2NhY2VydC9zYWZlTURMLnBlbTA0BggrBgEFBQcw +AYYoaHR0cDovL2NlcnRpZmljYXRlcy9zYWZlLmNhL2Noa2NlcnRzdGF0czBTBgNV +HSAETDBKMD8GCSsGAQQBug4BAjAyMDAGCCsGAQUFBwIBFiRodHRwOi8vY2VydGlm +aWNhdGVzLnNhZmUuY2EvcG9saWNpZXMwBwYFZ4EMAQEwCQYDVR0TBAIwADBFBgNV +HR8EPjA8MDqgOKA2hjRodHRwOi8vY2VydGlmaWNhdGVzLnNhZmUuY2EvcmVwb3Np +dG9yeS9yZXZva2xpc3QucGVtMCUGA1UdEQQeMByCFG1haWxsZXVyLmV4YW1wbGUu +Y29thwR/fwoZMCcGA1UdJQQgMB4GCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUH +AwQwHQYDVR0OBBYEFIn8+ieFGnVwdLZHnCq2H5BYv8XBMB8GA1UdIwQYMBaAFJy+ +C8AidvXPvP14mpJ3IP6/lh7YMA0GCSqGSIb3DQEBDAUAA4ICAQBoIbYRYKbqMa+a +MWS+iPlgF9dL1ZWozb0EECo9+WEl4USHXVOBR6XURjKo7/O+HDZxGXdK+BVDOMVh +Ygl8HtYMcrmcl+vCzrbQFAt8AYwdBb9+KQmfE+LlHdiJeA74r4crlNzDJ5zN2zP3 +YHyaD6sJed1ftLJgVKWInHY/bsyRs6YTY2S+sC43nIDb4ZUREugKW72wuUnuzWw0 +ZO+FVznXL42ltk2Yj8UuLdWXi8xJhLopqelAtypW9A/LAtIv7F1MLGuI4bYByyxu +yEmmLEjTgZwNbwfFVn5H9H0UgWLhKbYokX/b/Ed8f+H+nAirZCL4z7uPnnUeB6zd +VoiVyoRCH7CQyjp7JABDRFc6g2f3FWUUv5aFOdlTbOPy3A/iu9cPgXEAFr0fgiuv +9ytJBJ8c/ju72iapuotfcPRoo/yIS880R1TrOmVNJMdmYGFVA4EQpLMwPkDK6Azo +JJ8OIFwf6mW9WyPNlfgcdO8lLFV62IXrM/6Yjs280W75OHFfi8sJLj14tDdLcGBg +hfA0eOdMBUenukZYe0oujANfSeqoxIFOCMdQ4kOyItLLauZpcU6l9Uml/QMHJehD +Lv36HfWcJJB9KedA+OWw6gKkxeU6+NCniDEaPY06/azNAmpKCNTdqaN2RSrRQzoX +vnVQM0NmexymzA4NkFyFfWzMsFZERQ== +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2a:01:e0:a5:fb:80:10:00:00:00:02 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=CA, L=Montreal, ST=Quebec, O=SAFE Inc., OU=Digital Certificate Signing, CN=SAFE Root CA 1 + Validity + Not Before: Jan 20 17:19:55 2024 GMT + Not After : Jun 7 17:19:55 2051 GMT + Subject: C=CA, O=SAFE Inc., OU=Digital Certificate Signing, CN=SAFE Midle Ground CA (2024) - SHA384 - 3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d1:52:9b:dc:10:57:6d:9a:0e:09:5b:1b:aa:fb: + 76:8c:65:b3:f2:ca:75:36:8f:c0:cb:82:d8:2f:5b: + 0e:25:0c:5f:fc:18:94:41:87:5d:75:eb:92:ec:2a: + 87:14:ec:5f:cc:f6:8f:bf:db:4e:a3:07:aa:ec:90: + 3a:48:43:b9:01:84:42:fb:34:0b:06:5f:d8:e4:6d: + e7:55:8f:f6:ad:98:c4:7d:6f:a8:39:de:f8:70:94: + 71:f3:2f:24:1b:3b:ab:42:70:d8:6c:06:ef:81:af: + fa:f7:68:77:66:0e:60:12:df:80:bb:b4:92:4a:1f: + 3e:52:2d:f5:9a:e3:ba:26:d3:88:68:aa:11:88:0f: + b8:be:7e:e3:d7:88:ce:86:09:1a:a3:2c:ce:74:c1: + d7:d6:7a:c4:b5:04:1e:25:ef:b7:15:6a:16:27:4d: + 0f:ed:af:46:fc:a0:57:a2:6d:fe:91:c3:c7:1f:87: + 06:fe:5a:e2:a8:de:33:67:ae:6d:06:84:f2:15:1d: + 9d:ff:11:cf:be:6f:a9:a5:13:13:0b:ef:67:19:1f: + ea:a8:ed:f0:db:f2:1f:ba:8c:a5:1e:b3:54:b7:68: + c3:37:85:db:01:2e:83:4d:e0:06:be:93:54:b0:dc: + 31:23:98:15:b7:ec:b5:82:57:7a:7c:34:6c:3b:2b: + 3b:fa:b3:12:9a:63:63:d9:54:fd:bf:a1:ee:3c:a4: + 47:83:04:60:b9:9b:74:8f:f7:92:93:1d:f5:ea:98: + 87:c4:c9:de:d6:b8:5f:bf:fc:2e:41:e0:55:38:65: + 80:54:02:c6:d9:bd:7d:51:96:ba:55:ad:bf:01:ce: + 31:21:54:1e:56:16:79:7b:97:1a:53:92:86:80:54: + ef:e9:75:ad:21:45:37:82:54:52:ed:c3:37:8c:11: + ab:63:dd:64:ae:15:b4:f5:cc:02:2f:61:ab:42:d6: + c5:a1:c0:dd:19:ef:70:f1:7f:6d:31:af:4e:60:bb: + 83:a1:f7:49:a5:de:94:dd:31:c1:74:4b:11:73:da: + 4d:f4:4e:90:9e:ae:dd:c0:61:d6:6b:54:3f:3a:78: + c3:8b:e4:0e:ba:c6:9c:f3:3f:fb:6c:34:7c:ff:3d: + 65:d7:0b:ec:4c:19:37:51:37:c5:3b:34:7e:55:85: + 10:82:33:30:7f:ff:95:63:5b:45:3c:45:90:34:fb: + 1c:5e:ef:64:a3:a7:a8:58:0f:d0:97:6a:de:5a:8f: + 29:51:6b:14:01:b1:ec:59:74:47:0e:d9:d0:1a:78: + df:16:e5:fe:5b:8b:95:48:0f:26:20:58:ef:14:6a: + 97:ca:c0:b3:7d:ac:7f:8a:6c:59:be:1b:fc:a0:47: + e7:57:b1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + CA Issuers - URI:http://certificates.safe.ca/cacert/safeMDL.pem + OCSP - URI:http://certificates/safe.ca/chkcertstats + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.7438.1.1 + CPS: http://certificates.safe.ca/repository/ + Policy: 2.23.140.1.2.1 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + Full Name: + URI:http://certificates.safe.ca/repository/revoklist.pem + X509v3 Subject Alternative Name: + DNS:certificates.safe.ca, IP Address:192.219.254.53 + X509v3 Authority Key Identifier: + 87:DD:FB:32:49:26:5E:13:F8:B7:F2:DF:EF:9C:F6:85:34:37:7A:D9 + X509v3 Subject Key Identifier: + 9C:BE:0B:C0:22:76:F5:CF:BC:FD:78:9A:92:77:20:FE:BF:96:1E:D8 + Signature Algorithm: ecdsa-with-SHA384 + Signature Value: + 30:46:02:21:00:ff:21:78:ff:d7:43:e7:9d:7d:dd:e6:f1:89: + f9:39:8a:14:e0:46:ca:b2:f2:59:a1:09:70:a0:2d:8b:66:a1: + 65:02:21:00:d6:cf:8e:54:06:f0:d3:4c:23:f6:9d:a7:d5:b7: + 23:6d:b9:c8:18:15:63:a3:92:98:3c:dc:25:18:71:1c:74:68 +-----BEGIN CERTIFICATE----- +MIIFejCCBR+gAwIBAgILKgHgpfuAEAAAAAIwCgYIKoZIzj0EAwMwgYQxCzAJBgNV +BAYTAkNBMREwDwYDVQQHDAhNb250cmVhbDEPMA0GA1UECAwGUXVlYmVjMRIwEAYD +VQQKDAlTQUZFIEluYy4xJDAiBgNVBAsMG0RpZ2l0YWwgQ2VydGlmaWNhdGUgU2ln +bmluZzEXMBUGA1UEAwwOU0FGRSBSb290IENBIDEwIBcNMjQwMTIwMTcxOTU1WhgP +MjA1MTA2MDcxNzE5NTVaMHoxCzAJBgNVBAYTAkNBMRIwEAYDVQQKDAlTQUZFIElu +Yy4xJDAiBgNVBAsMG0RpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzExMC8GA1UE +AwwoU0FGRSBNaWRsZSBHcm91bmQgQ0EgKDIwMjQpIC0gU0hBMzg0IC0gMzCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANFSm9wQV22aDglbG6r7doxls/LK +dTaPwMuC2C9bDiUMX/wYlEGHXXXrkuwqhxTsX8z2j7/bTqMHquyQOkhDuQGEQvs0 +CwZf2ORt51WP9q2YxH1vqDne+HCUcfMvJBs7q0Jw2GwG74Gv+vdod2YOYBLfgLu0 +kkofPlIt9ZrjuibTiGiqEYgPuL5+49eIzoYJGqMsznTB19Z6xLUEHiXvtxVqFidN +D+2vRvygV6Jt/pHDxx+HBv5a4qjeM2eubQaE8hUdnf8Rz75vqaUTEwvvZxkf6qjt +8NvyH7qMpR6zVLdowzeF2wEug03gBr6TVLDcMSOYFbfstYJXenw0bDsrO/qzEppj +Y9lU/b+h7jykR4MEYLmbdI/3kpMd9eqYh8TJ3ta4X7/8LkHgVThlgFQCxtm9fVGW +ulWtvwHOMSFUHlYWeXuXGlOShoBU7+l1rSFFN4JUUu3DN4wRq2PdZK4VtPXMAi9h +q0LWxaHA3RnvcPF/bTGvTmC7g6H3SaXelN0xwXRLEXPaTfROkJ6u3cBh1mtUPzp4 +w4vkDrrGnPM/+2w0fP89ZdcL7EwZN1E3xTs0flWFEIIzMH//lWNbRTxFkDT7HF7v +ZKOnqFgP0Jdq3lqPKVFrFAGx7Fl0Rw7Z0Bp43xbl/luLlUgPJiBY7xRql8rAs32s +f4psWb4b/KBH51exAgMBAAGjggGyMIIBrjAOBgNVHQ8BAf8EBAMCAQYwgYAGCCsG +AQUFBwEBBHQwcjA6BggrBgEFBQcwAoYuaHR0cDovL2NlcnRpZmljYXRlcy5zYWZl +LmNhL2NhY2VydC9zYWZlTURMLnBlbTA0BggrBgEFBQcwAYYoaHR0cDovL2NlcnRp +ZmljYXRlcy9zYWZlLmNhL2Noa2NlcnRzdGF0czBXBgNVHSAEUDBOMEIGCSsGAQQB +ug4BATA1MDMGCCsGAQUFBwIBFidodHRwOi8vY2VydGlmaWNhdGVzLnNhZmUuY2Ev +cmVwb3NpdG9yeS8wCAYGZ4EMAQIBMBIGA1UdEwEB/wQIMAYBAf8CAQAwRQYDVR0f +BD4wPDA6oDigNoY0aHR0cDovL2NlcnRpZmljYXRlcy5zYWZlLmNhL3JlcG9zaXRv +cnkvcmV2b2tsaXN0LnBlbTAlBgNVHREEHjAcghRjZXJ0aWZpY2F0ZXMuc2FmZS5j +YYcEwNv+NTAfBgNVHSMEGDAWgBSH3fsySSZeE/i38t/vnPaFNDd62TAdBgNVHQ4E +FgQUnL4LwCJ29c+8/Xiakncg/r+WHtgwCgYIKoZIzj0EAwMDSQAwRgIhAP8heP/X +Q+edfd3m8Yn5OYoU4EbKsvJZoQlwoC2LZqFlAiEA1s+OVAbw00wj9p2n1bcjbbnI +GBVjo5KYPNwlGHEcdGg= +-----END CERTIFICATE----- diff --git a/certs/mailleur_server-key.pem b/certs/mailleur_server-key.pem new file mode 100644 index 0000000..f8aea13 --- /dev/null +++ b/certs/mailleur_server-key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCybjX3jOsHDaH4 +EP3djdmez59LOU3ugV6zXqJngZ637Li7CBJdBwEjvD0kgqewprFWV27muZWP+38S +/eyRS4Ft6I9dM8Pm2yRm9fLNHoaPI7Y4LkbJlM1MtjdBRF+PCDb3kHeX9h2BqESU +IzCoGUG8uNRS2UxXReoeLqhgm8c0bYFmXWj4pWcxWkkUE3xor9CrbuUs2lyxIHj/ +SzweWoGgkWZ/qWwt37ZPiVPbYkAB6qvYnx1LXNwtlYNzonfIP87+OREusjgXPbxQ +c1DQGlt2nkR2bckUU2EFMaZmHbqpiFK7KKm73j4FPxFr7hQLD/J5ajxWyfZ4D9Uv +i3utI3XzU+e0q4LEjfGE+II+l6aFhBj8iecSlcntKMVs2ITe99X9qMHmLVV1FJwb +X4mRClgO/5JnLvCexEgwGr4dZDW6h5Ku1yRfCCg3suzJWjaEZh7ylHO8foM+DNr/ +j+ocE5RT1nGPoVInxQ8xC306liP1zL9Km44IWhXsSmvbJRYhLJtSTXHTbG9VY8wo +NyNYz2PdOHkkq0b5liBrsXe0uPHPHn6u9YtbiZjl33HRtWbNb7bCjw51WeFfz6uz +h85twbpEaHlwrgsHH9V6MwsT/TmYW0YZ5KK/9AZIEgHH/MjMFYHWLoI/fle4qAbY +cIH3w0JMr0h6JjiW4m/8s+afuG8rDQIDAQABAoICAB9WdHOBJDElr44AO/oKxQ8b +o3xEeP+76HxD0W2w6gWfFZXBtenxRj22vJ1aNiX0LN6/deqfaxlx4BBfmQousvFx +ACbsJcq4r9TGewmUBCmFKeaFmCik0gbYVO2JWugl1vOVg6+kieug+ER1RsErSGyj +IKVZZUtJq/P3mVp4WZ0HY4vtOXe8IxrbosycHIRNZq6JSEZfppp0W9PorIsfNbeT ++ebPhICtExm2gowcHiZIBz0BOxWmnkQCR6dKQFPjAxGKx84F/ox0awvNKQMXsfss +ElWjdAa2GyrcnL9AFu3aE7+rxV3Jy2ZD/KUSWCJWP22cHzNV/sv46eYTDxpqSTdz +G7kj4QhEB5XuDbt7S+CZm9PTBxeUylZX8442rWEwjJsA+gCJw5gD1Y6brrWBb/op +NUWU14usY3OuTXCmtUUYt5n34YpSo9i7No1EPAxwdZWS7CwO/d8qI4/ieK2dazl2 +CftrO5U/13iZEdflH/Q/VUQ8xIR9fCZ2igUT3o1hSLCZWTPS8N+cHxhM81Nb0q5c +e80zUTJDGT7YSNJEmixZ2lWMFAWYpEgOp6qWRKCaYY0j71DlXzQcJuqbBoroswh8 +GJZFusIfQYVeaxK2blCrlurYh0lvCSjc2zls9CMM/6aCo4NU6Tao5sBSsbiE+OHj +QJH+J6dnup9gmQKjCflhAoIBAQDq0NEEiyG4+GmOmt8J2kDeA6fl0fvoJNkZQJ+q +wGMCAQZvRVe8+mSS5oRsp5U9E2ZnafowRdhzk8ODYmBSDZ2Nv2ZbU3lbaBz1PzSs +L0iLQq5fs88ygVVCQguZ69snsv1/Tf3cG6FXuhkIhsPHL666QdePqukcLTcVk814 +d1FUnhf3CKCQ7F2HycSfcYu4ombBc5hQ3zzXlS9HtcJri7mmlw0s70USEuR9N7yc +m2y6AN8VQcRptg21OBiCWvu8oqIn8YG2myjYxpNjZ3aqDfGDSnlq/Ik9Uq/f2JvF +DU1B/D9nXWB2fyDDdsKBIMy4+0uDHyFDp7EmCqIYAzigGK8hAoIBAQDChyamrg84 +58g+6e+Ni5fvrMyYfySA9AliUaBw+Oo18j6wU21EGUIVZNKTxeInluddl9o+73GM +77Htd6nI3l8tOFCExJDG10hRKzcgqagDUPyYZS8To5qUnQifQdvg0DVyEYyu+jrj +FSyjpP2IxTfqBD7I5xHUlsdOcZvKnuJaFix/SIRlQGZNkUuIRH8GazU3l5cJjkYQ +qckK5sKDeqtC4MdEbf1DnwLTQafZrNaPMlrEFIAJe53qRuJa7PGx3hvaJIqJHuct +4ju2Soq0Fz+2zYoOs0O2Qpy9An6tkGc9/xHCRz1mrk5T+F/ga+Z2DdkkJQE3iN9j +gkrw1yjL+1ptAoIBAQC+0wH5qkO2eRH3VP6KmDZ89gWc69/GkSNotS7MadpMB58+ +D+E0b1wKUZEuZ6YNY1WmFua+EhTMIDoT7H+QTwZJ6lB5SUXnNZ3K5BmfEDHpEkB4 +/7wTNC2gUeHxrU2FXp1JtozmMgIVM+QiHLq/hY1+SgGu/FrCjjAktd+V1YlftbaO +CBHMlHmR3zONy42bd0cAUTtoBXMBU3h/00LzeTJfIoQPj0bXYEkVRZVew6RBKHIi +aTcAHXXYXoT0cpH/gz86LLaYOlGgkQe4EZ3KptgtNPmlKyMwlaDdzb8RDTVKuX6h +Nq4svjVXA40fuRMGBRohrcuvmniJDL0bvIpo+IZhAoIBAQCY/Bs8mMUl9rs4J1ib +U/5QovBguhUmSUYcCaAJWOkxNetxVpsnJEohcyJczxJ2GiqpI6SjPEJsGZIv9J0V +eTUW5iQE1mYZyvN3ymnXiTW2LfoJjAIDCvamC/3c6bmXy4dMx1qBvg+TyXJK3JX7 ++0ZnB6Gs9HTEYTQrkBN6vYu8V5X1ID3nN0d9l1f0uhHAJY47wz8oZ7jYn/6ZUTQG +nPGVbhuoyGuWw7ZAGHF+MnynL23MqWasjoh51/dqlM/cF5aF75j4D9K19icJzQPa +cDJOfMUnnHoTG74Ss6SWsWtQiYoY5Vf3qfu19C7K23DqxSdRUrzrRPySUMTJNh1C +ltHdAoIBACLYtKTz+39eWJspcui51HkyjnRjK0yAB46vZG38vJESa/Ljm61uhRBB +DJNpw37OUWD8QUmPzAW5WbiX/XnC1JCdgOcLDuIQHQ9NZy/Js2vcodT5GUuiCI5o +74LzV0uUfGHS/cef73Om+dXFud+Yed3ekx4gTkqIWvQqSwFJ9FY8nHblsjYnJCPV +3MuRXQUhus9HRlYKhFBNpAp+N/eniqR/NKFY5rEKgX0ixZXLO//5SLoMtbs3g/F+ +VUWPvocU6H6Gdta6Ro5rAXKIspFwGvWDLFAjHEbPbTYC2rZoRCa90UyJWLkhhitZ +Plr6wPq89gaTcWQaNVjwDVAuPmCSHv4= +-----END PRIVATE KEY----- diff --git a/certs/root-safe_CA.pem b/certs/root-safe_CA.pem new file mode 100644 index 0000000..3d0f12d --- /dev/null +++ b/certs/root-safe_CA.pem @@ -0,0 +1,89 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 02:d3:24:58:50:9a:63:62:01:9c:77:99:26:1d:07:d4:9a:6f:b8:31 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=CA, L=Montreal, ST=Quebec, O=SAFE Inc., OU=Digital Certificate Signing, CN=SAFE Root CA 1 + Validity + Not Before: Apr 25 13:26:55 2021 GMT + Not After : Apr 25 13:26:55 2041 GMT + Subject: C=CA, L=Montreal, ST=Quebec, O=SAFE Inc., OU=Digital Certificate Signing, CN=SAFE Root CA 1 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:2b:ba:82:6e:03:14:e8:ee:9b:1d:0b:e3:80:e8: + ef:1f:68:fd:b5:4d:24:50:9d:7a:04:07:b9:d1:c3: + 70:db:aa:c9:10:c3:3d:7f:26:a0:88:22:21:51:39: + fd:51:10:8e:67:31:9e:5c:b2:be:60:94:01:75:7e: + c3:ef:b3:ac:6c + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 87:DD:FB:32:49:26:5E:13:F8:B7:F2:DF:EF:9C:F6:85:34:37:7A:D9 + X509v3 Authority Key Identifier: + 87:DD:FB:32:49:26:5E:13:F8:B7:F2:DF:EF:9C:F6:85:34:37:7A:D9 + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.7438.1.1 + CPS: http://certificates.safe.ca/repository/ + Policy: 2.23.140.1.2.1 + Signature Algorithm: ecdsa-with-SHA384 + Signature Value: + 30:45:02:20:50:43:0d:35:ec:ec:53:6e:3c:74:4e:7b:53:3f: + df:2d:d4:5d:8a:2a:0b:7a:21:c4:6e:93:04:70:b5:b5:74:2a: + 02:21:00:a6:6e:95:77:72:9d:0e:bc:f0:15:5f:b7:02:cc:e1: + ac:b1:3d:f5:a6:99:01:23:30:3a:76:03:6b:ee:ac:92:fa +-----BEGIN CERTIFICATE----- +MIICyjCCAnCgAwIBAgIUAtMkWFCaY2IBnHeZJh0H1JpvuDEwCgYIKoZIzj0EAwMw +gYQxCzAJBgNVBAYTAkNBMREwDwYDVQQHDAhNb250cmVhbDEPMA0GA1UECAwGUXVl +YmVjMRIwEAYDVQQKDAlTQUZFIEluYy4xJDAiBgNVBAsMG0RpZ2l0YWwgQ2VydGlm +aWNhdGUgU2lnbmluZzEXMBUGA1UEAwwOU0FGRSBSb290IENBIDEwHhcNMjEwNDI1 +MTMyNjU1WhcNNDEwNDI1MTMyNjU1WjCBhDELMAkGA1UEBhMCQ0ExETAPBgNVBAcM +CE1vbnRyZWFsMQ8wDQYDVQQIDAZRdWViZWMxEjAQBgNVBAoMCVNBRkUgSW5jLjEk +MCIGA1UECwwbRGlnaXRhbCBDZXJ0aWZpY2F0ZSBTaWduaW5nMRcwFQYDVQQDDA5T +QUZFIFJvb3QgQ0EgMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCu6gm4DFOju +mx0L44Do7x9o/bVNJFCdegQHudHDcNuqyRDDPX8moIgiIVE5/VEQjmcxnlyyvmCU +AXV+w++zrGyjgb0wgbowDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +HQYDVR0OBBYEFIfd+zJJJl4T+Lfy3++c9oU0N3rZMB8GA1UdIwQYMBaAFIfd+zJJ +Jl4T+Lfy3++c9oU0N3rZMFcGA1UdIARQME4wQgYJKwYBBAG6DgEBMDUwMwYIKwYB +BQUHAgEWJ2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuc2FmZS5jYS9yZXBvc2l0b3J5LzAI +BgZngQwBAgEwCgYIKoZIzj0EAwMDSAAwRQIgUEMNNezsU248dE57Uz/fLdRdiioL +eiHEbpMEcLW1dCoCIQCmbpV3cp0OvPAVX7cCzOGssT31ppkBIzA6dgNr7qyS+g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- diff --git a/certs/safeMDL.pem b/certs/safeMDL.pem new file mode 100644 index 0000000..331cd2c --- /dev/null +++ b/certs/safeMDL.pem @@ -0,0 +1,110 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2a:01:e0:a5:fb:80:10:00:00:00:02 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=CA, L=Montreal, ST=Quebec, O=SAFE Inc., OU=Digital Certificate Signing, CN=SAFE Root CA 1 + Validity + Not Before: Jan 20 17:19:55 2024 GMT + Not After : Jun 7 17:19:55 2051 GMT + Subject: C=CA, O=SAFE Inc., OU=Digital Certificate Signing, CN=SAFE Midle Ground CA (2024) - SHA384 - 3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d1:52:9b:dc:10:57:6d:9a:0e:09:5b:1b:aa:fb: + 76:8c:65:b3:f2:ca:75:36:8f:c0:cb:82:d8:2f:5b: + 0e:25:0c:5f:fc:18:94:41:87:5d:75:eb:92:ec:2a: + 87:14:ec:5f:cc:f6:8f:bf:db:4e:a3:07:aa:ec:90: + 3a:48:43:b9:01:84:42:fb:34:0b:06:5f:d8:e4:6d: + e7:55:8f:f6:ad:98:c4:7d:6f:a8:39:de:f8:70:94: + 71:f3:2f:24:1b:3b:ab:42:70:d8:6c:06:ef:81:af: + fa:f7:68:77:66:0e:60:12:df:80:bb:b4:92:4a:1f: + 3e:52:2d:f5:9a:e3:ba:26:d3:88:68:aa:11:88:0f: + b8:be:7e:e3:d7:88:ce:86:09:1a:a3:2c:ce:74:c1: + d7:d6:7a:c4:b5:04:1e:25:ef:b7:15:6a:16:27:4d: + 0f:ed:af:46:fc:a0:57:a2:6d:fe:91:c3:c7:1f:87: + 06:fe:5a:e2:a8:de:33:67:ae:6d:06:84:f2:15:1d: + 9d:ff:11:cf:be:6f:a9:a5:13:13:0b:ef:67:19:1f: + ea:a8:ed:f0:db:f2:1f:ba:8c:a5:1e:b3:54:b7:68: + c3:37:85:db:01:2e:83:4d:e0:06:be:93:54:b0:dc: + 31:23:98:15:b7:ec:b5:82:57:7a:7c:34:6c:3b:2b: + 3b:fa:b3:12:9a:63:63:d9:54:fd:bf:a1:ee:3c:a4: + 47:83:04:60:b9:9b:74:8f:f7:92:93:1d:f5:ea:98: + 87:c4:c9:de:d6:b8:5f:bf:fc:2e:41:e0:55:38:65: + 80:54:02:c6:d9:bd:7d:51:96:ba:55:ad:bf:01:ce: + 31:21:54:1e:56:16:79:7b:97:1a:53:92:86:80:54: + ef:e9:75:ad:21:45:37:82:54:52:ed:c3:37:8c:11: + ab:63:dd:64:ae:15:b4:f5:cc:02:2f:61:ab:42:d6: + c5:a1:c0:dd:19:ef:70:f1:7f:6d:31:af:4e:60:bb: + 83:a1:f7:49:a5:de:94:dd:31:c1:74:4b:11:73:da: + 4d:f4:4e:90:9e:ae:dd:c0:61:d6:6b:54:3f:3a:78: + c3:8b:e4:0e:ba:c6:9c:f3:3f:fb:6c:34:7c:ff:3d: + 65:d7:0b:ec:4c:19:37:51:37:c5:3b:34:7e:55:85: + 10:82:33:30:7f:ff:95:63:5b:45:3c:45:90:34:fb: + 1c:5e:ef:64:a3:a7:a8:58:0f:d0:97:6a:de:5a:8f: + 29:51:6b:14:01:b1:ec:59:74:47:0e:d9:d0:1a:78: + df:16:e5:fe:5b:8b:95:48:0f:26:20:58:ef:14:6a: + 97:ca:c0:b3:7d:ac:7f:8a:6c:59:be:1b:fc:a0:47: + e7:57:b1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + CA Issuers - URI:http://certificates.safe.ca/cacert/safeMDL.pem + OCSP - URI:http://certificates/safe.ca/chkcertstats + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.7438.1.1 + CPS: http://certificates.safe.ca/repository/ + Policy: 2.23.140.1.2.1 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + Full Name: + URI:http://certificates.safe.ca/repository/revoklist.pem + X509v3 Subject Alternative Name: + DNS:certificates.safe.ca, IP Address:192.219.254.53 + X509v3 Authority Key Identifier: + 87:DD:FB:32:49:26:5E:13:F8:B7:F2:DF:EF:9C:F6:85:34:37:7A:D9 + X509v3 Subject Key Identifier: + 9C:BE:0B:C0:22:76:F5:CF:BC:FD:78:9A:92:77:20:FE:BF:96:1E:D8 + Signature Algorithm: ecdsa-with-SHA384 + Signature Value: + 30:46:02:21:00:ff:21:78:ff:d7:43:e7:9d:7d:dd:e6:f1:89: + f9:39:8a:14:e0:46:ca:b2:f2:59:a1:09:70:a0:2d:8b:66:a1: + 65:02:21:00:d6:cf:8e:54:06:f0:d3:4c:23:f6:9d:a7:d5:b7: + 23:6d:b9:c8:18:15:63:a3:92:98:3c:dc:25:18:71:1c:74:68 +-----BEGIN CERTIFICATE----- +MIIFejCCBR+gAwIBAgILKgHgpfuAEAAAAAIwCgYIKoZIzj0EAwMwgYQxCzAJBgNV +BAYTAkNBMREwDwYDVQQHDAhNb250cmVhbDEPMA0GA1UECAwGUXVlYmVjMRIwEAYD +VQQKDAlTQUZFIEluYy4xJDAiBgNVBAsMG0RpZ2l0YWwgQ2VydGlmaWNhdGUgU2ln +bmluZzEXMBUGA1UEAwwOU0FGRSBSb290IENBIDEwIBcNMjQwMTIwMTcxOTU1WhgP +MjA1MTA2MDcxNzE5NTVaMHoxCzAJBgNVBAYTAkNBMRIwEAYDVQQKDAlTQUZFIElu +Yy4xJDAiBgNVBAsMG0RpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzExMC8GA1UE +AwwoU0FGRSBNaWRsZSBHcm91bmQgQ0EgKDIwMjQpIC0gU0hBMzg0IC0gMzCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANFSm9wQV22aDglbG6r7doxls/LK +dTaPwMuC2C9bDiUMX/wYlEGHXXXrkuwqhxTsX8z2j7/bTqMHquyQOkhDuQGEQvs0 +CwZf2ORt51WP9q2YxH1vqDne+HCUcfMvJBs7q0Jw2GwG74Gv+vdod2YOYBLfgLu0 +kkofPlIt9ZrjuibTiGiqEYgPuL5+49eIzoYJGqMsznTB19Z6xLUEHiXvtxVqFidN +D+2vRvygV6Jt/pHDxx+HBv5a4qjeM2eubQaE8hUdnf8Rz75vqaUTEwvvZxkf6qjt +8NvyH7qMpR6zVLdowzeF2wEug03gBr6TVLDcMSOYFbfstYJXenw0bDsrO/qzEppj +Y9lU/b+h7jykR4MEYLmbdI/3kpMd9eqYh8TJ3ta4X7/8LkHgVThlgFQCxtm9fVGW +ulWtvwHOMSFUHlYWeXuXGlOShoBU7+l1rSFFN4JUUu3DN4wRq2PdZK4VtPXMAi9h +q0LWxaHA3RnvcPF/bTGvTmC7g6H3SaXelN0xwXRLEXPaTfROkJ6u3cBh1mtUPzp4 +w4vkDrrGnPM/+2w0fP89ZdcL7EwZN1E3xTs0flWFEIIzMH//lWNbRTxFkDT7HF7v +ZKOnqFgP0Jdq3lqPKVFrFAGx7Fl0Rw7Z0Bp43xbl/luLlUgPJiBY7xRql8rAs32s +f4psWb4b/KBH51exAgMBAAGjggGyMIIBrjAOBgNVHQ8BAf8EBAMCAQYwgYAGCCsG +AQUFBwEBBHQwcjA6BggrBgEFBQcwAoYuaHR0cDovL2NlcnRpZmljYXRlcy5zYWZl +LmNhL2NhY2VydC9zYWZlTURMLnBlbTA0BggrBgEFBQcwAYYoaHR0cDovL2NlcnRp +ZmljYXRlcy9zYWZlLmNhL2Noa2NlcnRzdGF0czBXBgNVHSAEUDBOMEIGCSsGAQQB +ug4BATA1MDMGCCsGAQUFBwIBFidodHRwOi8vY2VydGlmaWNhdGVzLnNhZmUuY2Ev +cmVwb3NpdG9yeS8wCAYGZ4EMAQIBMBIGA1UdEwEB/wQIMAYBAf8CAQAwRQYDVR0f +BD4wPDA6oDigNoY0aHR0cDovL2NlcnRpZmljYXRlcy5zYWZlLmNhL3JlcG9zaXRv +cnkvcmV2b2tsaXN0LnBlbTAlBgNVHREEHjAcghRjZXJ0aWZpY2F0ZXMuc2FmZS5j +YYcEwNv+NTAfBgNVHSMEGDAWgBSH3fsySSZeE/i38t/vnPaFNDd62TAdBgNVHQ4E +FgQUnL4LwCJ29c+8/Xiakncg/r+WHtgwCgYIKoZIzj0EAwMDSQAwRgIhAP8heP/X +Q+edfd3m8Yn5OYoU4EbKsvJZoQlwoC2LZqFlAiEA1s+OVAbw00wj9p2n1bcjbbnI +GBVjo5KYPNwlGHEcdGg= +-----END CERTIFICATE----- diff --git a/conf/.mailleur.conf.swp b/conf/.mailleur.conf.swp new file mode 100644 index 0000000..b1399f6 Binary files /dev/null and b/conf/.mailleur.conf.swp differ diff --git a/conf/blacklister.conf b/conf/blacklister.conf new file mode 100644 index 0000000..ff146c4 --- /dev/null +++ b/conf/blacklister.conf @@ -0,0 +1,26 @@ +#dnsbl.sorbs.net +#t1.dnsbl.net.au +#checked 2025-07-12 by preference order +#The SpamCop Blocking List (SCBL) lists IP addresses which +#have transmitted reported email to SpamCop users. SpamCop +-1 bl.spamcop.net 127.0.0.2 +#Spamhaus Block List (SBL) is a realtime database of IP addresses +#of spam sources, including known spammers, spam gangs, +#spam operations and spam support services. +-1 sbl.spamhaus.org 127.0.0.2,127.0.0.3,127.0.0.9 +#b.barracudacentral.org will return the standard +#127.0.0.2 IP address when queried if the SMTP server is listed. +-6 b.barracudacentral.org 127.0.0.2 +#www.blocklist.de is a free and voluntary service provided +#by a Fraud/Abuse-specialist, +-1 bl.blocklist.de 127.0.0.9,127.0.0.13 +# ips.backscatterer.org for scoring or rejecting misdirected +#bounces and misdirected autoresponders +-1 ips.backscatterer.org 127.0.0.2 +#DroneBL is a realtime monitor of abusable IPs +#-1 dnsbl.dronebl.org +#The s5h blacklist is a real-time IP-based blacklist that is +#maintained by the System 5 Hosting (S5H) organization. +#-1 all.s5h.net 127.0.0.2 +#Junk Email Filter is a front end email spam filtering +-1 hostkarma.junkemailfilter.co 127.0.0.2 diff --git a/conf/mailleur.conf b/conf/mailleur.conf new file mode 100644 index 0000000..3fb243b --- /dev/null +++ b/conf/mailleur.conf @@ -0,0 +1,80 @@ +#file used to set environment configuration +#------------------------------------------------ +#Defining application name +APPNAME=mailleur +#root working directoy definition for the whole application +ROOTBASE="/" +#defining local default domain +DFLTDOMAIN="localdomain" +#defining the local REALM +#Caution! the realm is hardcoded within data-base +#and USED too to hash the user passwd +#Changing this value coule be a trouble make +#(entering again ALL user password) +REALM="mailleur-email" +#------------------------------------------------ +#list of listening port to do SMTP protocole +#format +#protocol|ipnum|port|iteration[,protocol|ipnum|port|iteration]++ +#example +#stmtps|ipnum|465|5 -> protocol smtps|IP number|port 465|5 iterations +#|ipnum||| -> smtp|ipnum|25|2 +#||,smtps||465|2 -> smtp|0.0.0.0|25|2 + smtps||465|2 +#|| -> smtp|0.0.0.0|25|2 +#Examples for test purpose +#SMTPPORTS="|127.127.10.25|1025|,smtps|127.127.10.25|1465|1" +#SMTPPORTS="|127.127.10.25|1025|" +#SMTPPORTS="smtps|127.127.10.25|1465|1" +#Defaults (production) +SMTPPORTS="|||5,smtps||465|3,smtp||587|2" +#------------------------------------------------ +#SSL Security level default value +#CIPHER_LIST="DEFAULT" +#SSL_SECURITY=2 +#------------------------------------------------ +#Defining SERVER mode Certificate data +CA_ROOT_SRV="/etc/pki/tls/make-ca/ca-bundle.crt" +CA_VERIFY_SRV=0 #to check PEER/client remote certificate +#If certificate set via do_dns_tlsa.sh (letsencrypt) +#CA_CERT_SRV="/etc/certbot/mailleur/mailleur-fullchain.pem" +#CA_KEY_SRV="/etc/certbot/mailleur/mailleur-key.pem" +#If certificate are self signed (default installation) +#CA_CERT_SRV="/etc/pki/mailleur/mailleur-cert.pem" +#CA_KEY_SRV="/etc/pki/mailleur/mailleur-key.pem" +#Symbolic link set at installation +CA_CERT_SRV="/etc/pki/mailleur/mailleur-cert.pem" +CA_KEY_SRV="/etc/pki/mailleur/mailleur-key.pem" +#------------------------------------------------ +#Defining CLIENT mode Certificate data +CA_ROOT_CLT="/etc/pki/tls/make-ca/ca-bundle.crt" +CA_VERIFY_CLT=0 #to check PEER/server remote certificate +#If certificate set via do_dns_tlsa.sh (letsencrypt) +#CA_CERT_CLT="/etc/certbot/mailleur/mailleur-fullchain.pem" +#CA_KEY_CLT="/etc/certbot/mailleur/mailleur-key.pem" +#If certificate are self signed (default installation) +#CA_CERT_CLT="/etc/pki/mailleur/mailleur-cert.pem" +#CA_KEY_CLT="/etc/pki/mailleur/mailleur-key.pem" +#Symbolic link set at installation +CA_CERT_CLT="/etc/mailleur/pki/mailleur-cert.pem" +CA_KEY_CLT="/etc/mailleur/pki/mailleur-key.pem" +#------------------------------------------------ +#Configured for Postgresql database +#DB_TYPE can be either POSTGRESQL,MYSQL, default POSTGRESQL +DB_TYPE=TO_BE_DEFINED +DB_NAME=mailleur +DB_HOST=localhost +DB_PORT=TO_BE_DEFINED +DB_LANG="UTF-8" +#------------------------------------------------ +#Dovecot storage directory +DOV_MAILDIR="/var/spool/mailleur/mails" +#------------------------------------------------ +#The list of public blacklist serveur +BLACKLISTER=/etc/mailleur/blacklister.conf +#the list of IP from which we accept to relay email +RELAYABLE=/etc/mailleur/relayed.conf +#------------------------------------------------ +#Minimal credit level to which remote is rejected at once +#if credit is equal or below that level +RJCTCRED=-50 +#------------------------------------------------ diff --git a/conf/mailleur.conf.dvl b/conf/mailleur.conf.dvl new file mode 100644 index 0000000..0389242 --- /dev/null +++ b/conf/mailleur.conf.dvl @@ -0,0 +1,66 @@ +#file used to set environment configuration +#Used for developpement purpose ONLY +#------------------------------------------------ +#Defining application name +APPNAME=mailleur +#root working directoy definition for the whole application +ROOTBASE="/home/jmp/safe-mailleur/mailleur/test_area/" +#defining local default domain +DFLTDOMAIN="example.com" +#defining the local REALM +#Caution! the realm is hardcoded within data-base +#and USED too to hash the user passwd +#Changing this value coule be a trouble make +#(entering again ALL user password) +REALM="mailleur-email" +#------------------------------------------------ +#list of listening port to do SMTP protocole +#format +#protocol|ipnum|port|iteration[,protocol|ipnum|port|iteration]++ +#example +#stmtps|ipnum|465|5 -> protocol smtps|IP number|port 465|5 iterations +#|ipnum||| -> smtp|ipnum|25|2 +#||,smtps||465|2 -> smtp|0.0.0.0|25|2 + smtps||465|2 +#|| -> smtp|0.0.0.0|25|2 +#SMTPPORTS="||1025" +#SMTPPORTS="|127.127.10.25|1025|,smtps|127.127.10.25|1026|1" +#SMTPPORTS="|127.127.10.25|1025|" +#SMTPPORTS="smtps|127.127.10.25|1065|1" +#------------------------------------------------ +#SSL Security level +#CIPHER_LIST="ECDHE-ECDSA-AES256-GCM-SHA384" +#SSL_SECURITY=3 +#------------------------------------------------ +#Defining SERVER mode Certificate data +CA_ROOT_SRV="/etc/pki/tls/make-ca/ca-bundle.crt" +CA_CERT_SRV="./certs/mailleur_server-chain-cert_x509.pem" +CA_KEY_SRV="./certs/mailleur_server-key.pem" +CA_VERIFY_SRV=0 #to check PEER/client remote certificate +#------------------------------------------------ +#Defining CLIENT mode Certificate data +CA_ROOT_CLT="/etc/pki/tls/make-ca/ca-bundle.crt" +CA_CERT_CLT="./certs/localhost-chain-cert.pem" +CA_KEY_CLT="./certs/localhost-key.pem" +CA_VERIFY_CLT=0 #to check PEER/server remote certificate +#------------------------------------------------ +#Configured for Postgresql database +#DB_TYPE can be either POSTGRESQL,MYSQL, default POSTGRESQL +#DB_NAME=mailleur +#DB_HOST=localhost +#DB_LANG="UTF-8" +#DB_TYPE=POSTGRESQL +#DB_PORT=5432 +#DB_TYPE=MYSQL +#DB_PORT=3306 + +#------------------------------------------------ +#Dovecot storage directory +DOV_MAILDIR="/var/spool/mailleur/mails" +#------------------------------------------------ +SMTPPORTS="|127.127.10.25|1025|5,smtps|127.127.10.26|1465|3,smtp|127.127.10.26|1587|2" +#------------------------------------------------ +#The list of public blacklist serveur +BLACKLISTER=/etc/mailleur/blacklister.conf +#the list of IP from which we accept to relay email +RELAYABLE=/etc/mailleur/relayed.conf.dvl +#------------------------------------------------ diff --git a/conf/relayed.conf b/conf/relayed.conf new file mode 100644 index 0000000..114af58 --- /dev/null +++ b/conf/relayed.conf @@ -0,0 +1,5 @@ +#-------------------------------------------------------- +##Private address block which email can be relayed from +127.0.0.0/8 #local loop number +#-------------------------------------------------------- +#Setup you own list diff --git a/conf/relayed.conf.dvl b/conf/relayed.conf.dvl new file mode 100644 index 0000000..5c217dc --- /dev/null +++ b/conf/relayed.conf.dvl @@ -0,0 +1,6 @@ +#-------------------------------------------------------- +##Private address block which email can be relayed from +127.0.0.0/8 #local loop number +192.168.254.0/24 #local network +#-------------------------------------------------------- +#Setup you own list diff --git a/cron/mailleur.cron b/cron/mailleur.cron new file mode 100644 index 0000000..bb01438 --- /dev/null +++ b/cron/mailleur.cron @@ -0,0 +1,6 @@ +#--------------------------------------------------- +#shell script to manage rpplication ecurring homeworking task +#--------------------------------------------------- +#to update lets encrypt certificate +#1 1 1 * * root PATH=/usr/sbin:$PATH /usr/lib/mailleur/support/do_dns_tlsa.sh + diff --git a/data-feed/dbgfeed.tst b/data-feed/dbgfeed.tst new file mode 100644 index 0000000..efe12e1 --- /dev/null +++ b/data-feed/dbgfeed.tst @@ -0,0 +1,17 @@ +#==================================================== +#starting test +T:debug test function +R:220 mailleur.example.com ESMTP (cleartext) ... +S:HELO example.com +R:250 mailleur.example.com link (cleartext) ready... +C:GOTLS +R:250 Link now encryp... +S:EHLO example.com +R:250-mailleur.example.com link (crypted) ready, your IP/FQDN... +R:250-SIZE 52428800 +R:250-8BITMIME +R:250-ENHANCEDSTATUSCODES +R:250-AUTH PLAIN LOGIN +R:250 HELP +S:QUIT +R:221 2.0.0 Bye, closing connection... diff --git a/data-feed/extfeed00.tst b/data-feed/extfeed00.tst new file mode 100644 index 0000000..fbe3a87 --- /dev/null +++ b/data-feed/extfeed00.tst @@ -0,0 +1,18 @@ +#to test feeder againt an production email serveur +T:external email serveur +R:220 safemail3.safe.ca ESMTP... +S:EHLO example.com +#R:250-safemail3.safe.ca Hum! devel5.safe.ca [192.168.254.70], No MX on your hello +R:250-safemail3.safe.ca Hum!... +R:250-ENHANCEDSTATUSCODES +R:250-8BITMIME +R:250-SIZE +R:250-AUTH PLAIN LOGIN +R:250-STARTTLS +R:250 HELP +#send a empty ehlo +S:EHLO +R:501 syntax error in parameters or arguments (domain part missing), disconnecting +R:Disconnected +#S:QUIT +#R:221 2.0.0 Bye, closing connection... diff --git a/data-feed/feed000.tst b/data-feed/feed000.tst new file mode 100644 index 0000000..5e1bf21 --- /dev/null +++ b/data-feed/feed000.tst @@ -0,0 +1,66 @@ +#==================================================== +# WAIT X - Stop for X seconds +# RESTART - Restart connection with remote +# COMMENT START - START commenting mode +# COMMENT STOP - STOP commenting mode +# R: incoming data +# S: outgoing data +# T: Test titre or Info +C:COMMENT START +#==================================================== +#Please update /etc/hosts with with following +#start of /etc/host addon +#---------------------------------------------------- +#Definition to validate mailleur daemon (mailleur) server +#The test serveur itself +127.127.10.25 mailleur.example.com mailleur +#The example.com email feeder +127.127.0.1 feed1.example.com feed1 +127.127.0.2 feed2.example.com feed2 +#remote access +#127.168.0.1 no reverss address detection +127.168.10.1 foreign1.badserver.tld foreign1 +#---------------------------------------------------- +#end of /etc/host addon +#==================================================== +C:COMMENT STOP +T:(feed000) Sending a very Simple Email with ONE local delivery +C:CONNECT +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#==================================================== +S:HELO example.com +#R:250-mailleur.example.com, link (cleartext) ready, your IP/FQDN=[127.127.0.2/feed2.example.com] +R:250 mailleur.example.com, link (cleartext) ready,... +S:MAIL FROM: +R:250 2.1.3 postmaster@example.com sender ok +S:RCPT TO: +R:250 5.6.7 Address will be processed +S:RCPT TO: +R:250 5.6.7 Address will be processed +#------------------------------------------------------------------------- +#-sending data +C:DATA 354 3.5.0 End data with . +D:Subject: (feed000) Very Simple email contents +C:T +D:From: Maitre Post +D:To: Maitre WEB +D: +D:this email is for local test purpose only +D:with 2 known recipients beeing as: +D:postmaster and webmaster. +D: +D:Checking line with one '.' transmissioon +D:. +D:Previous line is one single dot +D: +D:you should have character '|' as last characeter +D:of this email (after End Of Text). +D:End Of Text| +C:. +#------------------------------------------------------------------------- +R:250-3.5.3 Session ID=<... +R:250-3.5.3 data stream received:... +R:250 3.5.3 Message accepted for delivery +S:QUIT +R:221 2.0.0 Bye, closing connection... +#------------------------------------------------------------------------- diff --git a/data-feed/feed001.tst b/data-feed/feed001.tst new file mode 100644 index 0000000..50655e7 --- /dev/null +++ b/data-feed/feed001.tst @@ -0,0 +1,52 @@ +#==================================================== +T:(feed001) Sending a a simple mail to remote server +C:CONNECT +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#==================================================== +S:EHLO example.com +#R:250-mailleur.example.com, link (cleartext) ready, your IP/FQDN=[127.127.0.2/feed2.example.com] +R:250-mailleur.example.com, link (cleartext) ready,... +R:250-STARTTLS +R:250-AUTH DIGEST-MD5 +R:250-SIZE 52428800 +R:250-8BITMIME +R:250 ENHANCEDSTATUSCODES +C:GOTLS +S:EHLO example.com +R:250-mailleur.example.com, link (crypted) ready,... +R:250-AUTH PLAIN LOGIN DIGEST-MD5 +R:250-SIZE 52428800 +R:250-8BITMIME +R:250 ENHANCEDSTATUSCODES +S:MAIL FROM: SIZE=1024 +R:250 2.1.3 postmaster@example.com sender ok +S:RCPT TO: +R:250 5.6.7 Address will be processed +S:RCPT TO: +R:250 5.6.7 Address will be processed +#------------------------------------------------------------------------- +#-sending data +C:DATA 354 3.5.0 End data with . +D:Subject: (feed001) Very Simple email contents +D:From: Maitre Post +D:To: Remote person +D:CC: Other person +C:T +D: +D:FIRST Line +D:SECOND Line +D:LAST Line +D:. +D:this is a line with a dot +D: +D:. +D:.single dot +D:end +D:ligne court| +C:. +#------------------------------------------------------------------------- +R:250-3.5.3 Session ID=<... +R:250-3.5.3 data stream received:... +R:250 3.5.3 Message accepted for delivery +S:QUIT +R:221 2.0.0 Bye, closing connection... diff --git a/data-feed/feed002.tst b/data-feed/feed002.tst new file mode 100644 index 0000000..361f350 --- /dev/null +++ b/data-feed/feed002.tst @@ -0,0 +1,34 @@ +T:(feed002) Sending a very Simple Email to 2 domains +C:CONNECT +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#==================================================== +S:HELO example.com +R:250 mailleur.example.com, link (cleartext) ready,... +S:MAIL FROM: +R:250 2.1.3 trouble@mailref1.example.com sender ok +S:RCPT TO: +R:250 5.6.7 Address will be processed +S:RCPT TO: +R:250 5.6.7 Address will be processed +S:RCPT TO: +R:250 5.6.7 Address will be processed +S:RCPT TO: +R:250 5.6.7 Address will be processed +#------------------------------------------------------------------------- +#-sending data +C:DATA 354 3.5.0 End data with . +D:Subject: (feed002) Very Simple email contents 2 domains +D:From: Maitre Post +D:To: Maitre WEB +D: +D:.single dot, next is an empty line starting with a '.' +D:. +D:This email is sent to 3 domain X 1 users +D: +C:. +#------------------------------------------------------------------------- +R:250-3.5.3 Session ID=<... +R:250-3.5.3 data stream received:... +R:250 3.5.3 Message accepted for delivery +S:QUIT +R:221 2.0.0 Bye, closing connection... diff --git a/data-feed/feed003.tst b/data-feed/feed003.tst new file mode 100644 index 0000000..a15ee68 --- /dev/null +++ b/data-feed/feed003.tst @@ -0,0 +1,59 @@ +T:(feed003) Sending two email within the same session +C:CONNECT +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#========================================================================= +S:HELO example.com +R:250 mailleur.example.com, link (cleartext) ready,... +S:MAIL FROM: +R:250 2.1.3 trouble@mailref1.example.com sender ok +S:RCPT TO: +R:250 5.6.7 Address will be processed +S:RCPT TO: +R:250 5.6.7 Address will be processed +S:RCPT TO: +R:551 5.6.0 unknown user +#------------------------------------------------------------------------- +#-sending data +C:DATA 354 3.5.0 End data with . +D:Subject: feed003 email first part +D:From: Tester +D:To: A User1 +D:Cc: A User2 +D: +D:This email was transmitted by feed003 first session +C:. +#------------------------------------------------------------------------- +R:250-3.5.3 Session ID=<... +R:250-3.5.3 data stream received:... +R:250 3.5.3 Message accepted for delivery +#========================================================================= +#Testing Reset sequence +S:RSET +R:250-2.1.0 flushed session ... +R:250 2.1.0 opening new session... +#------------------------------------------------------------------------- +S:HELO example.com +R:250 mailleur.example.com, link (cleartext) ready,... +S:MAIL FROM: +R:250 2.1.3 postmaster@mailref1.example.com sender ok +S:RCPT TO: +R:250 5.6.7 Address will be processed +S:RCPT TO: +R:250 5.6.7 Address will be processed +#------------------------------------------------------------------------- +#-sending data +C:DATA 354 3.5.0 End data with . +D:Subject: feed003 email second part +D:From: Tester +D:To: A User1 +D:Cc: A User2 +D: +D:This email was transmitted by feed003 second session +C:. +#------------------------------------------------------------------------- +R:250-3.5.3 Session ID=<... +R:250-3.5.3 data stream received:... +R:250 3.5.3 Message accepted for delivery +#========================================================================= +S:QUIT +R:221 2.0.0 Bye, closing connection... diff --git a/data-feed/feed004.tst b/data-feed/feed004.tst new file mode 100644 index 0000000..71c82e3 --- /dev/null +++ b/data-feed/feed004.tst @@ -0,0 +1,32 @@ +T:(feed004) Email using UTF-8 characters on local delivery +C:CONNECT +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#==================================================== +S:HELO example.com +R:250 mailleur.example.com, link (cleartext) ready,... +S:MAIL FROM: +R:250 2.1.3 postmaster@example.com sender ok +S:RCPT TO: +R:250 5.6.7 Address will be processed +#------------------------------------------------------------------------- +#-sending data +C:DATA 354 3.5.0 End data with . +D:Subject: (feed004) Email using UTF-8 characters +C:T +D:From: Maitre Post +D:To: Maitre WEB +D: +D:this email is for local test purpose only +D:with 2 known recipients beeing as: +D:postmaster and webmaster. +D: +D:This line include accentued latin char +D:via the reciption email address <áöüñ@example.com> +C:. +#------------------------------------------------------------------------- +R:250-3.5.3 Session ID=<... +R:250-3.5.3 data stream received:... +R:250 3.5.3 Message accepted for delivery +S:QUIT +R:221 2.0.0 Bye, closing connection... +#------------------------------------------------------------------------- diff --git a/data-feed/feed005.tst b/data-feed/feed005.tst new file mode 100644 index 0000000..4eac57e --- /dev/null +++ b/data-feed/feed005.tst @@ -0,0 +1,13 @@ +T:(feed005) Email testing remote server credential +C:CONNECT +#==================================================== +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +C:ORGN: 213.209.157.107 +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +S:helo example.com +R:250 mailleur.example.com, link (cleartext) ready, your IP/FQDN=[213.209.157.107/No.Reverse] +S:MAIL FROM: +R:556-4.5.7 Originator server IP [213.209.157.107] black listed... +R:556 5.5.4 Closing connection +R:Disconnected +#------------------------------------------------------------------------- diff --git a/data-feed/feed006.tst b/data-feed/feed006.tst new file mode 100644 index 0000000..a10ec7f --- /dev/null +++ b/data-feed/feed006.tst @@ -0,0 +1,40 @@ +T:(feed006) Email testing BAD remote server credential in case of authentication +C:CONNECT +#==================================================== +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +C:ORGN: 213.209.157.108 +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +C:GOTLS +S:EHLO example.com +R:250-mailleur.example.com, link (crypted) ready, your IP/FQDN=[213.209.157.108/No.Reverse] +R:250-AUTH PLAIN LOGIN DIGEST-MD5 +R:250-SIZE 52428800 +R:250-8BITMIME +R:250 ENHANCEDSTATUSCODES +S:AUTH LOGIN +R:334 VXNlcm5hbWU6 +S:dXRmOC3DocO2X8O8w7FAZXhhbXBsZS5jb20= +R:334 UGFzc3dvcmQ6 +S:dXRmOC3DocO2X8O8w7E= +R:235 5.7.5 authentication successful +S:MAIL FROM: +R:250 2.1.3 trouble@mailref1.example.com sender ok +S:RCPT TO: +R:250 5.6.7 Address will be processed +#-sending data +C:DATA 354 3.5.0 End data with . +D:Subject: (feed006) A email to a not existing user after authentication +D:From: Trouble maker +D:To: Not existing +C:T +D: +D:This email check relaying after authentication +D: +D: +C:. +#------------------------------------------------------------------------- +R:250-3.5.3 Session ID=<... +R:250-3.5.3 data stream received:... +R:250 3.5.3 Message accepted for delivery +S:QUIT +R:221 2.0.0 Bye, closing connection... diff --git a/data-feed/feed007.tst b/data-feed/feed007.tst new file mode 100644 index 0000000..b907720 --- /dev/null +++ b/data-feed/feed007.tst @@ -0,0 +1,35 @@ +T:(feed007) Testing if remote server is within relay list +#this email should be REJECT as relaying intended +C:CONNECT +#==================================================== +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +C:ORGN: 192.168.254.25 +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +C:GOTLS +S:EHLO example.com +R:250-mailleur.example.com, link (crypted) ready, your IP/FQDN=[192.168.254.25/No.Reverse] +R:250-AUTH PLAIN LOGIN DIGEST-MD5 +R:250-SIZE 52428800 +R:250-8BITMIME +R:250 ENHANCEDSTATUSCODES +S:MAIL FROM: +R:250 2.1.3 trouble@mailref1.example.com sender ok +S:RCPT TO: +R:250 5.6.7 Address will be processed +#-sending data +C:DATA 354 3.5.0 End data with . +D:Subject: (feed006) A email to a not existing user after authentication +D:From: Trouble maker +D:To: Not existing +C:T +D: +D:This email check relaying after authentication +D: +D: +C:. +#------------------------------------------------------------------------- +R:250-3.5.3 Session ID=<... +R:250-3.5.3 data stream received:... +R:250 3.5.3 Message accepted for delivery +S:QUIT +R:221 2.0.0 Bye, closing connection... diff --git a/data-feed/feed008.tst b/data-feed/feed008.tst new file mode 100644 index 0000000..18ea76b --- /dev/null +++ b/data-feed/feed008.tst @@ -0,0 +1,40 @@ +T:(feed008) Email testing remote server relaying +C:CONNECT +#==================================================== +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#take a "random" imp number as server remote IP +C:ORGN: 18.209.86.113 +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +S:EHLO keeper-us-east-1d.mxtoolbox.com +R:250-mailleur.example.com, link (cleartext) ready, your IP/FQDN=[18.209.86.113/keeper-us-east-1d.mxtoolbox.com] +R:250-STARTTLS +R:250-AUTH DIGEST-MD5 +R:250-SIZE 52428800 +R:250-8BITMIME +R:250 ENHANCEDSTATUSCODES +S:MAIL FROM: +R:250 2.1.3 supertool@mxtoolboxsmtpdiag.com sender ok +S:RCPT TO: +R:250 5.6.7 Address will be processed +S:RCPT TO: +R:555 2.8.0 No MX nor IP for for domain +S:RCPT TO: +R:555 2.8.0 No relay accepted for domain +#------------------------------------------------------------------------- +#-sending data +C:DATA 354 3.5.0 End data with . +D:Subject: (feed008) sending email to local only +D:From: Maitre Post +D:To: Maitre WEB +D: +D:.single dot, next is an empty line starting with a '.' +D:. +D:This email is sent to 3 domain X 1 users +D: +C:. +#------------------------------------------------------------------------- +R:250-3.5.3 Session ID=<... +R:250-3.5.3 data stream received:... +R:250 3.5.3 Message accepted for delivery +S:QUIT +R:221 2.0.0 Bye, closing connection... diff --git a/data-feed/feed009.tst b/data-feed/feed009.tst new file mode 100644 index 0000000..66b5911 --- /dev/null +++ b/data-feed/feed009.tst @@ -0,0 +1,35 @@ +T:(feed009) Making sure we accept local IP email +C:CONNECT +#==================================================== +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#take a "random" imp number as server remote IP +C:ORGN: 209.85.222.45 +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +S:EHLO keeper-us-east-1d.mxtoolbox.com +R:250-mailleur.example.com, link (cleartext) ready, your IP/FQDN=[209.85.222.45/mail-ua1-f45.google.com] +R:250-STARTTLS +R:250-AUTH DIGEST-MD5 +R:250-SIZE 52428800 +R:250-8BITMIME +R:250 ENHANCEDSTATUSCODES +S:MAIL FROM: SIZE=2958 +R:250 2.1.3 nobody@gmail.com sender ok +S:RCPT TO: +R:250 5.6.7 Address will be processed +#------------------------------------------------------------------------- +#-sending data +C:DATA 354 3.5.0 End data with . +D:Subject: (feed008) sending email to local only +D:From: A Nobody +D:To: A simple very local user +D: +D:this ia an email "from" gmail. +D:test text text +D: +C:. +#------------------------------------------------------------------------- +R:250-3.5.3 Session ID=<... +R:250-3.5.3 data stream received:... +R:250 3.5.3 Message accepted for delivery +S:QUIT +R:221 2.0.0 Bye, closing connection... diff --git a/data-feed/feed010.tst b/data-feed/feed010.tst new file mode 100644 index 0000000..8620b80 --- /dev/null +++ b/data-feed/feed010.tst @@ -0,0 +1,29 @@ +#==================================================== +T:(feed010) Testing if helo and ehlo fdqdn is OK +C:CONNECT +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +S:HELO [192.219.254.34] +R:250 mailleur.example.com, link (cleartext) ready,... +#==================================================== +S:HELO 192.219.254.35 +R:250 mailleur.example.com, link (cleartext) ready,... +#==================================================== +S:HELO domain +R:250 mailleur.example.com, link (cleartext) ready,... +#==================================================== +S:HELO 8.8.8.8 +R:250 mailleur.example.com, link (cleartext) ready,... +#==================================================== +S:EHLO .com +R:501 5.5.4 HELO argument is incorrect, closing connection. +#==================================================== +C:CONNECT +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +S:EHLO domain..com +R:501 5.5.4 HELO argument is incorrect, closing connection. +#==================================================== +C:CONNECT +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +S:EHLO [.192.219.254.1] +R:501 5.5.4 HELO argument is incorrect, closing connection. +#==================================================== diff --git a/data-feed/feed011.tst b/data-feed/feed011.tst new file mode 100644 index 0000000..d99eea4 --- /dev/null +++ b/data-feed/feed011.tst @@ -0,0 +1,8 @@ +T:(feed011) Checkin authentication mode is AUTH DISGEST-MDr5 +C:CONNECT +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +S:AUTH DIGEST-MD5 +R:334 cmVhbG09Im1ha... +S:dXNlcm5hbWU9ImRpZ2kiLHJlYWxtPSJtYWlsbGV1ci1lbWFpbCIsbm9uY2U9Ik1XdHZVSFpWYVc1d2QyUlhiRWRLU1hCRk1WUmxUR2xpY2s1aWEyMUIiLGNub25jZT0iNU1TQ2Z5YUN0WWxES2c2YkVhK0kiLG5jPTAwMDAwMDAxLHFvcD0iYXV0aCIsZGlnZXN0LXVyaT0ic210cC8xOTIuMjE5LjI1NC4xODEiLHJlc3BvbnNlPWQxYTFlOGFmMDUzZmJhNmQzY2NhMzg3NmQ2YWY1N2ExLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz +R:504 5.7.4 wrong authentication +R:Disconnected diff --git a/data-feed/feed10.tst b/data-feed/feed10.tst new file mode 100644 index 0000000..50c2f0b --- /dev/null +++ b/data-feed/feed10.tst @@ -0,0 +1,16 @@ +#very simple test to feed SMTP server +#==================================================== +T:(feed10) Testing if MX is found +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#==================================================== +S:HELO example.com +R:250 mailleur.example.com, link (cleartext) ready,... +S:MAIL FROM: +R:250 2.1.3 postmaster@example.com sender ok +S:RCPT TO: +R:563 5.6.4 No valid MX found for recipient domain name (domain=subdom0.example.com) +S:RCPT TO: +R:250 5.6.7 Address will be processed +S:QUIT +R:221 2.0.0 Bye, closing connection... +#------------------------------------------------------------------------- diff --git a/data-feed/feed11.tst b/data-feed/feed11.tst new file mode 100644 index 0000000..1f41d5a --- /dev/null +++ b/data-feed/feed11.tst @@ -0,0 +1,47 @@ +#==================================================== +T:(feed11) Sending an mail to an non exitsing user +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#==================================================== +S:EHLO example.com +#R:250-mailleur.example.com, link (cleartext) ready, your IP/FQDN=[127.127.0.2/feed2.example.com] +R:250-mailleur.example.com, link (cleartext) ready,... +R:250-SIZE 52428800 +R:250-STARTTLS +R:250-8BITMIME +R:250-ENHANCEDSTATUSCODES +R:250 AUTH PLAIN LOGIN +C:GOTLS +S:EHLO example.com +R:250-mailleur.example.com, link (crypted) ready,... +R:250-SIZE 52428800 +R:250-8BITMIME +R:250-ENHANCEDSTATUSCODES +R:250 AUTH PLAIN LOGIN +S:MAIL FROM: +R:250 2.1.3 trouble@mailref1.example.com sender ok +#--------------------------------------------- +S:RCPT TO: +R:551 5.6.5 unknown user +S:RCPT TO: +R:250 5.6.7 Address will be processed +S:RCPT TO: +R:250 5.6.7 Address will be processed +#------------------------------------------------------------------------- +#-sending data +C:DATA 354 3.5.0 End data with . +D:Subject: (feed11) A email to a not existing user +D:From: Trouble maker +D:To: Not existing +C:T +D: +D:This mail on remote MX should be sent back to the originator +D:while the other user@posdb.example.com receipient should got email +D: +D: +C:. +#------------------------------------------------------------------------- +R:250-3.5.3 Session ID=<... +R:250-3.5.3 data stream received:... +R:250 3.5.3 Message accepted for delivery +S:QUIT +R:221 2.0.0 Bye, closing connection... diff --git a/data-feed/feed12.tst b/data-feed/feed12.tst new file mode 100644 index 0000000..2e3353f --- /dev/null +++ b/data-feed/feed12.tst @@ -0,0 +1,18 @@ +#==================================================== +T:(feed12) Trying to send Email while the domain is without MX +C:CONNECT +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#==================================================== +S:HELO example.com +R:250 mailleur.example.com, link (cleartext) ready,... +S:MAIL FROM: +R:250 2.1.3 trouble@mailref1.example.com sender ok +S:RCPT TO: +R:563 5.6.4 No valid MX found for recipient domain name (domain=subdom0.example.com) +#------------------------------------------------------------------------- +#-sending data +C:DATA 503 5.5.0 RCPT first. transaction protocol command out of sequence +C:. +#------------------------------------------------------------------------- +S:QUIT +R:221 2.0.0 Bye, closing connection... diff --git a/data-feed/feed13.tst b/data-feed/feed13.tst new file mode 100644 index 0000000..2161179 --- /dev/null +++ b/data-feed/feed13.tst @@ -0,0 +1,6 @@ +#==================================================== +T:(feed13) Trying to overcome the entry buffer +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#==================================================== +S:SSH-2.0-Go +S:??^EL^S^TÌK>^\^U3^W^[õ¶T6è^RP??^A^Ycurve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1??^B[ssh-rsa-cert-v01@openssh.com,ssh-dss-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss,ssh-ed25519,ssh-rsa-cert-v01@openssh.com,ssh-dss-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss,ssh-ed25519???<9b>aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,arcfour256,arcfour128,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,arcfour256,arcfour128???<9b>aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,arcfour256,arcfour128,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@EL^S^TÌK>^\^U3"^W^[õ¶T6è^RP??^A^Ycurve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1??^B[ssh-rsa-cert-v01@openssh.com,ssh-dss-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss,ssh-ed25519,ssh-rsa-cert-v01@openssh.com,ssh-dss-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss,ssh-ed25519???<9b>aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,arcfour256,arcfour128,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,arcfour256,arcfour128???<9b>aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,arcfour256,arcfour128,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@ diff --git a/data-feed/feed20.tst b/data-feed/feed20.tst new file mode 100644 index 0000000..30e31b6 --- /dev/null +++ b/data-feed/feed20.tst @@ -0,0 +1,13 @@ +#very simple test to feed SMTP server +#==================================================== +T:(feed20) Testing double connectopm +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#==================================================== +S:HELO example.com +R:250 mailleur.example.com, link (cleartext) ready,... +C:ORGN: 185.242.226.23 +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +C:WAIT 120 $wait "forever" +S:QUIT +R:221 2.0.0 Bye, closing connection... +#------------------------------------------------------------------------- diff --git a/data-feed/feed21.tst b/data-feed/feed21.tst new file mode 100644 index 0000000..05d2ab1 --- /dev/null +++ b/data-feed/feed21.tst @@ -0,0 +1,6 @@ +#very simple test to feed SMTP server +#==================================================== +T:(feed20) Testing double connectopm +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#==================================================== +#------------------------------------------------------------------------- diff --git a/data-feed/feed30.tst b/data-feed/feed30.tst new file mode 100644 index 0000000..f3e8d32 --- /dev/null +++ b/data-feed/feed30.tst @@ -0,0 +1,34 @@ +#very simple test to feed SMTP server +#==================================================== +T:(feed30) Testing a simple email +C:CONNECT +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#==================================================== +S:HELO example.com +R:250 mailleur.example.com, link (cleartext) ready,... +S:MAIL FROM: +R:250 2.1.3 postmaster@example.com sender ok +S:RCPT TO: +R:250 5.6.7 Address will be processed +S:RCPT TO: +R:250 5.6.7 Address will be processed +#------------------------------------------------------------------------- +#-sending data +C:DATA 354 3.5.0 End data with . +D:Subject: (feed030) Very Simple email contents +C:T +D:From: Maitre Post +D:To: Big Master +D: +D:this email is for local test purpose only +D:and test log display +D: +C:. +#------------------------------------------------------------------------- +R:250-3.5.3 Session ID=<... +R:250-3.5.3 data stream received:... +R:250 3.5.3 Message accepted for delivery +#------------------------------------------------------------------------- +S:QUIT +R:221 2.0.0 Bye, closing connection... +#------------------------------------------------------------------------- diff --git a/data-feed/feedx10.tst b/data-feed/feedx10.tst new file mode 100644 index 0000000..9d0928f --- /dev/null +++ b/data-feed/feedx10.tst @@ -0,0 +1,5 @@ +T:(feedx10) Making sure we can reject a remote +C:CONNECT +#==================================================== +#take a "invalid" imp number as server remote IP +R:521 7.0.0 Remote server credit too low diff --git a/data-feed/feedxx.tst b/data-feed/feedxx.tst new file mode 100644 index 0000000..845b533 --- /dev/null +++ b/data-feed/feedxx.tst @@ -0,0 +1,39 @@ +T:(feed05) sending a small email after beeing authenticated +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#==================================================== +#-sending authentication request via BASE64 +#https://www.base64encode.org/ +#AUTH LOGIN +#-Usernanme 'webmaster@example.com' --> 'd2VibWFzdGVyQGV4YW1wbGUuY29t' +#-password 'mailleur' --> 'bWFpbGxldXI=" +#AUTH PLAIN +#-full seq "authid\0webmaster@example.com\0mailleur' +# --> YXV0aGlkXDB3ZWJtYXN0ZXJAZXhhbXBsZS5jb21cMG1haWxsZXVy +# authid will be discarded by authentication procedure +#authid can be missing +S:AUTH PLAIN +R:334 5.7.1 Please provide auth sequence +S:YXV0aGlkXDB3ZWJtYXN0ZXJAZXhhbXBsZS5jb21cMG1haWxsZXVy +R:235 5.7.5 Authentication successful +S:AUTH PLAIN YXV0aGlkXDB3ZWJtYXN0ZXJAZXhhbXBsZS5jb21cMG1haWxsZXVy +R:235 5.7.5 Authentication successful +S:AUTH LOGIN +#requesting Username: +R:334 VXNlcm5hbWU6 +#sending 'webmaster@example.com' as B64 +S:d2VibWFzdGVyQGV4YW1wbGUuY29t +#requesting Password: +R:334 UGFzc3dvcmQ6 +#sending 'mailleur' as B64 +S:bWFpbGxldXI= +R:235 5.7.5 Authentication successful +S:AUTH PLAIN AHVzZXIxQG1haWxwb3N0Zy5leGFtcGxlLmNvbQBtYWlsbGV1cg== +R:504 5.7.4 authentication failed +#\0bigre_bigre\0nouser +S:AUTH PLAIN XDBiaWdyZV9iaWdyZVwwbm91c2Vy +R:504 5.7.4 authentication failed +#\0postmaster@example.com\0nopasswd +S:AUTH PLAIN XDBwb3N0bWFzdGVyQGV4YW1wbGUuY29tXDBub3Bhc3N3ZA== +R:504 5.7.4 authentication failed +S:QUIT +R:221 2.0.0 Bye, closing connection... diff --git a/data-feed/feedyy.tst b/data-feed/feedyy.tst new file mode 100644 index 0000000..f37727a --- /dev/null +++ b/data-feed/feedyy.tst @@ -0,0 +1,19 @@ +T:(feed05) sending a small email after beeing authenticated +R:220 mailleur.example.com, ESMTP (cleartext) mailleur... +#==================================================== +#-sending authentication request via BASE64 +#https://www.base64encode.org/ +#AUTH LOGIN +#-Usernanme 'webmaster@example.com' --> 'd2VibWFzdGVyQGV4YW1wbGUuY29t' +#-password 'mailleur' --> 'bWFpbGxldXI=" +#AUTH PLAIN +#-full seq "authid\0webmaster@example.com\0mailleur' +# --> YXV0aGlkXDB3ZWJtYXN0ZXJAZXhhbXBsZS5jb21cMG1haWxsZXVy +# authid will be discarded by authentication procedure +#authid can be missing +S:AUTH PLAIN YXV0aGlkXDB3ZWJtYXN0ZXJAZXhhbXBsZS5jb21cMG1haWxsZXVy +R:235 5.7.5 Authentication successful +S:MAIL FROM: +R:250 2.1.3 webmaster@example.com sender ok +S:QUIT +R:221 2.0.0 Bye, closing connection... diff --git a/data-feed/zone.example.com b/data-feed/zone.example.com new file mode 100644 index 0000000..f062c1c --- /dev/null +++ b/data-feed/zone.example.com @@ -0,0 +1,105 @@ +$ORIGIN example.com. +$TTL 5m ; 5 min +@ IN SOA dns1.example.com. root.example.com. ( + 0000000000 ; Serial_Marker + 600 ; Refresh (10 min) + 300 ; retry (5 min) + 1209600 ; expiry (1W) + 900 ; minimum (15 min) + ) + + IN NS dns1 + IN NS dns2 + +;--------------------------------------------------------------------- +dns1 IN A 127.0.0.1 +dns2 IN A 127.0.0.2 +;--------------------------------------------------------------------- +;test MX using IP 127.0.0.255 +@ IN A 127.0.0.127 + IN MX 10 mx1 + IN MX 20 mx2 + +mx1 IN A 127.0.0.128 +mx2 IN A 127.0.0.129 + +;--------------------------------------------------------------------- +$ORIGIN example.com. +chkmx IN A 127.0.0.255 + IN TXT ( + "v=info " + "chkmx PASS with 127.0.0.255," + "chkmx FAIL with 127.0.0.1" + ) + IN TXT ( + "v=spf1 " + "mx:spf.example.com/25 " + "-all" + ) + +chkip4 IN A 127.0.1.255 + IN TXT ( + "v=info " + "chkip4 PASS with 127.0.1.255," + "chkip4 FAIL with 127.0.1.1" + ) + IN TXT ( + + "v=spf1 " + "ip4:127.0.1.128/25 " + "-all" + ) + +chkip6 IN AAAA fc00:0:0:0:ffff::7f00:002f + IN TXT ( + "v=info " + "chkip6 PASS with PREFIX::127.0.2.255, " + "chkip6 FAIL with PREFIX::127.0.2.1" + ) + IN TXT ( + "v=spf1 " + "ip6:0:0:0:0:0:ffff:7f00:0280/121 " + "-all" + ) + +chkaddr IN A 127.0.3.255 + IN TXT ( + "v=info " + "chkaddr PASS with 127.0.3.255," + "chkaddr FAIL with 127.0.3.1" + "chkaddr PASS with 127.0.1.255," + "chkaddr FAIL with 127.0.1.1" + "chkaddr PASS with PREFIX::127.0.2.255, " + "chkaddr FAIL with PREFIX::127.0.2.1" + ) + IN TXT ( + "v=spf1 " + "a " + "a:chkip4 " + "a:chkip6/121 " + "-all" + ) + +;check include +chkinc IN TXT ( + "v=info " + "chkinc PASS with 127.0.0.255," + "chkinc FAIL with 127.0.0.1" + "chkinc PASS with 127.0.1.255," + "chkinc FAIL with 127.0.1.1," + "chkinc PASS with PREFIX::127.0.2.255, " + "chkinc FAIL with PREFIX::127.0.2.1," + "chkinc PASS with PREFIX::127.0.3.255," + "chkinc FAIL with PREFIX::127.0.3.1," + ) + + IN TXT ( + "v=spf1 " + "include:chkimx" + "include:chkip4" + "include:chkip6" + "include:chkaddr" + "-all" + ) + +;--------------------------------------------------------------------- diff --git a/data-spf/spf.tst b/data-spf/spf.tst new file mode 100644 index 0000000..c8f868e --- /dev/null +++ b/data-spf/spf.tst @@ -0,0 +1,29 @@ +#======================================================== +#data to check if SPF are properly seen +#NOTE: this test rely on the fact +#"spf.example.com" is accessible via a DNS request. +#======================================================== +#Checking MX +#Acceptable IP number +spf_pass chkmx.spf.example.com 127.0.0.255 +#wrong MX ip number +spf_fail chkmx.spf.example.com 127.0.0.1 +#Checking IP4 +spf_pass chkip4.spf.example.com 127.0.1.255 +spf_fail chkip4.spf.example.com 127.0.1.1 +#Checking IP6 +spf_pass chkip6.spf.example.com 0:0:0:0:0:FFFF:127.0.2.255 +spf_fail chkip6.spf.example.com 0::ffff:127.0.2.1 +##checking addr +spf_fail chkaddr.spf.example.com 127.0.1.1 +spf_pass chkaddr.spf.example.com 127.0.1.255 +spf_fail chkaddr.spf.example.com 127.0.3.1 +spf_pass chkaddr.spf.example.com 127.0.3.255 +spf_fail chkaddr.spf.example.com 0::ffff:127.0.1.1 +spf_pass chkaddr.spf.example.com 0::ffff:127.0.1.255 +spf_fail chkaddr.spf.example.com 0::ffff:127.0.3.1 +spf_pass chkaddr.spf.example.com 0::ffff:127.0.3.255 +#-------------------------------------------------------- +#test with gmail. +spf_pass gmail.com 74.125.224.54 +#-------------------------------------------------------- diff --git a/dbg/mailleur.conf b/dbg/mailleur.conf new file mode 100644 index 0000000..106b010 --- /dev/null +++ b/dbg/mailleur.conf @@ -0,0 +1,80 @@ +#file used to set environment configuration +#------------------------------------------------ +#Defining application name +APPNAME=mailleur +#root working directoy definition for the whole application +ROOTBASE="/" +#defining local default domain +DFLTDOMAIN="safe.ca" +#defining the local REALM +#Caution! the realm is hardcoded within data-base +#and USED too to hash the user passwd +#Changing this value coule be a trouble make +#(entering again ALL user password) +REALM="mailleur-email" +#------------------------------------------------ +#list of listening port to do SMTP protocole +#format +#protocol|ipnum|port|iteration[,protocol|ipnum|port|iteration]++ +#example +#stmtps|ipnum|465|5 -> protocol smtps|IP number|port 465|5 iterations +#|ipnum||| -> smtp|ipnum|25|2 +#||,smtps||465|2 -> smtp|0.0.0.0|25|2 + smtps||465|2 +#|| -> smtp|0.0.0.0|25|2 +#Examples +#SMTPPORTS="|127.127.10.25|1025|,smtps|127.127.10.25|1026|1" +#SMTPPORTS="|127.127.10.25|1025|" +#SMTPPORTS="smtps|127.127.10.25|1065|1" +#Defaults +SMTPPORTS="|||5,smtps||465|3,smtp||587|2" +#------------------------------------------------ +#SSL Security level default value +#CIPHER_LIST="DEFAULT" +#SSL_SECURITY=2 +#------------------------------------------------ +#Defining SERVER mode Certificate data +CA_ROOT_SRV="/etc/pki/tls/make-ca/ca-bundle.crt" +CA_VERIFY_SRV=0 #to check PEER/client remote certificate +#If certificate set via do_dns_tlsa.sh (letsencrypt) +#CA_CERT_SRV="/etc/certbot/mailleur/mailleur-fullchain.pem" +#CA_KEY_SRV="/etc/certbot/mailleur/mailleur-key.pem" +#If certificate are self signed (default installation) +#CA_CERT_SRV="/etc/pki/mailleur/mailleur-cert.pem" +#CA_KEY_SRV="/etc/pki/mailleur/mailleur-key.pem" +#Symbolic link set at installation +CA_CERT_SRV="/etc/mailleur/pki/mailleur-cert.pem" +CA_KEY_SRV="/etc//mailleur/pki/mailleur-key.pem" +#------------------------------------------------ +#Defining CLIENT mode Certificate data +CA_ROOT_CLT="/etc/pki/tls/make-ca/ca-bundle.crt" +CA_VERIFY_CLT=0 #to check PEER/server remote certificate +#If certificate set via do_dns_tlsa.sh (letsencrypt) +#CA_CERT_CLT="/etc/certbot/mailleur/mailleur-fullchain.pem" +#CA_KEY_CLT="/etc/certbot/mailleur/mailleur-key.pem" +#If certificate are self signed (default installation) +#CA_CERT_CLT="/etc/pki/mailleur/mailleur-cert.pem" +#CA_KEY_CLT="/etc/pki/mailleur/mailleur-key.pem" +#Symbolic link set at installation +CA_CERT_CLT="/etc/mailleur/pki/mailleur-cert.pem" +CA_KEY_CLT="/etc/mailleur/pki/mailleur-key.pem" +#------------------------------------------------ +#Configured for Postgresql database +#DB_TYPE can be either POSTGRESQL,MYSQL, default POSTGRESQL +DB_TYPE=POSTGRESQL +DB_NAME=mailleur +DB_HOST=localhost +DB_PORT=5432 +DB_LANG="UTF-8" +#------------------------------------------------ +#Dovecot storage directory +DOV_MAILDIR="/var/spool/mailleur/mails" +#------------------------------------------------ +#The list of public blacklist serveur +BLACKLISTER=/etc/mailleur/blacklister.conf +#the list of IP from which we accept to relay email +RELAYABLE=/etc/mailleur/relayed.conf +#------------------------------------------------ +#Minimal credit level to which remote is rejected at once +#if credit is equal or below that level +RJCTCRED=-50 +#------------------------------------------------ diff --git a/dovecot/conf.d/70-mailleur-mysql.conf b/dovecot/conf.d/70-mailleur-mysql.conf new file mode 100644 index 0000000..7895daa --- /dev/null +++ b/dovecot/conf.d/70-mailleur-mysql.conf @@ -0,0 +1,11 @@ +# ------------------------------- +# 70-mailleur-mysql-conf +# Configuration Dovecot to use Mariadb server +# ------------------------------- +sql_driver = mysql + +mysql remote { + host = localhost.localdomain + user = mailleur + dbname = mailleur + } diff --git a/dovecot/conf.d/70-mailleur-pgsql.conf b/dovecot/conf.d/70-mailleur-pgsql.conf new file mode 100644 index 0000000..ca34767 --- /dev/null +++ b/dovecot/conf.d/70-mailleur-pgsql.conf @@ -0,0 +1,13 @@ +# ------------------------------- +# 70-pgsql.conf +# Configuration Dovecot to use PostgreSQL server +# ------------------------------- +sql_driver = pgsql + +pgsql remote { + parameters { + host = localhost.localdomain + user = mailleur + dbname = mailleur + } + } diff --git a/dovecot/conf.d/80-mailleur-usesql.conf b/dovecot/conf.d/80-mailleur-usesql.conf new file mode 100644 index 0000000..d83fd8c --- /dev/null +++ b/dovecot/conf.d/80-mailleur-usesql.conf @@ -0,0 +1,23 @@ +# ------------------------------- +# 80-usesql.conf +# Configuration Dovecot to use SQL database +# ------------------------------- +# --- Passdb : authentication via SQL --- +passdb sql { + default_password_scheme = SHA512-CRYPT + query = SELECT password FROM emails WHERE email='%{user}'; + } + +# --- Userdb : user data(home, uid, gid) via SQL --- +# +# +# + +userdb sql { + query = SELECT 'mailleur' AS uid,'mail' AS gid, \ + '/var/spool/mailleur/mails/%{user | domain}/%{user | username}' \ + AS home,'maildir:~/dovecot' AS mail \ + FROM emails WHERE email='%{user}'; + } + + diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..9a857ab --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,236 @@ +#-------------------------------------------------------------------- +#Executable generation area +#-------------------------------------------------------------------- +debug : toremake + @ $(MAKE) \ + $(PAR) \ + OPTIME="-g -DMODEDEBUG" \ + objs + @ echo "library compiled in '$@' mode, now ready" + +prod : toremake + @ $(MAKE) $(PAR) OPTIME="-O3" objs + @ echo "library compiled in '$@' mode, now ready" + +clean : + - rm -fr *.so.* *.o *.a *.tar.gz + +allclean: clean + - rm -fr *.d + +#-------------------------------------------------------------------- +#Equivalences +#-------------------------------------------------------------------- +OBJS= \ + modrec.o \ + lvleml.o \ + geseml.o gestcp.o gesspf.o gessql.o \ + devlog.o devsoc.o devsql.o \ + unidig.o unidns.o unieml.o unipar.o \ + uniprc.o unisig.o unisql.o unitls.o \ + subafn.o subcnv.o subrou.o + +LIBS= \ + libmar.a libpos.a + +objs : $(OBJS) $(LIBS) + @ ar -cr libmail.a $(OBJS) + +#-------------------------------------------------------------------- +#Dependances +modrec.d \ +modrec.o: \ + subrou.h \ + uniprc.h \ + unisig.h \ + devsoc.h \ + gestcp.h \ + modrec.h modrec.c + +lvleml.d \ +lvleml.o: \ + subcnv.h subrou.h \ + unidig.h unidns.h unieml.h uniprc.o \ + gestcp.h gessql.h \ + lvleml.h lvleml.c + +gesspf.d \ +gesspf.o: \ + subrou.h \ + gesspf.h gesspf.h + +geseml.d \ +geseml.o: \ + subrou.h \ + unidns.h unieml.h unipar.h unitls.h \ + devsql.h \ + geseml.h geseml.h + +gestcp.d \ +gestcp.o: \ + subrou.h \ + unieml.h \ + uniprc.h \ + unisig.h \ + gestcp.h gestcp.c + +gessql.d \ +gessql.o: \ + unisql.h \ + devsql.h \ + gessql.h gessql.c + +devlog.o: \ + subrou.h \ + uniprc.h \ + devlog.h devlog.c + +devsoc.o: \ + subafn.h subrou.h \ + unidns.h unieml.h uniprc.h \ + devsoc.h devsoc.c + +devsql.o: \ + unipos.h \ + unimar.h \ + devsql.h devsql.c + +unidig.o: \ + subrou.h subcnv.h \ + unidig.h unidig.c + +unidns.o: \ + subafn.h subrou.h \ + unidns.h unidns.c + +unieml.o: \ + subrou.h \ + unieml.h unieml.c + +unimar.o: \ + subrou.h \ + unimar.h unimar.c + +unipar.o: \ + subrou.h \ + unipar.h unipar.c + +unipos.o: \ + subrou.h \ + unipos.h unipos.c + +uniprc.o: \ + subrou.h \ + uniprc.h uniprc.c + +unisig.o: \ + subrou.h \ + unisig.h unisig.c + +unitls.o: \ + subrou.h \ + unitls.h unitls.c + +subrou.o: \ + subrou.h subrou.c + +subafn.o: \ + subafn.h subafn.c + +subcnv.o: \ + subcnv.h subcnv.c + +lvleml.h: \ + devsoc.h devsql.h \ + geseml.h gestcp.h + +geseml.h: \ + unisql.h + +gestcp.h: \ + subrou.h \ + unidns.h \ + devlog.h devsoc.h + +gessql.h: \ + unieml.h \ + devsql.h + +gesspf.h: \ + subafn.h + +devsoc.h: \ + unitls.h + +devsql.h: \ + unisql.h + +uniprc.h: \ + subrou.h + +unieml.h \ +unitls.h \ + : \ + subafn.h + +libpos.a: unimar.o \ + subrou.h \ + unipos.h unipos.c + @ $(CC) \ + $(CFLAGS) \ + $(CPPFLAGS) \ + -DDATABASE=1 \ + -Dwith_postgres \ + -c \ + -g \ + -o libpos.o unipos.c + @ ar -cr libpos.a libpos.o unimar.o + +libmar.a: unipos.o \ + subrou.h \ + unimar.h unimar.c + @ $(CC) \ + $(CFLAGS) \ + $(CPPFLAGS) \ + -DDATABASE=2 \ + -Dwith_mysql \ + -c \ + -g \ + -o libmar.o unimar.c + @ ar -cr libmar.a libmar.o unipos.o + +#-------------------------------------------------------------------- +toremake: Makefile + touch toremake + - rm -f $(OBJS) $(LIBMAIL) + +#-------------------------------------------------------------------- +#to manage dependencies +%.d: %.c + @ set -e; rm -f $@; \ + $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ + sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +sources = \ + modrec.c \ + lvleml.c \ + geseml.c gesspf.c gessql.c gestcp.c \ + devlog.c devsoc.c devsql.c \ + unidig.c unidns.c unieml.c unimar.c \ + unipar.c unipos.c uniprc.c unisig.c \ + unisql.c unitls.c \ + subafn.c subcnv.c subrou.c \ + +include $(sources:.c=.d) +#-------------------------------------------------------------------- +.PHONY: clean allclean +#-------------------------------------------------------------------- +CC = gcc +LD = gcc +CPPFLAGS= -DPUBLIC='' +CFLAGS = -Wall -D_GNU_SOURCE \ + $(OPTIME) +LIBMAIL = libmail.a libmar.a libpos.a +PAR = -j`/usr/bin/getconf _NPROCESSORS_ONLN` +#-------------------------------------------------------------------- diff --git a/lib/devlog.c b/lib/devlog.c new file mode 100644 index 0000000..c58aa14 --- /dev/null +++ b/lib/devlog.c @@ -0,0 +1,377 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Log management implementation module */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "uniprc.h" +#include "devlog.h" + +#define JRLDIR "/var/spool/"APPNAME + +typedef struct { + char *filename; //the log filename + FILE *file; //The log file pointer + TIMESPEC start; //log start time + }LOGTYP; + +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to free reference to a log device */ +/* */ +/********************************************************/ +static LOGTYP *freelog(LOGTYP *log) + +{ +if (log!=(LOGTYP *)0) { + log->filename=rou_freestr(log->filename); + (void) free(log); + log=(LOGTYP *)0; + } +return log; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to merge current log within current */ +/* daily logs. */ +/* */ +/********************************************************/ +static _Bool mergelog(const char *logname,long *debut,long *fin) + +{ +#define OPEP "devlog.c:mergelog" +#define UFTIME "%Y%m%d" +#define EVENT "logevent" + +_Bool status; +char *event; +FILE *fevent; +FILE *flog; +time_t curtime; +char asctemps[100]; +char daily[200]; +int phase; +int proceed; + +status=true; +fevent=(FILE *)0; +flog=(FILE *)0; +curtime=time((time_t)0); +(void) strftime(asctemps,sizeof(asctemps),UFTIME,localtime(&curtime)); +event=(char *)0; +(void) strcpy(daily,""); +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG %s phase='%d' pid='%d'",OPEP,phase,getpid()); + switch (phase) { + case 0 : //do we have a log name? + if (logname==(char *)0) { + (void) rou_alert(0,"%s logname is missing (Bug!?)",OPEP); + proceed=false; //trouble trouble + } + break; + case 1 : //duplicat logname + (void) strncpy(daily,logname,sizeof(daily)-strlen(daily)); + if (strlen(daily)>0) { + char *ptr; + + if ((ptr=strrchr(daily,'/'))!=(char *)0) + *ptr='\000'; + } + (void) rou_asprintf(&event,"%s/event-%s.jrl",daily,asctemps); + break; + case 2 : //opening log file + if ((flog=fopen(logname,"r"))==(FILE *)0) { + (void) rou_alert(0,"%s Unable to open log file <%s> (error=<%s>)", + OPEP,logname,strerror(errno)); + phase=999; //no need to go further + } + break; + case 3 : //opening log file + if ((fevent=fopen(event,"a+"))==(FILE *)0) { + (void) rou_alert(0,"%s Unable to open event file <%s> (error=<%s>)", + OPEP,event,strerror(errno)); + (void) fclose(flog); + phase=999; //no need to go further + } + break; + case 4 : //locking access to logname + if (flock(fileno(fevent),LOCK_EX)<0) { + (void) rou_alert(0,"%s Unable to lock acces to log file <%s> " + "(error=<%s>) (Bug?)", + OPEP,event,strerror(errno)); + (void) fclose(fevent); + (void) fclose(flog); + phase=999; //no need to go further + } + break; + case 5 : //Setting file position + (void) fseek(fevent,(long)0,SEEK_END); + *debut=ftell(fevent); //First char position + break; + case 6 : { //merging file + char ch; + + while ((ch=fgetc(flog))!=EOF) + fputc(ch,fevent); + break; + case 7 : //unlocking file + (void) flock(fileno(fevent),LOCK_UN); + *fin=ftell(fevent)-1; //Last char Position + (void) fclose(fevent); + (void) fclose(flog); + } + break; + case 8 : //removing log file + if (unlink(logname)<0) { + (void) rou_alert(0,"%s Unable to delete log file <%s> (error=<%s>)", + OPEP,logname,strerror(errno)); + } + break; + default : //SAFE guard + event=rou_freestr(event); + proceed=false; + break; + } + phase++; + } +return status; +#undef UFTIME +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to open a session log to collect all */ +/* exchange with remote SMTP client. */ +/* return a NULL file pointeur if trouble. */ +/* */ +/********************************************************/ +PUBLIC LOGPTR *log_openlog(char *logname,const char *cmt) + +{ +#define OPEP "devlog.c:log_openlog" + +LOGTYP *log; +char logdir[PATH_MAX]; +int phase; +int proceed; + +log=(LOGTYP *)0; +(void) snprintf(logdir,sizeof(logdir),"%s/%s-logs/",JRLDIR,execname); +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 log name? + if (logname==(char *)0) { + (void) rou_alert(0,"%s logname is missing (Bug!?)",OPEP); + phase=999; + } + break; + case 1 : //generating log file name + char *loc; + + log=(LOGTYP *)calloc(1,sizeof(LOGTYP)); + loc=rou_apppath(logdir); + (void) rou_asprintf(&(log->filename),"%s%s-%05d.jrl",loc,logname,getpid()); + if (rou_do_mkpdir(loc)==false) { + (void) rou_alert(0,"%s Unable to create log directory <%s> (system?)", + OPEP,loc); + log=freelog(log); + phase=999; + } + loc=rou_freestr(loc); + break; + case 2 : //opening the log file + if ((log->file=fopen(log->filename,"w"))==(FILE *)0) { + (void) rou_alert(0,"%s Unable to open file <%s> (error=<%s>)", + OPEP,log->filename,strerror(errno)); + log=freelog(log); + phase=999; //No need to go further + } + break; + case 3 : //writing a minimal data + (void) clock_gettime(CLOCK_REALTIME,&(log->start)); + (void) fprintf(log->file,"\n#-----------------------------\n"); + (void) fprintf(log->file,"#%s",ctime(&(log->start.tv_sec))); + if (cmt!=(const char *)0) + (void) fprintf(log->file,"#%s\n",cmt); + (void) fflush(log->file); + log->start.tv_sec=0; + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return (LOGPTR *)log; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to close a session log */ +/* return the close status. */ +/* */ +/********************************************************/ +PUBLIC LOGPTR *log_closelog(LOGPTR *logptr,long *debut,long *fin) + +{ +#define OPEP "devlog.c:log_closelog" + +LOGTYP *log; +int phase; +int proceed; + +log=(LOGTYP *)logptr; +*debut=0; +*fin=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 log reference? + if (log==(LOGTYP *)0) + phase=999; + break; + case 1 : //closing log file + if (fclose(log->file)!=0) { + (void) rou_alert(0,"%s Unable to close log file <%s> (error=<%s>)", + OPEP,log->filename,strerror(errno)); + phase=999; + } + break; + case 2 : //merging current log + if (mergelog(log->filename,debut,fin)==false) + phase=999; + break; + case 3 : //removing logfile + break; + default : //SAFE guard + logptr=freelog(log); + proceed=false; + break; + } + phase++; + } +return logptr; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to insert a formated string within */ +/* log file. */ +/* */ +/********************************************************/ +PUBLIC int log_fprintlog(LOGPTR *logptr,_Bool showtime,const char *format,...) + +{ +#define OPEP "devlog.c:log_fprintlog" +int taille; +LOGTYP *log; +char chrono[30]; +char *line; +va_list args; +int phase; +int proceed; + +taille=0; +log=(LOGTYP *)logptr; +(void) strcpy(chrono,""); +line=(char *)0; +va_start(args,format); +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 log name? + if (log==(LOGTYP *)0) { + (void) rou_alert(0,"%s log pointer is NULL (Bug!?)",OPEP); + phase=999; + } + break; + case 1 : //set time marker within log + if (log->start.tv_sec==0) { + time_t timer; + struct tm* tm_info; + char buffer[10]; + + timer=time((time_t *)0); + tm_info=localtime(&timer); + (void) strftime(buffer,sizeof(buffer),"%T",tm_info); + (void) clock_gettime(CLOCK_REALTIME,&(log->start)); + (void) snprintf(chrono,sizeof(chrono),"%s.%03ld", + buffer,log->start.tv_nsec/1000000); + } + else { + (void) snprintf(chrono,sizeof(chrono),"%12s"," "); + if (showtime==true) { + register unsigned int delta; + u_int millisec; + u_int sec; + u_int min; + + delta=rou_getdifftime(&(log->start)); + millisec=delta%1000; + sec=(delta/1000)%60; + min=(delta/1000)/60; + if (min==0) + (void) snprintf(chrono,sizeof(chrono),"%6s%02d.%03d","+", + sec,millisec); + else + (void) snprintf(chrono,sizeof(chrono),"%3s%02d:%02d.%03d","+", + min,sec,millisec); + } + } + break; + case 2 : //formating the line + if ((taille=rou_vasprintf(&line,format,args))<0) { + (void) rou_alert(0,"%s Unable to format <%s> (Bug!?)",OPEP,format); + phase=999; + } + break; + case 3 : //string the formated line within logs + (void) fprintf(log->file,"%s %s\n",chrono,line); + (void) fflush(log->file); + break; + default : //SAFE guard + line=rou_freestr(line); + proceed=false; + break; + } + phase++; + } +va_end(args); +return taille; +#undef OPEP +} diff --git a/lib/devlog.d b/lib/devlog.d new file mode 100644 index 0000000..66ed141 --- /dev/null +++ b/lib/devlog.d @@ -0,0 +1,53 @@ +devlog.o devlog.d : devlog.c /usr/include/stdc-predef.h /usr/include/linux/limits.h \ + /usr/include/sys/file.h /usr/include/features.h \ + /usr/include/features-time64.h /usr/include/bits/wordsize.h \ + /usr/include/bits/timesize.h /usr/include/sys/cdefs.h \ + /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h /usr/include/fcntl.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/fcntl.h \ + /usr/include/bits/fcntl-linux.h \ + /usr/include/bits/types/struct_timespec.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/stat.h /usr/include/bits/struct_stat.h \ + /usr/include/errno.h /usr/include/bits/errno.h \ + /usr/include/linux/errno.h /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/malloc.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/stdio.h /usr/include/bits/libc-header-start.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/stdlib.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/sys/types.h \ + /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/byteswap.h \ + /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \ + /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/string.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/strings.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h /usr/include/time.h \ + /usr/include/bits/time.h /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h uniprc.h devlog.h diff --git a/lib/devlog.h b/lib/devlog.h new file mode 100644 index 0000000..0303e5b --- /dev/null +++ b/lib/devlog.h @@ -0,0 +1,28 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/************************************************/ +/* */ +/* device level, logs management */ +/* declaration. */ +/* */ +/************************************************/ +#ifndef DEVLOG +#define DEVLOG + +#include + +typedef void LOGPTR; + +//procedure to open a session log +extern LOGPTR *log_openlog(char *logname,const char *cmt); + +//procedure to close a previously open session log +extern LOGPTR *log_closelog(LOGPTR *logptr,long *debut,long *fin); + +//procedure to write a sequence within the current log +extern int log_fprintlog(LOGPTR *logptr,_Bool showtime,const char *format,...); + +//procedure to merge session log contents to +//current daily log +extern int log_mergelog(char *logname); + +#endif diff --git a/lib/devsoc.c b/lib/devsoc.c new file mode 100644 index 0000000..d663602 --- /dev/null +++ b/lib/devsoc.c @@ -0,0 +1,1669 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Low level subroutine declaration */ +/* to handle TCP socket. */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "subafn.h" +#include "unidns.h" +#include "unieml.h" +#include "uniprc.h" +#include "unitls.h" +#include "devsoc.h" + +#define MXCARIN 1200 //maximun number of char within carpile + //full line sould be more than 998 char + +typedef struct { + PROTYP proto; //Connexion protocol type + int handle; //connexion handle + _Bool connected;//soc is connected to remote + _Bool modtls; //soc is in TLS mode + TLSTYP *tls; //full TPS/SSL channel + char *cipherid; //Information on TLS crypting + int maxcarin; //absolute number within carin + char *EOL; //End of line marker + int carin; //number of char within incpt; + char *carpile; //area to store incoming char + char *ip; //Binding IP //IPV4 or IPV6 + char *port; //Binding Port + char *hostname; //binding hostname + time_t lasttry; //successful binding last time + int iteration; //number of soc slot used on the IP + }SOCTYP; + +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to free memory used by a */ +/* binding info. */ +/* */ +/* */ +/********************************************************/ +static SOCPTR *freesocket(SOCPTR *socptr) + +{ +if (socptr!=(SOCPTR *)0) { + register SOCTYP *soc; + + soc=(SOCTYP *)socptr; + soc->cipherid=rou_freestr(soc->cipherid); + soc->hostname=rou_freestr(soc->hostname); + soc->ip=rou_freestr(soc->ip); + soc->port=rou_freestr(soc->port); + soc->carpile=rou_freestr(soc->carpile); + soc->EOL=rou_freestr(soc->EOL); + (void) free(soc); + socptr=(SOCPTR *)0; + } +return socptr; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to create a new socket */ +/* */ +/* */ +/********************************************************/ +static SOCTYP *newsocket() + +{ +SOCTYP *soc; + +soc=(SOCTYP *)calloc(1,sizeof(SOCTYP)); +soc->handle=-1; +soc->maxcarin=MXCARIN; +soc->carin=0; +soc->EOL=strdup(CRLF); +soc->carpile=(char *)calloc(soc->maxcarin,sizeof(char)); +return soc; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to duplicate a socket */ +/* */ +/********************************************************/ +static SOCTYP *dupsocket(SOCTYP *soc) + +{ +SOCTYP *newsoc; + +newsoc=(SOCTYP *)newsocket(); +newsoc->proto=soc->proto; +newsoc->handle=soc->handle; +newsoc->connected=soc->connected; +newsoc->ip=strdup(soc->ip); +newsoc->port=strdup(soc->port); +newsoc->iteration=soc->iteration; +return newsoc; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to wait incoming connexion on a */ +/* plain (not crypted) socket */ +/* */ +/********************************************************/ +static int getnewhandle(SOCTYP *soc) + +{ +#define OPEP "devsoc.c:getnewhandle" + +int newhandle; + +if ((newhandle=accept(soc->handle,(SOCKADDR *)0,(socklen_t *)0))<0) { + if (errno==EAGAIN) + errno=EWOULDBLOCK; + switch (errno) { + case EWOULDBLOCK : + (void) rou_alert(0,"%s Socket on IP/PORT <%s/%s> is in no_block mode " + "(Bug?!, errno=<%s>)", + OPEP,soc->ip,soc->port,strerror(errno)); + break; + case EINVAL : + (void) rou_alert(0,"%s Socket on IP/PORT <%s/%s> not available " + "(Bug?!, errno=<%s>)", + OPEP,soc->ip,soc->port,strerror(errno)); + break; + case EINTR : + (void) rou_alert(5,"%s Socket on IP/PORT <%s/%s> got a signal " + "(errno=<%s>)", + OPEP,soc->ip,soc->port,strerror(errno)); + break; + default : + (void) rou_alert(0,"%s Unexpected error on IP/PORT <%s/%s> (errno=<%s>)", + OPEP,soc->ip,soc->port,strerror(errno)); + break; + } + } +return newhandle; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to check if a socket is connected */ +/* This procedure is called when pool exit with */ +/* en event. */ +/* */ +/********************************************************/ +static _Bool isconnected(SOCTYP *soc) + +{ +_Bool connected; +char buffer[10]; + +connected=true; +if (recv(soc->handle,buffer,sizeof(buffer),MSG_PEEK|MSG_DONTWAIT)==0) + connected=false; +return connected; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to clear and return socket status */ +/* return the errno. */ +/* */ +/********************************************************/ +static int checksockstat(int handle) + +{ +int status; +socklen_t len; + +status=0; +len=sizeof(status); +if (getsockopt(handle,SOL_SOCKET,SO_ERROR,&status,&len)<0) { + status=errno; + } +return status; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to open plain incoming channel */ +/* */ +/********************************************************/ +static _Bool openplain(SOCTYP *soc) + +{ +#define OPEP "devsoc:plainsoc" + +_Bool good; +int newhandle; +int flags; +int phase; +_Bool proceed; + +good=false; +newhandle=-1; +flags=0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //First prepare a new socket + if ((newhandle=getnewhandle(soc))<0) + phase=999; //no newhandle troub trouble + break; + case 1 : //getting newhandle flag + if ((flags=fcntl(newhandle,F_GETFL,0))<0) { + (void) rou_core_dump("%s, Unable to get socket descripteur on " + "IP/PORT <%s/%s> (Bug? error=<%s>)", + OPEP,soc->ip,soc->port,strerror(errno)); + phase=999; //never reached + } + break; + case 2 : //setting newhandle working mode + if ((flags=fcntl(newhandle,F_SETFL,flags|O_NONBLOCK|O_ASYNC))<0) { + (void) rou_core_dump("%s, Unable to set socket descripteur on " + "IP/PORT <%s/%s> (Bug? error=<%s>)", + OPEP,soc->ip,soc->port,strerror(errno)); + phase=999; //never reached + } + break; + case 3 : //Socket ready + soc->handle=newhandle; + soc->connected=true; + good=true; + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return good; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to close plain incoming channel */ +/* */ +/********************************************************/ +static void closeplain(SOCTYP *soc) + +{ +#define OPEP "devsoc.c:closeplain" + +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 : //is the connect still active + if (soc->connected==false) //no!, no need to shutdown + phase=999; //no need to go further + break; + case 1 : //shutting down the link + if (shutdown(soc->handle,SHUT_RDWR)<0) { + switch (errno) { + case ENOTCONN : //already disconnect by other side! + (void) rou_alert(0,"%s [%s:%s] Already disconnected (errno=<%s>)", + OPEP,soc->ip,soc->port,strerror(errno)); + break; + default : + (void) rou_alert(0,"%s unable to shutdown [%s:%s] (errno=<%s>)", + OPEP,soc->ip,soc->port,strerror(errno)); + break; + } + } + break; + case 2 : //closing connexion + if (close(soc->handle)<0) { + (void) rou_alert(0,"%s unable to close channel [%s:%s] properly " + "(errno=<%s>)", + OPEP,soc->ip,soc->port,strerror(errno)); + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to extract next line from the socket */ +/* incoming pile. */ +/* Return the number of character, zero if the */ +/* line is empty, -1 if no char are available. */ +/* */ +/********************************************************/ +static int doextract(SOCTYP *soc,char **lineptr) + +{ +#define OPEP "devsoc.c:doextract," + +int got; +char *eol; +int phase; +_Bool proceed; + +*lineptr=(char *)0; +got=-1; +eol=(char *)0; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG %s phase='%d' carin='%d'",OPEP,phase,soc->carin); + switch (phase) { + case 0 : //Do we have dat in carpile + if (soc->carin==0) + phase=999; //No char,no need to check for line + break; + case 1 : //do we have a buffer full; + //(void) rou_alert(0,"%s capile=<%s>",OPEP,soc->carpile); + if (soc->carin>=(soc->maxcarin)-1) { + //Overload! trying to overcome by extending carpile an adding an EOL + soc->maxcarin=soc->carin+5; + soc->carpile=(char *)realloc(soc->carpile,(soc->maxcarin)*sizeof(char)); + (void) strcat(soc->carpile,soc->EOL); + } + break; + case 2 : //Do we have a CRLF + eol=strstr(soc->carpile,soc->EOL); + if (eol==(char *)0) + phase=999; //No End Of Line yet + break; + case 3 : //duplicating carpile + *lineptr=calloc(soc->carin+1,sizeof(char)); + *eol='\000'; + (void) strcpy(*lineptr,soc->carpile); + got=strlen(*lineptr); + break; + case 4 : //managing carpile + soc->carin-=(got+strlen(soc->EOL)); + if (soc->carin<0) + soc->carin=0; + if (soc->carin>0) { + int delta; + + delta=got+strlen(soc->EOL); + (void) memmove(soc->carpile,soc->carpile+delta,soc->carin+1); + } + //soc->carpile[soc->carin]='\000'; + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return got; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to wait and get a new handle */ +/* */ +/********************************************************/ +static SOCTYP *waitincoming(SOCTYP *soc) + +{ +#define OPEP "devsoc.c:waitincoming" + +SOCTYP *newsoc; +_Bool ready; +int phase; +_Bool proceed; + +newsoc=(SOCTYP *)0; +ready=false; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //First prepare a new socket + newsoc=dupsocket(soc); + if (openplain(newsoc)==false) + //received a termination signal + phase=999; //return a null socket + break; + case 1 : //wait for incoming connexion + switch (newsoc->proto) { + case pro_smtp : //plain socket + case pro_starttls : //plain socket + STARTTLS + //nothing to do + break; + case pro_smtps : //set secure socket + newsoc->modtls=true; + newsoc->tls=tls_opentls(newsoc->handle,true); + if (newsoc->tls==(TLSTYP *)0) { + (void) rou_alert(0,"%s Unable to get a TLS channel",OPEP); + newsoc->modtls=false; + phase=999; //trouble trouble + } + break; + default : + (void) rou_alert(0,"%s Protocol '%d' unset (Bug?)", + OPEP,(int)(newsoc->proto)); + break; + } + break; + case 2 : //Everything is fine + (void) usleep(10000); //make sure link is properly set + ready=true; + break; + default : //SAFE guard + if (ready==false) + newsoc=soc_release(newsoc); //trouble touble + proceed=false; + break; + } + phase++; + } +return newsoc; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to bind a socket to a specific */ +/* address and return the linked handle */ +/* */ +/********************************************************/ +static int bindhandle(struct addrinfo *ai,SOCTYP *soc) + +{ +#define OPEP "devsoc.c:bindhandle," +#define BFSZ 30 //working buffer size + +int handle; +struct linger slg; +int reuse; +int phase; +_Bool proceed; + +handle=-1; +slg.l_onoff=true; +slg.l_linger=2; //2 sec max timeout on shutdown +reuse=1; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //lets get a socket + if ((handle=socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol))<0) { + (void) rou_alert(0,"%s Unable to open socket for <%s> (error='%s')", + OPEP,ai->ai_canonname,strerror(errno)); + phase=999; //trouble trouble + } + break; + case 1 : //setting socket option (address) + if (setsockopt(handle,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0) { + (void) rou_alert(0,"%s Unable to get socket option " + "SO_REUSEADDR for <%s> (error='%s')", + OPEP,ai->ai_canonname,strerror(errno)); + phase=999; //trouble cleanup phase + } + break; + case 2 : //setting socket option (port) + if (setsockopt(handle,SOL_SOCKET,SO_REUSEPORT,&reuse,sizeof(reuse))<0) { + (void) rou_alert(0,"%s Unable to get socket option " + "SO_REUSEPORT for <%s> (error='%s')", + OPEP,ai->ai_canonname,strerror(errno)); + phase=999; //trouble cleanup phase + } + break; + case 3 : //SO_LINGER allow Connection reset by peer + if (setsockopt(handle,SOL_SOCKET,SO_LINGER,&slg,sizeof(slg))<0) { + (void) rou_alert(0,"%s Unable to set socket option " + "SO_LINGER for <%s> (error='%s')", + OPEP,strerror(errno)); + phase=999; //trouble cleanup phase + } + break; + case 4 : //getting socket option + if (bind(handle,ai->ai_addr,ai->ai_addrlen)<0) { + (void) rou_alert(0,"%s Unable to bind on IP/port <%s/%s> (error='%s')", + OPEP,ai->ai_canonname,soc->port,strerror(errno)); + phase=999; //trouble cleanup phase + } + break; + case 5 : //everythin is fine no need to go further + proceed=false; + break; + default : //SAFE Guard (in case of trouble) + if (handle>=0) + close(handle); + handle=-1; //trouble trouble + proceed=false; + break; + } + phase++; + } +return handle; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to parse an email protocol */ +/* */ +/********************************************************/ +PUBLIC PROTYP soc_getprotocol(const char *strproto) + +{ +static struct { + PROTYP proto; + const char *voca; + }prolist[]={ + {pro_smtp,""}, + {pro_smtp,"smtp"}, + {pro_smtps,"smtps"}, + {pro_unknwn,(char *)0} + }; +PROTYP proto; + + +proto=pro_unknwn; +for (int i=0;prolist[i].voca!=(char *)0;i++) { + if (strcasecmp(strproto,prolist[i].voca)==0) { + proto=prolist[i].proto; + break; + } + } +return proto; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to free memory used by a bind */ +/* definition. */ +/* */ +/********************************************************/ +PUBLIC SOCPTR **soc_freebindinf(SOCPTR **socptr) + +{ +if (socptr!=(SOCPTR **)0) { + register SOCTYP **socs; + int i; + + socs=(SOCTYP **)socptr; + for (i=0;socs[i]!=(SOCTYP *)0;i++) { + socs[i]=freesocket(socs[i]); + } + (void) free(socs); + socptr=(SOCPTR **)0; + } +return socptr; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to set memory used by a bin */ +/* definition. */ +/* */ +/********************************************************/ +PUBLIC SOCPTR **soc_mkbindinf(SOCPTR **socptr,PROTYP proto, + const char *ip,const char *port,int iteration) + +{ +SOCTYP *soc; + +soc=newsocket(); +soc->proto=proto; +soc->ip=strdup(ip); +soc->port=strdup(port); +soc->iteration=iteration; +socptr=(SOCPTR **)rou_addlist((void **)socptr,(void *)soc); +return socptr; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to open a channel with a remote smtp */ +/* server. Return a socptr if successful. */ +/* */ +/********************************************************/ +PUBLIC SOCPTR *soc_openfeedsock(PROTYP proto,const char *srcip,const char *ip,const char *port) + +{ +#define OPEP "devsoc.c:soc_openfeedsoc," +#define WAITCNT 10 + +SOCTYP *soc; +int swait; +int status; +int handle; +int flags; +fd_set rset; +fd_set wset; +struct timeval timeout; +struct addrinfo hints; +struct addrinfo *ai; +int phase; +_Bool proceed; + +soc=(SOCTYP *)0; +swait=WAITCNT; +status=0; +handle=0; +flags=0; +FD_ZERO(&rset); +FD_ZERO(&wset); +timeout.tv_usec=0;; +timeout.tv_sec=swait; +(void) memset(&hints,'\000',sizeof(hints)); +hints.ai_family=PF_UNSPEC; +hints.ai_flags=HINTFLG; +hints.ai_socktype=SOCK_STREAM; +//ai=(struct addrinfo *)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 parameters + if ((ip==(const char *)0)||(port==(const char *)0)) { + (void) rou_alert(0,"%s, ip (%s) or port (%s) missing (config?)", + OPEP,ip,port); + phase=999; //no need to go further + } + break; + case 1 : //is address a good one + if ((status=getaddrinfo(ip,port,&hints,&ai))!=0) { + (void) rou_alert(0,"%s, Unable to find a address about " + "IP:port '%s:%s' (error='%s')", + OPEP,ip,port,gai_strerror(status)); + phase=999; //no need to go further + } + break; + case 2 : //lets create socket + if ((handle=socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol))<0) { + (void) rou_alert(0,"%s Unable to open socket for <%s> (error='%s')", + OPEP,ai->ai_canonname,strerror(errno)); + phase=999; //no need to go further + } + break; + case 3 : //Need to bind from a specific source address + if ((srcip!=(const char *)0)&&(strlen(srcip)>0)) { + struct sockaddr_in server_addr; + + (void) memset(&server_addr,'\000',sizeof(server_addr)); + server_addr.sin_family=AF_INET; + inet_pton(AF_INET,srcip, &(server_addr.sin_addr)); + if (bind(handle,(struct sockaddr*)&server_addr,sizeof(server_addr))<0) { + (void) rou_alert(0,"%s Unable to bind on <%s> error=<%s>", + OPEP,srcip,strerror(errno)); + (void) close(handle); + phase=999; + } + } + break; + case 4 : //getting the socket status + if ((flags=fcntl(handle,F_GETFL,0))<0) { + (void) rou_core_dump("%s, Unable to get socket descripteur on " + "IP/PORT <%s/%s> (Bug? error=<%s>)", + OPEP,soc->ip,soc->port,strerror(errno)); + phase=999; //never reached + } + break; + case 5 : //setting newhandle working mode + if ((flags=fcntl(handle,F_SETFL,flags|O_NONBLOCK|O_ASYNC))<0) { + (void) rou_core_dump("%s, Unable to set socket descripteur on " + "IP/PORT <%s/%s> (Bug? error=<%s>)", + OPEP,soc->ip,soc->port,strerror(errno)); + phase=999; //never reached + } + break; + case 6 : //connecting to remote + FD_SET(handle,&rset); /*FD ready for select */ + wset=rset; + if (connect(handle,ai->ai_addr,ai->ai_addrlen)<0) { + switch (errno) { + case EINPROGRESS : //its acceptable + break; + default : + (void) rou_alert(1,"%s unable to make connection with '%s.%s' " + "(error=<%s>)", + OPEP,ip,port,strerror(errno)); + (void) close(handle); + phase=999; + break; + } + } + break; + case 7 : //Wait link established + switch (select(handle+1,&rset,&wset,(fd_set *)0,&timeout)) { + case -1 : + (void) rou_alert(1,"%s Unable to establish connection with '%s.%s' " + "(error=<%s>)", + OPEP,ip,port,strerror(errno)); + (void) close(handle); + phase=999; + break; + case 0 : + (void) rou_alert(1,"%s Unable to establish connection with <%s> " + "within %d sec",OPEP,ip,swait); + (void) close(handle); + phase=999; + break; + default : //Link established + break; + } + break; + case 8 : //checking socket status + if ((status=checksockstat(handle))!=0) { + (void) rou_alert(0,"%s Unable to establish socklink with <%s:%s> (error=<%s>)", + OPEP,ip,port,strerror(status)); + (void) close(handle); + phase=999; + } + break; + case 9 : //socket is now ready + soc=newsocket(); + soc->proto=proto; + soc->connected=true; + soc->handle=handle; + soc->ip=strdup(ip); + soc->port=strdup(port); + soc->iteration=1; + break; + default : //SAFE Guard + if (ai!=(struct addrinfo *)0) + (void) freeaddrinfo(ai); + proceed=false; + break; + } + phase++; + } +return (SOCPTR *)soc; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to close an exchange socket sonnected */ +/* server. Return a so remote smtp server. */ +/* */ +/********************************************************/ +PUBLIC SOCPTR *soc_closefeedsock(SOCPTR *socptr) + +{ +#define OPEP "devsoc.c:soc_closefeedsoc" + +SOCTYP *soc; +int phase; +_Bool proceed; + +soc=(SOCTYP *)socptr; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Do we have an opened socket + if (soc==(SOCTYP *)0) { + (void) rou_alert(0,"%s, Aborting, socket is null (bug?)",OPEP); + phase=999; //no need to go further + } + break; + case 1 : //clsing cryptying if needed + if (soc->tls!=(TLSTYP *)0) + soc->tls=tls_closetls(soc->tls); + break; + case 2 : //is the sockect detected closed + if (soc->handle<0) + phase=999; //Socket allready closed + break; + case 3 : //let close the socket + if (close(soc->handle)<0) + (void) rou_alert(0,"%s, error on closing socket '%s.%s' (error=<%s>)", + OPEP,soc->ip,soc->port,strerror(errno)); + break; + default : //SAFE Guard + socptr=freesocket(socptr); + proceed=false; + break; + } + phase++; + } +return socptr; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return the number of iterations */ +/* within socket definition. */ +/* */ +/********************************************************/ +PUBLIC int soc_getiterations(SOCPTR *socptr) + +{ +int iterations; +SOCTYP *soc; + +soc=(SOCTYP *)socptr; +iterations=0; +if (soc!=(SOCTYP *)0) + iterations=soc->iteration; +return iterations; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to bind to one socket and return the */ +/* socket handle */ +/* */ +/********************************************************/ +PUBLIC _Bool soc_openbinding(SOCPTR *socptr) + +{ +#define OPEP "devsoc.c:soc_openbinding" + +_Bool done; +SOCTYP *soc; +uid_t gid; //ccurrent group id +uid_t uid; //ccurrent user id +struct addrinfo hints; +struct addrinfo *tobind; +int phase; +_Bool proceed; + +done=false; +soc=(SOCTYP *)socptr; +(void) memset(&hints,'\000',sizeof(hints)); +hints.ai_family=PF_UNSPEC; +hints.ai_flags=HINTFLG; +hints.ai_socktype=SOCK_STREAM; +tobind=(struct addrinfo *)0; +gid=getegid(); //let be back to root if needed +uid=geteuid(); //to open device on < 1024 port +if (setegid(getgid())<0) + (void) rou_core_dump("%s Unable to set the Egid to '%d' (error=<%s>", + OPEP,getgid(),strerror(errno)); +if (seteuid(getuid())<0) + (void) rou_core_dump("%s Unable to set the Euid to '%d' (error=<%s>", + OPEP,getuid(),strerror(errno)); +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //sanity check + if (soc==(SOCTYP *)0) { + (void) rou_alert(0,"%s, socket binding reference is NULL (Bug!?)",OPEP); + phase=999; //no need to go further + } + break; + case 1 : //check if time to retry binding + if ((soc->lasttry+5)>time((time_t)0)) { + phase=999; //no need to go further + } + break; + case 2 : //to have the right address infp + int status; + + soc->lasttry=time((time_t *)0); + if ((status=getaddrinfo(soc->ip,soc->port,&hints,&tobind))!=0) { + (void) rou_alert(0,"%s, Unable to find a address about " + "IP:port '%s:%s' (error='%s')", + OPEP,soc->ip,soc->port,gai_strerror(status)); + phase=999; //no need to go further + } + break; + case 3 : //binding socket + if ((soc->handle=bindhandle(tobind,soc))<0) + phase=999; //no need to go further + (void) freeaddrinfo(tobind); + break; + case 4 : //listening on socket + (void) prc_settitle("%s:%s, monitoring %02d contacts on %s:%s", + APPNAME,appname,soc->iteration,soc->ip,soc->port); + if (listen(soc->handle,soc->iteration+4)<0) { + (void) rou_alert(0,"%s, Unable to listen at address " + "IP:port '%s:%s' (error='%s')", + soc->ip,soc->port,strerror(errno)); + (void) close(soc->handle); + soc->handle=-1; + phase=999; //no need to go further + } + break; + case 5 : //listening on socket + done=true; + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +(void) setegid(gid); //recover the standard application +(void) seteuid(uid); //uid:gid +return done; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to unbind from one socket. */ +/* */ +/********************************************************/ +PUBLIC void soc_closebinding(SOCPTR *socptr) + +{ +#define OPEP "devsoc.c:soc_closebinding" + +SOCTYP *soc; +int phase; +_Bool proceed; + +soc=(SOCTYP *)socptr; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //sanity check + if (soc==(SOCTYP *)0) { + (void) rou_alert(0,"%s binding pointer is NULL (Bug!?)",OPEP); + phase=999; //not going further + } + break; + case 1 : //check if socket already close + if (soc->handle<0) { + phase=999; //yes, no need to go further + } + break; + case 2 : //closing the the socket + if (close(soc->handle)<0) + (void) rou_alert(0,"%s Unable to close socket (Bug!?, error=<%s>)", + OPEP,strerror(errno)); + soc->handle=-1; + break; + default : //SAFE Guard + soc->lasttry=(time_t)0; + proceed=false; + break; + } + phase++; + } +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to wait for incoming character on */ +/* socket, waiting up to attend second. */ +/* */ +/********************************************************/ +PUBLIC int soc_waitforchar(SOCPTR *socptr,u_int millisec) + +{ +#define OPEP "devsoc.c:soc_waitforchar" +register int status; +sigset_t origmask; +SOCTYP *soc; + +status=-2; +soc=(SOCTYP *)socptr; +if ((soc!=(SOCTYP *)0)&&(isconnected(soc)==true)) { + switch (soc->modtls) { + case true : + status=tls_waitforchar(soc->tls,millisec); + break; + case false : { + struct pollfd polling[1]; + + polling[0].events=POLLIN|POLLPRI|POLLHUP; + polling[0].revents=(short)0; + polling[0].fd=soc->handle; + (void) sigprocmask(SIG_SETMASK,(sigset_t *)0,&origmask); + status=poll(polling,1,millisec); + (void) sigprocmask(SIG_SETMASK,&origmask,(sigset_t *)0); + } + break; + } + switch (status) { + case -1 : //polling error + (void) rou_alert(0,"%s Polling error (error=<%s>)",OPEP,strerror(errno)); + break; + case 0 : //polling timeout + (void) rou_alert(0,"%s Polling timeout (error=<%s>)",OPEP,strerror(errno)); + break; + case 1 : //polling early return (data or event) + //checking if link still available + if (tls_write(soc->tls,(char *)0,0)<0) { + (void) rou_alert(0,"%s, TLS link disconnect detected",OPEP); + status=0; + } + break; + default : + (void) rou_alert(0,"%s Polling default (error=<%s>)",OPEP,strerror(errno)); + break; + } + } +return status; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return the next available line */ +/* within the socket carpile. */ +/* return the number of char within line */ +/* Return 0 if line is 'empty' */ +/* Return -1 if no characater available */ +/* */ +/********************************************************/ +PUBLIC int soc_getnextline(SOCPTR *socptr,char **lineptr) + +{ +#define OPEP "devsoc.c:soc_getnextline" + +int got; +register SOCTYP *soc; +int phase; +_Bool proceed; + +*lineptr=(char *)0; +got=-1; +soc=(SOCTYP *)socptr; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //Do we have dat in carpile + if (soc==(SOCTYP *)0) { + (void) rou_alert(0,"%s, socket binding reference is NULL (Bug!?)",OPEP); + phase=999; //no need to go further + } + break; + case 1 : //Do we have char available in carpile + got=doextract(soc,lineptr); + if (got>=0) //we have line + phase=999; //no need to go further + break; + case 2 : //lets wait for char + if (soc_receive(socptr)>0) //we have char + phase=0; //Let try to read line + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return got; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to send data to a tcp socket. */ +/* return the number of character transmitted, is */ +/* unable to send char return -1; */ +/* */ +/********************************************************/ +PUBLIC int soc_writebuffer(SOCPTR *socptr,char *buffer,int tosend) + +{ +#define OPEP "devsoc.c:soc_writebuffer" + +int sent; +SOCTYP *soc; + +sent=-1; +soc=(SOCTYP *)socptr; +if (soc!=(SOCTYP *)0) { + switch (soc->modtls) { + case true : + sent=tls_write(soc->tls,buffer,tosend); + break; + case false : + sent=send(soc->handle,buffer,tosend,0); + break; + } + if (sent<0) { + switch (errno) { + case EPIPE : + (void) rou_alert(0,"%s broken pipe",OPEP); + break; + default : + (void) rou_alert(0,"%s Unable to send data, error=%d <%s> (Bug)", + OPEP,errno,strerror(errno)); + break; + } + } + } +return sent; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to read incoming character from the */ +/* socket. */ +/* Return -1 if trouble. */ +/* the number of char read otherwise */ +/* */ +/********************************************************/ +PUBLIC int soc_receive(SOCPTR *socptr) + +{ +#define OPEP "devsoc.c:soc_receive" + +int got; +SOCTYP *soc; +int limit; +char *buffer; +int phase; +_Bool proceed; + +got=0; +soc=(SOCTYP *)socptr; +limit=0; +buffer=(char *)0; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG %s phase='%d' carpile=<%s>",OPEP,phase,soc->carpile); + switch (phase) { + case 0 : //is socket available + if (soc==(SOCTYP *)0) { + (void) rou_alert(0,"%s socket pointer is null (Bug?)",OPEP); + phase=999; //No need to go further + } + break; + case 1 : //Is the socket conneted + if (soc->connected==false) { + (void) rou_alert(0,"%s socket Already disconnect",OPEP); + phase=999; //No need to go further + } + break; + case 2 : //reading data + buffer=soc->carpile+soc->carin; + limit=(soc->maxcarin-soc->carin); + //(void) rou_alert(0,"%s JMPDBG limit='%d' maxcarin='%d' carin='%d'", + // OPEP,limit,soc->maxcarin,soc->carin); + (void) memset(buffer,'\000',limit); + limit--; + errno=0; + switch (soc->modtls) { + case true : + got=tls_read(soc->tls,buffer,limit); + break; + case false : + got=recv(soc->handle,buffer,limit,MSG_DONTWAIT); + break; + } + break; + case 3 : //check about recieved data + switch (got) { + case -1 : //do not block + if (errno==EWOULDBLOCK) + errno=EAGAIN; + switch (errno) { + case ITSOK : //SSL report (wrong) error? + case EAGAIN : //no char available yet + got=0; //lets report "no char" + break; + case ECONNRESET : //Connection reset by peer + (void) rou_alert(0,"%s connection reset by peer",OPEP); + break; + default : + (void) rou_alert(0,"%s Unexpected error=%d <%s> (Bug)", + OPEP,errno,strerror(errno)); + break; + } + break; + case 0 : //No char available? + //wait for timeout detection + break; + default : //we got some char from remote + for (int i=0;icarin+=got; //managing carpile + soc->carpile[soc->carin]='\000'; + break; + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return got; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to wait an accept a connexion comming */ +/* from a remote client. */ +/* return a new socket. */ +/* */ +/********************************************************/ +PUBLIC SOCPTR *soc_accept(SOCPTR *socptr,int pos) + +{ +#define OPEP "devsoc.c:soc_accept" + +SOCTYP *newsoc; +SOCTYP *soc; +int phase; +_Bool proceed; + +newsoc=(SOCTYP *)0; +soc=(SOCTYP *)socptr; +phase=0; +proceed=true; +while (proceed==true) { + (void) rou_dbglive(9,OPEP,"phase='%d'",phase); + switch (phase) { + case 0 : //checking if soc is available + if (soc==(SOCTYP *)0) { + (void) rou_core_dump("%s, socket descripteur missing (Bug?)",OPEP); + phase=999; //never reached + } + break; + case 1 : //display ready on process status; + (void) prc_settitle("%s:%s, waiting (%02d/%02d) on [%s:%s]", + APPNAME,appname,pos,soc->iteration,soc->ip,soc->port); + break; + case 2 : //waiting for new connection + if ((newsoc=waitincoming(soc))==(SOCPTR *)0) { + (void) rou_alert(4,"%s, Contact from Remote not successful",OPEP); + phase=999; //no need to go further + } + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return (SOCPTR *)newsoc; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return the address, name or port */ +/* for local or remote socket. */ +/* */ +/********************************************************/ +PUBLIC char *soc_getaddrinfo(SOCPTR *socptr,_Bool local,_Bool getname) + +{ +#define OPEP "devsoc.c:soc_getaddrinfo" + +char *data; +SOCTYP *soc; +int mode; + +data=(char *)0; +soc=(SOCTYP *)socptr; +mode=NI_NUMERICSERV; +switch (getname) { + case true : + mode|=NI_NAMEREQD; + break; + case false : + mode|=NI_NUMERICHOST; + break; + } +if (soc!=(SOCTYP *)0) { + int status; + struct sockaddr connip; + socklen_t taille; + char host[NI_MAXHOST]; + char serv[NI_MAXSERV]; + + (void) strcpy(host,"Unknown IP"); + (void) strcpy(serv,"Unknown service"); + taille=(socklen_t)(sizeof(connip)); + if (local==true) + status=getsockname(soc->handle,&connip,&taille); + else + status=getpeername(soc->handle,&connip,&taille); + switch (status) { + case -1 : //trouble to read socket data + switch(errno) { + case ENOTCONN : //other side just vanished + (void) rou_alert(0,"%s, Remote side vanished (local=%d, error=<%s>)", + OPEP,local,strerror(errno)); + break; + default : + (void) rou_alert(0,"%s, Unable to socket data (local=%d, error=<%s>)", + OPEP,local,strerror(errno)); + break; + } + break; + case 0 : //NO trouble to read socket data + status=getnameinfo(&connip,taille,host,sizeof(host),serv,sizeof(serv),mode); + switch (status) { + case 0 : //everything fine + break; + case EAI_AGAIN : + case EAI_NONAME : + if (getname==true) + (void) strcpy(host,NORVERS); //NO reverse name + default : + (void) rou_alert(0,"%s, Unable to get name (local=%d, error=<%s>)", + OPEP,local,strerror(errno)); + break; + } + break; + default : //Unexpected touble to read socket + (void) rou_alert(0,"%s, status=%d Unexpected (local=%d, error=<%s>) (Bug?)", + OPEP,status,local,strerror(errno)); + break; + } + switch (local) { + case true : + switch (getname) { + case true : + data=strdup(host); + break; + case false : + char local[NI_MAXHOST+NI_MAXSERV+1]; + + (void) snprintf(local,sizeof(local),"%s|%s",host,serv); + data=strdup(local); + break; + } + break; + case false : + data=strdup(host); + break; + } + } +return data; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to close and release exchange socket */ +/* */ +/********************************************************/ +PUBLIC SOCPTR *soc_release(SOCPTR *socptr) + +{ +#define OPEP "devsoc.c:soc_release" + +SOCTYP *soc; +int phase; +_Bool proceed; + +soc=(SOCTYP *)socptr; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //checking if soc is available + if (soc==(SOCTYP *)0) { + (void) rou_core_dump("%s, socket descripteur missing (Bug?)",OPEP); + phase=999; //never reached + } + break; + case 1 : //shutting down the TCP link + switch (soc->proto) { + case pro_smtp : //plain socket + (void) closeplain(soc); + break; + case pro_starttls : //plain socket + STARTTLS + if (soc->modtls==true) { + soc->tls=tls_closetls(soc->tls); + soc->modtls=false; + } + break; + case pro_smtps : //set secure socket + if (soc->modtls==true) { + soc->tls=tls_closetls(soc->tls); + soc->modtls=false; + } + break; + default : + (void) rou_alert(0,"%s Protocol '%d' unset (Bug?)", + OPEP,(int)(soc->proto)); + break; + } + break; + case 2 : //closing connexion + break; + case 3 : //fee memory used by socket + soc=freesocket(soc); + socptr=(SOCPTR *)soc; + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return socptr; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to purge incoming TLS channel */ +/* After crypted link is established but before */ +/* to use it. */ +/* */ +/* See VE-2011-0411, "plaintext command injection" */ +/* */ +/********************************************************/ +PUBLIC void soc_purge(SOCPTR *socptr,const char *peerip) + +{ +#define OPEP "devsoc.c:soc_purge," + +int max; +int count; + +max=1000; //purging for 1 seconde max; +count=0; +if (socptr!=(SOCPTR *)0) { + SOCTYP *soc; + + soc=(SOCTYP *)socptr; + for (;countcarin=0; + soc->carpile[0]='\000'; + (void) usleep(1000); //1 millisec + (void) soc_receive(soc); + if (soc->carin==0) //got no character + break; + } + } +if (count>=max) //one second max! + (void) rou_alert(0,"%s purge is too long with peer [%s]",OPEP,peerip); + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to switch a plain socket channel to */ +/* crypted channel, return true is successful. */ +/* */ +/********************************************************/ +PUBLIC _Bool soc_starttls(SOCPTR *socptr,_Bool server) + +{ +#define OPEP "devsoc.c:soc_starttls," + +_Bool ok; +SOCTYP *soc; + +ok=false; +soc=(SOCTYP *)socptr; +if ((soc!=(SOCTYP *)0)&&(soc->modtls==false)) { + switch (server) { + case true : //Nothing to do? + break; + case false : //Nothing to do? + break; + } + soc->tls=tls_opentls(soc->handle,server); + if (soc->tls!=(TLSTYP *)0) { + soc->proto=pro_smtps; + soc->modtls=true; + ok=true; + (void) tls_verify(soc->tls); + soc->cipherid=tls_getcipherid(soc->tls); + } + } +return ok; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return the security level used by */ +/* a crypted channel. */ +/* */ +/********************************************************/ +PUBLIC int soc_get_sec_level(SOCPTR *socptr) + +{ +int level; + +level=-1; +if (socptr!=(SOCPTR *)0) { + register SOCTYP *soc; + + soc=(SOCTYP *)socptr; + level=tls_get_sec_level(soc->tls); + } +return level; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return true if sthe socket is */ +/* in crypted mode. */ +/* */ +/********************************************************/ +PUBLIC _Bool soc_iscrypted(SOCPTR *socptr) + +{ +_Bool iscrypted; + +iscrypted=false; +if (socptr!=(SOCPTR *)0) + iscrypted=((SOCTYP *)socptr)->modtls; +return iscrypted; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return all cipher information */ +/* */ +/********************************************************/ +PUBLIC char *soc_getcipherid(SOCPTR *socptr) + +{ +char *cipherid; +SOCTYP *soc; + +cipherid=(char *)0; +soc=(SOCTYP *)socptr; +if (soc!=(SOCTYP *)0) + cipherid=tls_getcipherid(soc->tls); +return cipherid; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to get the cipher name used in cypted */ +/* mode. */ +/* */ +/********************************************************/ +PUBLIC const char *soc_get_cipher_name(SOCPTR *socptr) + +{ +const char *cipher; +SOCTYP *soc; + +cipher="Unknown"; +soc=(SOCTYP *)socptr; +if (soc!=(SOCTYP *)0) { + const char *ptr; + + if ((ptr=SSL_get_cipher_name(soc->tls->ssl))!=(const char *)0) + cipher=ptr; + } +return cipher; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return the socket mode as a string */ +/* */ +/********************************************************/ +PUBLIC const char *soc_getstrmode(SOCPTR *socptr) + +{ +const char *mode; +SOCTYP *soc; + +mode="Unknown"; +soc=(SOCTYP *)socptr; +if (soc!=(SOCTYP *)0) { + mode="cleartext"; + if (soc->modtls==true) + mode="crypted"; + } +return mode; +} diff --git a/lib/devsoc.d b/lib/devsoc.d new file mode 100644 index 0000000..bd80a98 --- /dev/null +++ b/lib/devsoc.d @@ -0,0 +1,120 @@ +devsoc.o devsoc.d : devsoc.c /usr/include/stdc-predef.h /usr/include/arpa/inet.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/netinet/in.h /usr/include/bits/stdint-uintn.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/sys/socket.h \ + /usr/include/bits/types/struct_iovec.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/socket.h /usr/include/sys/types.h \ + /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/time_t.h /usr/include/bits/types/timer_t.h \ + /usr/include/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/endianness.h \ + /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/bits/socket_type.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm-generic/socket.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h /usr/include/asm/posix_types.h \ + /usr/include/asm/posix_types_64.h /usr/include/asm-generic/posix_types.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/bits/in.h \ + /usr/include/errno.h /usr/include/bits/errno.h \ + /usr/include/linux/errno.h /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/fcntl.h /usr/include/bits/fcntl.h \ + /usr/include/bits/fcntl-linux.h /usr/include/bits/stat.h \ + /usr/include/bits/struct_stat.h /usr/include/netdb.h \ + /usr/include/rpc/netdb.h /usr/include/bits/netdb.h /usr/include/poll.h \ + /usr/include/sys/poll.h /usr/include/bits/poll.h /usr/include/stdio.h \ + /usr/include/bits/libc-header-start.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/stdlib.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/alloca.h /usr/include/bits/stdlib-float.h \ + /usr/include/signal.h /usr/include/bits/signum-generic.h \ + /usr/include/bits/signum-arch.h /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h /usr/include/bits/types/stack_t.h \ + /usr/include/sys/ucontext.h /usr/include/bits/sigstack.h \ + /usr/include/bits/sigstksz.h /usr/include/bits/ss_flags.h \ + /usr/include/bits/types/struct_sigstack.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h /usr/include/string.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/strings.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h subafn.h unidns.h unieml.h \ + uniprc.h unitls.h /usr/include/openssl/ssl.h \ + /usr/include/openssl/macros.h /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/configuration.h /usr/include/openssl/opensslv.h \ + /usr/include/openssl/e_os2.h /usr/include/inttypes.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdint.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/bits/stdint-least.h /usr/include/openssl/e_ostime.h \ + /usr/include/sys/time.h /usr/include/openssl/comp.h \ + /usr/include/openssl/crypto.h /usr/include/openssl/safestack.h \ + /usr/include/openssl/stack.h /usr/include/openssl/types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/limits.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h /usr/include/bits/posix2_lim.h \ + /usr/include/openssl/cryptoerr.h /usr/include/openssl/symhacks.h \ + /usr/include/openssl/cryptoerr_legacy.h /usr/include/openssl/core.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include-fixed/pthread.h \ + /usr/include/sched.h /usr/include/bits/sched.h \ + /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \ + /usr/include/bits/setjmp.h \ + /usr/include/bits/types/struct___jmp_buf_tag.h \ + /usr/include/openssl/comperr.h /usr/include/openssl/bio.h \ + /usr/include/openssl/bioerr.h /usr/include/openssl/x509.h \ + /usr/include/openssl/buffer.h /usr/include/openssl/buffererr.h \ + /usr/include/openssl/evp.h /usr/include/openssl/core_dispatch.h \ + /usr/include/openssl/indicator.h /usr/include/openssl/params.h \ + /usr/include/openssl/bn.h /usr/include/openssl/bnerr.h \ + /usr/include/openssl/evperr.h /usr/include/openssl/objects.h \ + /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \ + /usr/include/openssl/asn1err.h /usr/include/openssl/objectserr.h \ + /usr/include/openssl/ec.h /usr/include/openssl/ecerr.h \ + /usr/include/openssl/rsa.h /usr/include/openssl/rsaerr.h \ + /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \ + /usr/include/openssl/dherr.h /usr/include/openssl/dsaerr.h \ + /usr/include/openssl/sha.h /usr/include/openssl/x509err.h \ + /usr/include/openssl/x509_vfy.h /usr/include/openssl/lhash.h \ + /usr/include/openssl/pkcs7.h /usr/include/openssl/pkcs7err.h \ + /usr/include/openssl/http.h /usr/include/openssl/conf.h \ + /usr/include/openssl/conferr.h /usr/include/openssl/conftypes.h \ + /usr/include/openssl/pem.h /usr/include/openssl/pemerr.h \ + /usr/include/openssl/hmac.h /usr/include/openssl/async.h \ + /usr/include/openssl/asyncerr.h /usr/include/openssl/ct.h \ + /usr/include/openssl/cterr.h /usr/include/openssl/sslerr.h \ + /usr/include/openssl/sslerr_legacy.h /usr/include/openssl/prov_ssl.h \ + /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \ + /usr/include/openssl/tls1.h /usr/include/openssl/dtls1.h \ + /usr/include/openssl/srtp.h /usr/include/openssl/quic.h devsoc.h diff --git a/lib/devsoc.h b/lib/devsoc.h new file mode 100644 index 0000000..6f5e587 --- /dev/null +++ b/lib/devsoc.h @@ -0,0 +1,93 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Low level subroutine declaration */ +/* to handle tcp Socket. */ +/* */ +/********************************************************/ +#ifndef DEVSOC +#define DEVSOC + +#include +#include +#include + +#include "unitls.h" + +//convenient adress structure +typedef struct sockaddr SOCKADDR; + +//reference to a socket definition +typedef void SOCPTR; + +//procedure to parse an email protocol +extern PROTYP soc_getprotocol(const char *strproto); + +//procedure to free all memory used by a TCP socket +//definition (once closed) +extern SOCPTR **soc_freebindinf(SOCPTR **socptr); + +//procedure to assign memory to be used by a TCP socket +//definition +extern SOCPTR **soc_mkbindinf(SOCPTR **socptr,PROTYP proto, + const char *ip,const char *port,int iteration); + +//procedure to open one exchange socket +//to connect a remote smtp server +extern SOCPTR *soc_openfeedsock(PROTYP proto,const char *src,const char *ip,const char *port); + +//procedure to close an exchange socket connected to a remote smtp server +extern SOCPTR *soc_closefeedsock(SOCPTR *socptr); + +//procedure to return the number of channel to open on the soc +extern int soc_getiterations(SOCPTR *socptr); + +//procedure to open ONE socket and return handle to socket +extern _Bool soc_openbinding(SOCPTR *socptr); + +//procedure to close ONE socket +extern void soc_closebinding(SOCPTR *socptr); + +//procedure to wait for character from contact +extern int soc_waitforchar(SOCPTR *socptr,u_int millisec); + +//procedure to return a char array with the available line +extern int soc_getnextline(SOCPTR *socptr,char **lineptr); + +//procedure to send a buffer contens on channel +extern int soc_writebuffer(SOCPTR *socptr,char *buffer,int tosend); + +//procedure to receive up to limit char from socket +extern int soc_receive(SOCPTR *socptr); + +//procedure to wait and accept remote connexion +extern SOCPTR *soc_accept(SOCPTR *socptr,int pos); + +//procedure to get information about addrbane and port +extern char *soc_getaddrinfo(SOCPTR *socptr,_Bool local,_Bool getname); + +//procedure to release/clsoe socket +extern SOCPTR *soc_release(SOCPTR *socptr); + +//procedure to purge contact chenel (used in case of starttls) +extern void soc_purge(SOCPTR *socptr,const char *peerip); + +//procedure to initiate crypted mode on plain channel +extern _Bool soc_starttls(SOCPTR *socptr,_Bool server); + +//procedure to return the security level within a TLS link +extern int soc_get_sec_level(SOCPTR *socptr); + +//return flag true if socket is in crypted mode +extern _Bool soc_iscrypted(SOCPTR *socptr); + +//return the cipher mame used on the crypted link +extern const char *soc_get_cipher_name(SOCPTR *socptr); + +//return all cipher information +extern char *soc_getcipherid(SOCPTR *socptr); + +//return line socket mode (cleartext, crypted) +extern const char *soc_getstrmode(SOCPTR *socptr); + +#endif diff --git a/lib/devsql.c b/lib/devsql.c new file mode 100644 index 0000000..b1d823c --- /dev/null +++ b/lib/devsql.c @@ -0,0 +1,724 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Low level subroutine implementation */ +/* to handle SQL request */ +/* */ +/********************************************************/ +#include +#include +#include +#include + +#include "subrou.h" +#include "unimar.h" +#include "unipos.h" +#include "devsql.h" + +typedef void SQLRES; //Result from database + +typedef enum { + db_postgres, //Postgres database + db_maria, //Mariadb SQL + db_unknown + }SQLDBTYP; + +typedef struct { + SQLDBTYP sqldb; //database type + union { + POSPTR *psql; //postgreSQL reference/ + MARPTR *msql; //Mariadb|MySQL Reference + }db; + }SQLTYP; + + +//SQL database request +#define EMAILS "emails" //emails tables +#define SESSIONS "sessions" //session tables + +#ifdef GETFIELD +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to get the ASCII form of field located*/ +/* in a specific tuple + position in sqlresult. */ +/* */ +/********************************************************/ +static char *getfield(SQLTYP *sql,SQLRES *rs,int tuple,int position) + +{ +#define OPEP "devsql.c:getfield," + +char *value; + +value=(char *)0; +switch(sql->sqldb) { + case db_postgres : + value=pos_getfield((POSRES *)rs,tuple,position); + break; + case db_maria : + value=mar_getfield((MARRES *)rs,tuple,position); + break; + default : + (void) rou_alert(0,"%s Unexpected type='%d' (BUG!?)", + OPEP,(int)sql->sqldb); + break; + } +return value; +#undef OPEP +} +#endif +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to create an SQL pointer for proper */ +/* database type. */ +/* */ +/********************************************************/ +static SQLTYP *gettyp(const char *dbtype) + +{ +const char *db[]={"POSTGRESQL","MYSQL",(const char *)0}; + +SQLTYP *sql; + +sql=(SQLTYP *)0; +for (int i=0;db[i]!=(const char *)0;i++) { + if (strcmp(db[i],dbtype)==0) { + sql=(SQLTYP *)calloc(1,sizeof(SQLTYP)); + sql->sqldb=(SQLDBTYP)i; + break; //data base type found + } + } +return sql; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to make sure a string to be use to */ +/* access database is clean. */ +/* (no character to be misunderstood by database) */ +/* */ +/********************************************************/ +PUBLIC char *sql_gooddata(SQLPTR *sqlptr,char *key) + +{ +#define OPEP "devsql.c:sql_gooddata," + +char *gooddata; +char *sqlkey; +SQLTYP *sql; +int phase; +_Bool proceed; + +gooddata=(char *)0; +sqlkey=(char *)0; +sql=(SQLTYP *)sqlptr; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //do we have a string to encode + if ((key==(char *)0)||(strlen(key)==0)) { + gooddata=strdup("NULL"); //no, force a 'NULL' string. + phase=999; + } + break; + case 1 : //checking the key encoding + if ((sqlkey=sql_checkencoding(key))==(char *)0) { + (void) rou_alert(0,"%s dbkey <%s> encoding is wrong (config?)",OPEP,key); + gooddata=strdup("NULL"); //Let assum NULL + phase=999; //trouble trouble + } + break; + case 2 : //cleaning quote according daemon type + switch(sql->sqldb) { + case (db_postgres) : + gooddata=pos_cleanquote(sqlkey); + break; + case (db_maria) : + gooddata=mar_cleanquote(sqlkey); + break; + case (db_unknown) : + default : + (void) rou_alert(0,"%s Unknown SQL daemon (type='%d')",OPEP,sql->sqldb); + break; + } + sqlkey=rou_freestr(sqlkey); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return gooddata; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to return a dynamicaly allocated */ +/* char * with an SQL date computation sequence */ +/* */ +/********************************************************/ +PUBLIC char *sql_caldate(SQLPTR *sqlptr,char *expression,int second) + +{ +#define OPEP "devsql.c:sql_caldate," + +char *seq; + +seq=(char *)0; +if (sqlptr!=(SQLPTR *)0) { + SQLTYP *sql; + + sql=(SQLTYP *)sqlptr; + switch(sql->sqldb) { + case db_postgres : + seq=pos_caldate(expression,second); + break; + case db_maria : + seq=mar_caldate(expression,second); + break; + default : + (void) rou_alert(0,"%s Unexpected db type='%d' (BUG!?)", + OPEP,(int)sql->sqldb); + seq=strdup(""); + break; + } + } +return seq; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to establish a link with the */ +/* designated SQL server. */ +/* */ +/********************************************************/ +PUBLIC SQLPTR *sql_opensql() + +{ +#define OPEP "devsql.c:sql_opensql," + +static const char *dbenv[]={"DB_TYPE","DB_HOST","DB_PORT","DB_NAME"}; + +SQLTYP *sql; +const char *db[SQLENV]; +int phase; +_Bool proceed; + +sql=(SQLTYP *)0; +(void) memset(db,'\000',sizeof(db)); +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //get the preset sql env variable + for (int i=0;i<2;i++) { + switch (i) { + case 0 : //Postgresql + if (posenv[0]!=(char *)0) + (void) memcpy(db,posenv,sizeof(db)); + break; + case 1 : //MySQL/Mariadb + if (marenv[0]!=(char *)0) + (void) memcpy(db,marenv,sizeof(db)); + break; + default : //Trouble trouble + break; + } + } + break; + case 1 : //get database parameters + for (int i=0;i<(sizeof(dbenv)/sizeof(char *));i++) { + char *ptr; + + ptr=getenv(dbenv[i]); + if (ptr!=(char *)0) + db[i]=ptr; //Variable overwrite + } + break; + case 2 : //getting dbtype + if ((sql=gettyp(db[0]))==(SQLTYP *)0) { + (void) rou_alert(0,"%s %s type unknown (config?)",OPEP,dbenv[0]); + phase=999; //missing database information + } + break; + case 3 : //opening specific database + switch (sql->sqldb) { + case db_postgres : + sql->db.psql=pos_opensql(db[1],db[2],db[3]); + break; + case db_maria : + sql->db.msql=mar_opensql(db[1],db[2],db[3]); + break; + default : + (void) rou_alert(0,"%s Unexpected type='%d' (bug?)", + OPEP,(int)sql->sqldb); + break; + } + break; + case 4 : //checking if the database is properly open + _Bool isok; + + isok=false; + switch (sql->sqldb) { + case db_postgres: + isok=(sql->db.psql!=(POSPTR *)0); + break; + case db_maria : + isok=(sql->db.msql!=(MARPTR *)0); + break; + default : + break; + } + if (isok==false) { + (void) rou_alert(0,"%s data-base not properly connected (config?)",OPEP); + (void) free(sql); + sql=(SQLTYP *)0; + phase=999; //Trouble trouble + } + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return (SQLPTR *)sql; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to closed previously establish link */ +/* with the designated SQL server. */ +/* */ +/********************************************************/ +PUBLIC SQLPTR *sql_closesql(SQLPTR *sqlptr) + +{ +#define OPEP "devsql.c:sql_closesql," + +SQLTYP *sql; +int phase; +_Bool proceed; + +sql=(SQLPTR *)sqlptr; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //check if database available + if (sql==(SQLTYP *)0) { + (void) rou_alert(0,"%s %s Database pointer is NULL (bug?)",OPEP); + phase=999; + } + break; + case 1 : //opening specific database + switch (sql->sqldb) { + case db_postgres : + sql->db.psql=pos_closesql(sql->db.psql); + break; + case db_maria : + sql->db.msql=mar_closesql(sql->db.msql); + break; + default : + (void) rou_alert(0,"%s Unexpected type='%d' (bug?)", + OPEP,(int)sql->sqldb); + break; + } + break; + case 2 : //freeing memory used by SQL + (void) free(sql); + sql=(SQLTYP *)0; + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return (SQLPTR *)sql; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return a unix time in acsii */ +/* format (data-base compatible). */ +/* */ +/********************************************************/ +PUBLIC char *sql_fromunixtime(SQLPTR *sqlptr,time_t timestamp) + +{ +#define OPEP "devsql.c:sql_fromunixtime," + +const char *unixdate; + +unixdate=""; +if (sqlptr!=(SQLPTR *)0) { + SQLTYP *sql; + + sql=(SQLTYP *)sqlptr; + switch(sql->sqldb) { + case db_postgres : + unixdate=pos_fromunixtime(timestamp); + break; + case db_maria : + unixdate=mar_fromunixtime(timestamp); + break; + default : + (void) rou_alert(0,"%s Unexpected db type='%d' (BUG!?)", + OPEP,(int)sql->sqldb); + break; + } + } +return strdup(unixdate); + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return a unix time_t from an ASCII*/ +/* string (data-base compatible). */ +/* */ +/********************************************************/ +PUBLIC time_t sql_tounixtime(SQLPTR *sqlptr,const char *date) + +{ +#define OPEP "devsql.c:sql_tounixtime," + +time_t datetime; + +datetime=(time_t)0; +if (sqlptr!=(SQLPTR *)0) { + SQLTYP *sql; + + sql=(SQLTYP *)sqlptr; + switch(sql->sqldb) { + case db_postgres : + datetime=pos_tounixtime(date); + break; + case db_maria : + datetime=mar_tounixtime(date); + break; + default : + (void) rou_alert(0,"%s Unexpected db type='%d' (BUG!?)", + OPEP,(int)sql->sqldb); + break; + } + } +return datetime; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to get an exclusive access to a */ +/* specific database table. */ +/* */ +/********************************************************/ +PUBLIC _Bool sql_lock(SQLPTR *sqlptr,char *tablename) + +{ +#define OPEP "devsql.c:sql_lock," + +_Bool locked; + +locked=false; +if (sqlptr!=(SQLPTR *)0) { + SQLTYP *sql; + + sql=(SQLTYP *)sqlptr; + switch(sql->sqldb) { + case db_postgres : + locked=pos_lock(sql->db.psql,tablename); + break; + case db_maria : + locked=mar_lock(sql->db.psql,tablename); + break; + default : + (void) rou_alert(0,"%s Unexpected db type='%d' (BUG!?)", + OPEP,(int)sql->sqldb); + break; + } + } +return locked; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to release an exclusive access to a */ +/* specific database table. */ +/* */ +/********************************************************/ +PUBLIC _Bool sql_unlock(SQLPTR *sqlptr,_Bool commit) + +{ +#define OPEP "devsql.c:sql_unlock," + +_Bool unlocked; + +unlocked=false; +if (sqlptr!=(SQLPTR *)0) { + SQLTYP *sql; + + sql=(SQLTYP *)sqlptr; + switch(sql->sqldb) { + case db_postgres : + unlocked=pos_unlock(sql->db.psql,commit); + break; + case db_maria : + unlocked=mar_unlock(sql->db.psql,commit); + break; + default : + (void) rou_alert(0,"%s Unexpected db type='%d' (BUG!?)", + OPEP,(int)sql->sqldb); + break; + } + } +return unlocked; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to do some action to change database */ +/* contents. */ +/* */ +/********************************************************/ +PUBLIC int sql_request(SQLPTR *sqlptr,const char *fmt,...) + +{ +#define OPEP "devsql.c:sql_request," + +int number; +SQLTYP *sql; +va_list args; +char *cmd; + +number=-1; +sql=(SQLTYP *)sqlptr; +va_start(args,fmt); +if ((rou_vasprintf(&cmd,fmt,args))>0) { + (void) rou_alert(0,"JMPDBG SQL cmd=<%s>",cmd); + switch(sql->sqldb) { + case db_postgres : + number=pos_request(sql->db.psql,cmd); + break; + case db_maria : + number=mar_request(sql->db.msql,cmd); + break; + default : + (void) rou_alert(0,"%s Unexpected type='%d' (BUG!?)", + OPEP,(int)sql->sqldb); + break; + } + (void) free(cmd); + } +va_end(args); +return number; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to get the ASCII form of field located*/ +/* in a specific tuple + name in sqlresult. */ +/* */ +/********************************************************/ +PUBLIC const char *sql_getvalue(SQLPTR *sqlptr,SQLRES *rs,int row,const char *name) + +{ +#define OPEP "devsql.c:sql_getvalue," + +const char *value; +SQLTYP *sql; + +value=(const char *)0; +sql=(SQLTYP *)sqlptr; +switch(sql->sqldb) { + case db_postgres : + value=pos_getvalue((POSRES *)rs,row,name); + break; + case db_maria : + value=mar_getvalue((MARRES *)rs,row,name); + break; + default : + (void) rou_alert(0,"%s Unexpected type='%d' (BUG!?)", + OPEP,(int)sql->sqldb); + break; + } +return value; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to create a data search request and */ +/* submit it to the to the proper database daemon. */ +/* */ +/********************************************************/ +PUBLIC SQLRES *sql_gettupple(SQLPTR *sqlptr,const char *fmt,...) + +{ +#define OPEP "devsql.c:sql_gettupple," + +SQLRES *rs; + +rs=(SQLRES *)0; +if (sqlptr!=(SQLPTR *)0) { + SQLTYP *sql; + va_list args; + char *cmd; + + sql=(SQLTYP *)sqlptr; + va_start(args,fmt); + if ((rou_vasprintf(&cmd,fmt,args))>0) { + switch(sql->sqldb) { + case db_postgres : + rs=(SQLRES *)pos_gettupple(sql->db.psql,cmd); + break; + case db_maria : + rs=(SQLRES *)mar_gettupple(sql->db.msql,cmd); + break; + default : + (void) rou_alert(0,"%s Unexpected type='%d' (BUG!?)", + OPEP,(int)sql->sqldb); + break; + } + (void) free(cmd); + } + va_end(args); + } +return rs; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to the number of tupple within a */ +/* result issued by a successfull command. */ +/* */ +/********************************************************/ +PUBLIC int sql_getnbrtupple(SQLPTR *sqlptr,SQLRES *rs) + +{ +#define OPEP "devsql.c:sql_getnbrtupple," + +int numrow; + +numrow=-1; +if (sqlptr!=(SQLPTR *)0) { + SQLTYP *sql; + + sql=(SQLTYP *)sqlptr; + switch(sql->sqldb) { + case db_postgres : + numrow=pos_nbrtupple((POSRES *)rs); + break; + case db_maria : + numrow=mar_nbrtupple((MARRES *)rs); + break; + default : + (void) rou_alert(0,"%s Unexpected db type='%d' (BUG!?)", + OPEP,(int)sql->sqldb); + numrow=0; + break; + } + } +return numrow; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to drop result issued by a successfull*/ +/* command. */ +/* */ +/********************************************************/ +PUBLIC SQLRES *sql_droptupple(SQLPTR *sqlptr,SQLRES *rs) + +{ +#define OPEP "devsql.c:sql_dropresult," + +if (rs!=(SQLRES *)0) { + SQLTYP *sql; + + sql=(SQLTYP *)sqlptr; + switch(sql->sqldb) { + case db_postgres : + rs=(SQLRES *)pos_dropresult((POSRES *)rs); + break; + case db_maria : + rs=(SQLRES *)pos_dropresult((MARRES *)rs); + break; + default : + (void) rou_alert(0,"%s Unexpected type='%d' (BUG!?)", + OPEP,(int)sql->sqldb); + rs=(SQLRES *)0; + break; + } + } +return rs; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to retrieve/store data from/to */ +/* database. */ +/* */ +/********************************************************/ +PUBLIC _Bool sql_mngdata(SQLPTR *sqlptr,FLDTYP *field,SQLENUM action) + +{ +(void) rou_alert(0,"JMPDBG sql_mngdata need to be implemented!"); +return false; +} diff --git a/lib/devsql.d b/lib/devsql.d new file mode 100644 index 0000000..bc0f189 --- /dev/null +++ b/lib/devsql.d @@ -0,0 +1,44 @@ +devsql.o devsql.d : devsql.c /usr/include/stdc-predef.h /usr/include/ctype.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/types/locale_t.h \ + /usr/include/bits/types/__locale_t.h /usr/include/stdio.h \ + /usr/include/bits/libc-header-start.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/stdlib.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/sys/types.h /usr/include/bits/types/clock_t.h \ + /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/byteswap.h \ + /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \ + /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/string.h \ + /usr/include/strings.h subrou.h /usr/include/linux/types.h \ + /usr/include/asm/types.h /usr/include/asm-generic/types.h \ + /usr/include/asm-generic/int-ll64.h /usr/include/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h /usr/include/asm/posix_types.h \ + /usr/include/asm/posix_types_64.h /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h unimar.h unipos.h devsql.h \ + unisql.h diff --git a/lib/devsql.h b/lib/devsql.h new file mode 100644 index 0000000..1332fda --- /dev/null +++ b/lib/devsql.h @@ -0,0 +1,60 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Low level subroutine declaration */ +/* to handle SQL resquest. */ +/* */ +/********************************************************/ +#ifndef DEVSQL +#define DEVSQL + +#include "unisql.h" + +//An SQL database pointer reference +typedef void SQLPTR; + +//An SQL database result reference +typedef void SQLRES; + +//procedure to make sure a string is acceptable +//as key search by database +extern char *sql_gooddata(SQLPTR *sqlptr,char *key); + +//procedure to return a dynamicaly allocated string +//to do SQL compute a date with a delta in second +extern char *sql_caldate(SQLPTR *sqlptr,char *expression,int second); + +//to connect a remote SQL server +extern SQLPTR *sql_opensql(); + +//procedure to close an previously opened SQL channel +extern SQLPTR *sql_closesql(SQLPTR *sqlptr); + +//converting a time to a database representation +extern char *sql_fromunixtime(SQLPTR *sqlptr,time_t timestamp); + +//converting a database time representation to unix time +extern time_t sql_tounixtime(SQLPTR *sqlptr,const char *date); + +//procedure to LOCK access to a database table +extern _Bool sql_lock(SQLPTR *sqlPTR,char *tablename); + +//procedure to UNLOCK access to a database table +extern _Bool sql_unlock(SQLPTR *sqlptr,_Bool commit); + +//procedure to transmit a simple data-base action +extern int sql_request(SQLPTR *sqlptr,const char *fmt,...); + +//to extract data from database +extern const char *sql_getvalue(SQLPTR *sqlptr,SQLRES *rs,int row,const char *name); + +//to extract data from database +extern SQLRES *sql_gettupple(SQLPTR *sqlptr,const char *fmt,...); + +//to retreive the number of tupple available within result +extern int sql_getnbrtupple(SQLPTR *sqlptr,SQLRES *); + +//to free memory used by a database tupple +extern SQLRES *sql_droptupple(SQLPTR *sqlptr,SQLRES *res); + +#endif diff --git a/lib/geseml.c b/lib/geseml.c new file mode 100644 index 0000000..8b091dd --- /dev/null +++ b/lib/geseml.c @@ -0,0 +1,967 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Implement all routine to manage email transport */ +/* exchange. */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "unidns.h" +#include "unieml.h" +#include "unipar.h" +#include "unitls.h" +#include "devsql.h" +#include "geseml.h" + +//dovecot local storage directory +#define DIRDOV "DOV_MAILDIR" + +typedef struct { + char *domain; //common domain + TRATYP **todo; //Transfer reference + }REFTYP; +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to compare 2 transaction struct */ +/* */ +/********************************************************/ +static int cmp_sessid(const void *p1,const void *p2) + + +{ +return strcmp((*((TRATYP **)p1))->sessid,(*((TRATYP **)p2))->sessid); +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to display/debug TRATYP record content*/ +/* */ +/********************************************************/ +static REFTYP *findref(REFTYP **reflist,char *domain) + + +{ +REFTYP *found; + +found=(REFTYP *)0; +if (reflist!=(REFTYP **)0) { + while (*reflist!=(REFTYP *)0) { + if (strcmp((*reflist)->domain,domain)==0) { + found=*reflist; + break; + } + reflist++; + } + } +return found; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to free a add domain reference from a */ +/* list of reference. */ +/* */ +/********************************************************/ +static REFTYP *freeref(REFTYP *reflist) + +{ +if (reflist!=(REFTYP *)0) { + (void) free(reflist->todo); + (void) free(reflist); + reflist=(REFTYP *)0; + } +return reflist; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to add a add domain reference to a */ +/* list of reference. */ +/* */ +/********************************************************/ +static REFTYP **addref(REFTYP **reflist,TRATYP *trans) + +{ +#define OPEP "geseml.c:addref," + +char *dom; +REFTYP *ref; +int phase; +_Bool proceed; + +dom=(char *)0; +ref=(REFTYP *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Firsy Check if we have data + if (trans==(TRATYP *)0) { + (void) rou_alert(0,"%s trans is NULL (Bug?)",OPEP); + phase=999; //No need to gi further + } + break; + case 1 : //Do we hav a domain + if ((dom=strchr(trans->rcptto,'@'))==(char *)0) { + (void) rou_alert(0,"%s unable to find domain within <%s> (Bug?)", + OPEP,trans->rcptto); + phase=999; //No dmain + } + break; + case 2 : //do we have domain + dom++; + if (strlen(dom)==0) { + (void) rou_alert(0,"%s Domain length from < <%s> is zero (Bug?)", + OPEP,trans->rcptto); + phase=999; //No dmain + } + break; + case 3 : //do we know domain + if ((ref=findref(reflist,dom))!=(REFTYP *)0) + phase++; //we have reference already + break; + case 4 : //Adding reference + ref=(REFTYP *)calloc(1,sizeof(REFTYP)); + ref->domain=dom; + reflist=(REFTYP **)rou_addlist((void **)reflist,(void *)ref); + break; + case 5 : //Adding transaction within reference + ref->todo=(TRATYP **)rou_addlist((void **)ref->todo,(void *)trans); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return reflist; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to display/debug TRATYP record content*/ +/* */ +/********************************************************/ +static void print_tra(FILE *qfile,char *line,char *temps) + +{ +if (qfile==(FILE *)0) + (void) rou_alert(0,"TRA=<%s>",line); +else { + if (temps!=(char *)0) + (void) fprintf(qfile,"%s\n",temps); + (void) fprintf(qfile,"%s\n",line); + } +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to display/debug ONE TRATYP record */ +/* content */ +/* */ +/********************************************************/ +PUBLIC _Bool eml_dump_one_tra(FILE *qfile,TRATYP *tra) + +{ +#define OPEP "geseml.c:eml_dump_one_tra," +_Bool status; + +status=false; +if (tra!=(TRATYP *)0) { + char temps[50]; + char line[300]; + + status=true; + (void) strftime(temps,sizeof(temps),"#%Y-%m-%d %H:%M:%S", + localtime(&(tra->date))); + (void) snprintf(line,sizeof(line),"%c\t%lu\t%05u %*s %*s %*s %*s \"%*s\" %s", + tra->code, + tra->date, + tra->delay, + -32,tra->sessid, + -30,tra->reverse, + -30,tra->rcptto, + -30,tra->sfrom, + -30,tra->hfrom, + tra->hsubject + ); + (void) print_tra(qfile,line,temps); + if (tra->resp!=(char **)0) { + char **ptr; + + ptr=tra->resp; + while (*ptr!=(char *)0) { + (void) snprintf(line,sizeof(line),"\t%s",*ptr); + (void) print_tra(qfile,line,(char *)0); + ptr++; + } + } + } +return status; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to display/debug TRATYP record content*/ +/* */ +/********************************************************/ +PUBLIC _Bool eml_dump_list_tra(FILE *qfile,TRATYP **tra) + +{ +#define OPEP "geseml.c:eml_dump_list_tra," + +_Bool action; + +action=false; +if (tra!=(TRATYP **)0) { + time_t isnow; + + isnow=time((time_t *)0); + if (qfile!=(FILE *)0) { + (void) fprintf(qfile,"#'C', completed email task\n"); + (void) fprintf(qfile,"#'L', Local email\n"); + (void) fprintf(qfile,"#'R', Remote email\n"); + (void) fprintf(qfile,"#code\tdate\t\tdelay " + "%*s %*s %*s %*s %*s subject\n", + -32,"session-id", + -30,"reverss-address", + -30,"recipient", + -30,"sfrom", + -30,"efrom"); + } + while (*tra!=(TRATYP *)0) { + (void) eml_dump_one_tra(qfile,*tra); + if (((*tra)->date+(*tra)->delay)<=isnow) + action=true; + tra++; + } + } +return action; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to duplicate an resp list within a tra*/ +/* record. */ +/* */ +/********************************************************/ +PUBLIC void eml_duptra_resp(TRATYP *tra,char **resp) + +{ +if (tra!=(TRATYP *)0) { + (void) eml_freetra_resp(tra); + if (resp!=(char **)0) { + while (*resp!=(char *)0) { + tra->resp=(char **)rou_addlist((void **)tra->resp,strdup(*resp)); + resp++; + } + } + } +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to duplicate TRATYP structure */ +/* */ +/********************************************************/ +PUBLIC TRATYP *eml_duptra(TRATYP *tra) + +{ +TRATYP *dup; + +dup=(TRATYP *)0; +if (tra!=(TRATYP *)0) { + dup=(TRATYP *)calloc(1,sizeof(TRATYP)); + dup->code=tra->code; + dup->date=tra->date; + dup->delay=tra->delay; + dup->reverse=strdup(tra->reverse); + dup->sfrom=strdup(tra->sfrom); + dup->hfrom=strdup(tra->hfrom); + dup->hsubject=strdup(tra->hsubject); + dup->rcptto=strdup(tra->rcptto); + dup->sessid=strdup(tra->sessid); + if (tra->resp!=(char **)0) { + char **ptr; + + ptr=tra->resp; + while (*ptr!=(char *)0) { + dup->resp=(char **)rou_addlist((void **)dup->resp,(void *)strdup(*ptr)); + ptr++; + } + } + } +return dup; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to scan the a qfile and build a */ +/* list of email transport directive. */ +/* */ +/********************************************************/ +PUBLIC TRATYP **eml_scanqfile(TRATYP **list,FILE *qfile) + +{ +#define OPEP "geseml.c:eml_scanqfile," +#define FMT "%c %ld %d %s %s %s %s \"%[^\"]\" %99[^\n]" + +TRATYP *cur; //previous trans record +char *ptr; +char line[300]; + +cur=(TRATYP *)0; +while ((ptr=fgets(line,sizeof(line),qfile))!=(char *)0) { + char id[300]; + char reverse[300]; + char sfrom[300]; + char hfrom[300]; + char hsubject[300]; + char to[300]; + char code; + u_long date; + u_int delay; + int phase; + _Bool proceed; + + phase=0; + proceed=true; + while (proceed==true) { + switch (phase) { + case 0 : //Removing comment + if ((ptr=strchr(line,'#'))!=(char *)0) + *ptr='\000'; + (void) rou_stripcrlf(line); + if (strlen(line)==0) + phase=999; //No data within line + break; + case 1 : //scanning line contents + switch (line[0]) { + case '\t' : //extra response line + if ((cur!=(TRATYP *)0)&&(strlen(line)>1)) + cur->resp=(char **)rou_addlist((void **)cur->resp,strdup(line+1)); + phase=999; //not a scanable trans line + break; + case 'C' : //Directives + case 'L' : + case 'R' : + case 'W' : + (void) memset(hfrom,'\000',sizeof(hfrom)); + (void) memset(hsubject,'\000',sizeof(hsubject)); + if (sscanf(line,FMT,&code,&date,&delay, + id,reverse,to,sfrom,hfrom,hsubject)!=9) { + (void) rou_alert(0,"%s Unable to scan (config?)",OPEP,line); + phase=999; //No data within line + } + break; + default : + (void) rou_alert(0,"%s Unexpected code within (config?)", + OPEP,line); + phase=999; //No data within line + break; + } + break; + case 2 : //cleaning element + while ((ptr=strchr(hfrom,'\"'))!=(char *)0) + *ptr=' '; + break; + case 3 : //storing line contents + if (strlen(id)>0) { //always? + cur=(TRATYP *)calloc(1,sizeof(TRATYP)); + cur->code=code; + cur->date=date; + cur->delay=delay; + cur->reverse=strdup(reverse); + cur->sessid=strdup(id); + cur->rcptto=strdup(to); + cur->sfrom=strdup(sfrom); + cur->hfrom=strdup(hfrom); + cur->hsubject=strdup(hsubject); + list=(TRATYP **)rou_addlist((void **)list,(void *)cur); + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } + } +return list; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to generate a list of todo file to */ +/* sender MTA. */ +/* */ +/********************************************************/ +PUBLIC void eml_todoqfile(TRATYP **list) + +{ +#define OPEP "geseml.c:eml_todoqfile," + +REFTYP **domlist; + +domlist=(REFTYP **)0; +if (list!=(TRATYP **)0) { + while (*list!=(TRATYP *)0) { + domlist=addref(domlist,*list); + list++; + } + } +if (domlist!=(REFTYP **)0) { + int iter; + time_t current; + struct tm *tinfo; + char buffer[80]; + REFTYP **ptr; + + iter=0; + (void) time(¤t); + tinfo=localtime(¤t); + (void) strftime(buffer,sizeof(buffer),"%s",tinfo); + ptr=domlist; + while (*ptr!=(REFTYP *)0) { + FILE *qfile; + _Bool action; + const char *ext; + char qname[150]; + int phase; + _Bool proceed; + + qfile=(FILE *)0; + action=false; + ext=EXTRANS; + (void) snprintf(qname,sizeof(qname),"%08ld-%08d-%04d",current,getpid(),iter); + phase=0; + proceed=true; + while (proceed==true) { + switch (phase) { + case 0 : //Opening qfile + if ((qfile=eml_createqfile(qname,EXTOBE))==(FILE *)0) + phase=999; //Trouble trouble + break; + case 1 : //dumping TRANS data to file + (void) eml_sort_list((*ptr)->todo); + if ((action=eml_dump_list_tra(qfile,(*ptr)->todo))==true) { + ext=EXTODO; + } + break; + case 2 : //Closing file + (void) eml_closeqfile(qfile); + break; + case 3 : //file ready, renaming file, + (void) eml_renameqfile(qname,EXTOBE,ext); + break; + case 4 : //do we need to start sender? + //Never start sender anymore (Saturday, July 19 2025) +#ifdef JMPDBG + if ((action==true)&&(foreground==false)) + (void) eml_start_sender(qname); +#endif + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } + *ptr=freeref(*ptr); + ptr++; + iter++; + } + (void) free(domlist); + } + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to clean/remove 'done' file. */ +/* */ +/********************************************************/ +PUBLIC void eml_doneqfile(TRATYP **list) + +{ +#define OPEP "geseml.c:eml_doneqfile," + +TRATYP **next; + +next=(TRATYP **)0; +if (list!=(TRATYP **)0) { + TRATYP **ptr; + + ptr=list; + while (*ptr!=(TRATYP *)0) { + _Bool toadd; + + toadd=true; + switch ((*ptr)->code) { + case 'C' : //email completed + toadd=false; + (void) eml_freetra_resp(*ptr); //no need to report actions + if (eml_countqfile((*ptr)->sessid,-1)==0) { + char fname[200]; + + (void) rou_alert(0,"%s JMPDBG need to remove <%s>",OPEP,(*ptr)->sessid); + (void) snprintf(fname,sizeof(fname),"%s.%s",(*ptr)->sessid,EXTCNT); + (void) eml_deleteqfile(fname); + } + break; + case 'W' : //need to send a warning + (void) eml_do_warning(*ptr); + break; + default : + break; + } + if (toadd==true) + next=(TRATYP **)rou_addlist((void **)next,(void *)eml_duptra(*ptr)); + ptr++; + } + } +if (next!=(TRATYP **)0) { + FILE *qfile; + time_t current; + char qname[150]; + int phase; + _Bool proceed; + + qfile=(FILE *)0; + (void) time(¤t); + (void) snprintf(qname,sizeof(qname),"%08ld-%08d-%04d",current,getpid(),0); + phase=0; + proceed=true; + while (proceed==true) { + switch (phase) { + case 0 : //Opening qfile + if ((qfile=eml_createqfile(qname,EXTOBE))==(FILE *)0) + phase=999; //Trouble trouble + break; + case 1 : //dumping TRANS data to file + (void) eml_dump_list_tra(qfile,next); + break; + case 2 : //Closing file + (void) eml_closeqfile(qfile); + break; + case 3 : //file ready, renaming file, + (void) eml_renameqfile(qname,EXTOBE,EXTRANS); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } + next=(TRATYP **)rou_freelist((void **)next,(genfree_t)eml_freetra); + } +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to store an email contents with the */ +/* recipient email area. */ +/* Return true if successful, false otherwise */ +/* */ +/********************************************************/ +PUBLIC _Bool eml_store_email(TRATYP *tra) + +{ +#define OPEP "geseml.c:eml_store_email," + +_Bool done; +char *locdom; +char dirname[300]; +int phase; +_Bool proceed; + +done=false; +locdom=(char *)0; +phase=0; +proceed=true; +while (proceed==true) { + (void) rou_dbglive(9,OPEP,"phase='%d'",phase); + switch (phase) { + case 0 : //Extracting recipient email + if ((tra!=(TRATYP *)0)&&(tra->rcptto!=(char *)0)&&(strlen(tra->rcptto)>0)) + locdom=strrchr(tra->rcptto,'@'); + if (locdom==(char *)0) { + (void) rou_alert(0,"%s Unable to get recipient domain in <%s> (Bug?)", + OPEP,tra->rcptto); + phase=999; //Big trouble + } + else + locdom++; + break; + case 1 : //creating recipient directory if needed + DIR *dir; + char *path; + + path=rou_apppath(getenv(DIRDOV)); + (void) snprintf(dirname,sizeof(dirname),"%s/%s/%s",path,locdom,tra->rcptto); + *(strrchr(dirname,'@'))='\000'; //keeping username only + (void) strncat(dirname,"/dovecot/new",sizeof(dirname)-strlen(dirname)); + if ((dir=opendir(dirname))==(DIR *)0) { + if (rou_do_mkpdir(dirname)==false) { + (void) rou_alert(0,"%s Unable to create <%s> directory (system?/bug?)", + OPEP,dirname); + phase=999; //big trouble, No need to go further + } + } + else + closedir(dir); + (void) free(path); + break; + case 2 : //duplicating session file to the recipient directory + if (eml_dupqfile(tra->sessid,dirname)==false) { + (void) rou_alert(0,"%s Unable to store email <%s> to user directory <%s>", + OPEP,tra->sessid,dirname); + phase=999; //big trouble. + } + break; + case 3 : //everything fine + char cmt[200]; + + (void) eml_freetra_resp(tra); + (void) snprintf(cmt,sizeof(cmt),"%d Message delivered in mail box",CMDOK); + tra->resp=(char **)rou_addlist((void **)tra->resp,(void *)strdup(cmt)); + done=true; + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return done; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to add an execution delay to an email */ +/* sending request. */ +/* Return true if succesfull, false otherwise */ +/* */ +/********************************************************/ +PUBLIC _Bool eml_add_delay(time_t isnow,TRATYP *tra) + +{ +#define OPEP "geseml.c:eml_add_delay," +_Bool status; + +status=false; +if (tra!=(TRATYP *)0) { + tra->date=isnow; + tra->delay=(tra->delay*2)+60; + status=true; + } +return status; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to fork process and execute the */ +/* "sender" component. */ +/* */ +/********************************************************/ +PUBLIC _Bool eml_start_sender(char *todo) + +{ +#define OPEP "unieml.c:eml_start_sender," + +_Bool status; + +status=false; +switch (fork()) { + case -1 : //trouble trouble + (void) rou_alert(0,"%s Unable to fork process (error=<%s> Bug?)", + OPEP,strerror(errno)); + break; + case 0 : //the forked process + char *execpath; + char *argv[10]; + char dbgstr[10]; + char buffer[300]; + + (void) memset(argv,'\000',sizeof(argv)); + (void) snprintf(dbgstr,sizeof(dbgstr),"%d",debug); + (void) snprintf(buffer,sizeof(buffer),"%s%s",SBINDIR,SENDER); + execpath=rou_apppath(buffer); + (void) snprintf(buffer,sizeof(buffer),"%s.%s",todo,EXTODO); + argv[0]=execpath; //The FULL SENDER name + argv[1]="-c"; + argv[2]=config; + argv[3]="-d"; + argv[4]=dbgstr; + argv[5]=buffer; + if (rootdir!=(char *)0) { + argv[5]="-r"; + argv[6]=rootdir; + argv[7]=buffer; + } + (void) rou_dbglive(2,OPEP,"Starting sender=<%s> todo= <%s>",execpath,buffer); + if (execv(execpath,argv)<0) { + (void) rou_alert(0,"%s Unable to exec process=<%s> (error=<%s> Bug?)", + OPEP,execpath,strerror(errno)); + (void) rou_freestr(execpath); + (void) exit(-1); + } + break; + default : //the forking process itself + (void) usleep(10000); //relax delay + status=true; + break; + } +return status; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to make sure todo list is sorted */ +/* according the session id. */ +/* */ +/********************************************************/ +PUBLIC _Bool eml_sort_list(TRATYP **list) + +{ +_Bool result; + +result=false; +if (list!=(TRATYP **)0) { + register int num; + + num=rou_nbrlist((void **)list); + (void) qsort((void *)list,num,sizeof(TRATYP *),cmp_sessid); + result=true; + } +return result; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to build a warning/reply about an */ +/* unsuccessfull email sending. The Email is sent */ +/* back to the originator. */ +/* */ +/********************************************************/ +PUBLIC _Bool eml_do_warning(TRATYP *tra) + +{ +#define OPEP "geseml.c:eml_do_warning," + +_Bool done; +char *sessata; //attachement session number +FILE *qout; +char orig[100]; +char cmt[200]; +int phase; +_Bool proceed; + +done=false; +sessata=eml_getmainsesid(); +(void) snprintf(orig,sizeof(orig),"%s@%s","noreply",getenv("DFLTDOMAIN")); +qout=(FILE *)0; +phase=0; +proceed=true; +while (proceed==true) { + (void) rou_dbglive(9,OPEP,"phase='%d'",phase); + switch (phase) { + case 0 : //create the new attachement file + if ((qout=eml_createqfile(sessata,(char *)0))==(FILE *)0) { + (void) rou_alert(0,"%s Unable to create attachement file (system?)", + OPEP); + phase=999; + } + break; + case 1 : //Preparing attachement email + (void) fprintf(qout,"%s%s Email daemon <%s>\n",HFROM,APPNAME,orig); + (void) fprintf(qout,"To: <%s>\n",tra->sfrom); + (void) fprintf(qout,"Date: %s\n",rou_ascsysstamp(time((time_t *)0))); + (void) fprintf(qout,"%s%s\n",HTITLE,*(tra->resp)+4); + break; + case 2 : //attaching (200 line at most) from email itself + done=eml_attache(qout,tra->sessid,tra->resp,200); + qout=eml_closeqfile(qout); + if (done==false) { + (void) rou_alert(0,"%s Unable to create attachement session (system?)", + OPEP); + phase=999; + } + break; + case 3 : //creating a count file for attachement file + if ((qout=eml_createqfile(sessata,EXTCNT))==(FILE *)0) { + (void) rou_alert(0,"%s Unable to open 'count' qfile <%s> (error=<%s>)", + OPEP,sessata,strerror(errno)); + (void) eml_deleteqfile(sessata); + done=false; + phase=999; + } + break; + case 4 : //set number winthin sessata count file + (void) fprintf(qout,"1\n"); + (void) eml_closeqfile(qout); + break; + case 5 : //counting original session + switch (eml_countqfile(tra->sessid,-1)) { + case -1 : + (void) rou_alert(0,"%s Unable to count down sessid <%s>", + OPEP,tra->sessid); + phase=999; + break; + case 0 : //session file is not needed anymore + (void) snprintf(cmt,sizeof(cmt),"%s.%s",tra->sessid,EXTCNT); + (void) eml_deleteqfile(cmt); + break; + default : //Nothing to do + break; + } + break; + case 6 : //check if email is FROM local or remote + char *domain; + int status; + + domain=strchr(tra->sfrom,'@'); + status=dns_is_domain_local(domain,tls_get_bind_afn()); + switch (status) { + case dns_local : + tra->code='L'; + break; + case dns_remote : + tra->code='R'; + break; + case dns_nomx : //Should NEVER ever occur + (void) rou_alert(0,"%s Unable to find MX for domain<%s> (bug?)", + OPEP,status,domain); + phase=999; + break; + default : + (void) rou_alert(0,"%s Unexpected status='%d' for domain<%s> (bug?)", + OPEP,status,domain); + phase=999; + break; + } + break; + case 7 : //reversing originator/recipient + tra->delay=0; + tra->sessid=rou_freestr(tra->sessid); + tra->sessid=strdup(sessata); + tra->rcptto=rou_freestr(tra->rcptto); + tra->rcptto=tra->sfrom; + tra->sfrom=strdup(orig); + done=true; + break; + case 8 : //building the new sessid file + tra->resp=(char **)rou_freelist((void **)tra->resp,(genfree_t)rou_freestr); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +sessata=rou_freestr(sessata); +return done; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to check email header and extract */ +/* session data. */ +/* Return true if data was extracted. */ +/* */ +/********************************************************/ +PUBLIC _Bool eml_scan_headerline(SESTYP *session,const char *line) + +{ +#define OPEP "geseml.c:eml_scan_headerline," +_Bool extracted; + +const char *look[]={HFROM,HTITLE,(char *)0}; + +extracted=false; +if ((line!=(char *)0)&&(strlen(line)>0)) { + (void) rou_dbglive(0,OPEP,"scaning header <%s>",line); + for (int i=0;(extracted==false)&&(look[i]!=(char *)0);i++) { + int max; + + max=strlen(look[i]); + if (strncasecmp(line,look[i],max)==0) { + extracted=true; + switch (i) { + case 0 : //Inserting the header from in session + session->hfrom=rou_freestr(session->hfrom); + session->hfrom=strdup(line+max); + break; + case 1 : //Inserting the header from in session + session->hsubject=rou_freestr(session->hsubject); + session->hsubject=strdup(line+max); + break; + default : + (void) rou_alert(0,"%s Code missing for Head entrey <%s> (Bug?!)", + OPEP,look[i]); + break; + } + } + } + } +return extracted; + +#undef OPEP +} diff --git a/lib/geseml.d b/lib/geseml.d new file mode 100644 index 0000000..e732ec2 --- /dev/null +++ b/lib/geseml.d @@ -0,0 +1,111 @@ +geseml.o geseml.d : geseml.c /usr/include/stdc-predef.h /usr/include/dirent.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/dirent.h \ + /usr/include/bits/posix1_lim.h /usr/include/bits/local_lim.h \ + /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/dirent_ext.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/string.h \ + /usr/include/bits/libc-header-start.h /usr/include/bits/types/locale_t.h \ + /usr/include/bits/types/__locale_t.h /usr/include/strings.h \ + /usr/include/unistd.h /usr/include/bits/posix_opt.h \ + /usr/include/bits/environments.h /usr/include/bits/confname.h \ + /usr/include/bits/getopt_posix.h /usr/include/bits/getopt_core.h \ + /usr/include/bits/unistd_ext.h /usr/include/uuid/uuid.h \ + /usr/include/sys/types.h /usr/include/bits/types/clock_t.h \ + /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/byteswap.h \ + /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \ + /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/sys/time.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h unidns.h \ + subafn.h /usr/include/netdb.h /usr/include/netinet/in.h \ + /usr/include/bits/stdint-uintn.h /usr/include/sys/socket.h \ + /usr/include/bits/types/struct_iovec.h /usr/include/bits/socket.h \ + /usr/include/bits/socket_type.h /usr/include/bits/sockaddr.h \ + /usr/include/asm/socket.h /usr/include/asm-generic/socket.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/bits/in.h \ + /usr/include/rpc/netdb.h /usr/include/bits/netdb.h unieml.h \ + /usr/include/stdio.h /usr/include/bits/types/__fpos_t.h \ + /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h unipar.h unitls.h \ + /usr/include/openssl/ssl.h /usr/include/openssl/macros.h \ + /usr/include/openssl/opensslconf.h /usr/include/openssl/configuration.h \ + /usr/include/openssl/opensslv.h /usr/include/openssl/e_os2.h \ + /usr/include/inttypes.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdint.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/bits/stdint-least.h /usr/include/openssl/e_ostime.h \ + /usr/include/openssl/comp.h /usr/include/openssl/crypto.h \ + /usr/include/stdlib.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/openssl/safestack.h \ + /usr/include/openssl/stack.h /usr/include/openssl/types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/limits.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix2_lim.h \ + /usr/include/openssl/cryptoerr.h /usr/include/openssl/symhacks.h \ + /usr/include/openssl/cryptoerr_legacy.h /usr/include/openssl/core.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include-fixed/pthread.h \ + /usr/include/sched.h /usr/include/bits/sched.h \ + /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \ + /usr/include/bits/setjmp.h \ + /usr/include/bits/types/struct___jmp_buf_tag.h \ + /usr/include/openssl/comperr.h /usr/include/openssl/bio.h \ + /usr/include/openssl/bioerr.h /usr/include/openssl/x509.h \ + /usr/include/openssl/buffer.h /usr/include/openssl/buffererr.h \ + /usr/include/openssl/evp.h /usr/include/openssl/core_dispatch.h \ + /usr/include/openssl/indicator.h /usr/include/openssl/params.h \ + /usr/include/openssl/bn.h /usr/include/openssl/bnerr.h \ + /usr/include/openssl/evperr.h /usr/include/openssl/objects.h \ + /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \ + /usr/include/openssl/asn1err.h /usr/include/openssl/objectserr.h \ + /usr/include/openssl/ec.h /usr/include/openssl/ecerr.h \ + /usr/include/openssl/rsa.h /usr/include/openssl/rsaerr.h \ + /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \ + /usr/include/openssl/dherr.h /usr/include/openssl/dsaerr.h \ + /usr/include/openssl/sha.h /usr/include/openssl/x509err.h \ + /usr/include/openssl/x509_vfy.h /usr/include/openssl/lhash.h \ + /usr/include/openssl/pkcs7.h /usr/include/openssl/pkcs7err.h \ + /usr/include/openssl/http.h /usr/include/openssl/conf.h \ + /usr/include/openssl/conferr.h /usr/include/openssl/conftypes.h \ + /usr/include/openssl/pem.h /usr/include/openssl/pemerr.h \ + /usr/include/openssl/hmac.h /usr/include/openssl/async.h \ + /usr/include/openssl/asyncerr.h /usr/include/openssl/ct.h \ + /usr/include/openssl/cterr.h /usr/include/openssl/sslerr.h \ + /usr/include/openssl/sslerr_legacy.h /usr/include/openssl/prov_ssl.h \ + /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \ + /usr/include/openssl/tls1.h /usr/include/openssl/dtls1.h \ + /usr/include/openssl/srtp.h /usr/include/openssl/quic.h devsql.h \ + unisql.h geseml.h diff --git a/lib/geseml.h b/lib/geseml.h new file mode 100644 index 0000000..5edb501 --- /dev/null +++ b/lib/geseml.h @@ -0,0 +1,62 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Define all procedure to manage email transport */ +/* data. */ +/* */ +/********************************************************/ +#ifndef GESEML +#define GESEML + +#include +#include +#include + +#include "unisql.h" + +//procedure to dump a list of transfert record +extern _Bool eml_dump_one_tra(FILE *out,TRATYP *tra); + +//procedure to dump a list of transfert record +extern _Bool eml_dump_list_tra(FILE *out,TRATYP **tra); + +//procedure to fee memory used to duplicate a resp list to tra resp +extern void eml_duptra_resp(TRATYP *tra,char **resp); + +//procedure to duplicate a TRATYP structure +extern TRATYP *eml_duptra(TRATYP *tra); + +//procedure to fee memory used by a TRATYP structure +//extern TRATYP **eml_freeall_tra(TRATYP **tra); + +//procedure to open a specific qfile +extern TRATYP **eml_scanqfile(TRATYP **list,FILE *qfile); + +//procedure to Generate todolist file within queue +extern void eml_todoqfile(TRATYP **list); + +//procedure to clean/remove done file within queue +extern void eml_doneqfile(TRATYP **list); + +//procedure to store an email to the local email storage area +extern _Bool eml_store_email(TRATYP *tra); + +//procedure to add execution delay to an email sending +extern _Bool eml_add_delay(time_t isnow,TRATYP *tra); + +//procedure to fork a process and start the "sender" process +extern _Bool eml_start_sender(char *todo); + +//procedure to sort a transmission list according sessionid +extern _Bool eml_sort_list(TRATYP **List); + +//procedure to build a warning/reply from the transfer record +extern _Bool eml_do_warning(TRATYP *tra); + +//procedure to scan on line from email header +extern _Bool eml_scan_headerline(SESTYP *session,const char *line); + +//procedure to update database with transfer record (TRATYP) +extern int eml_update_tradb(TRATYP **tra); + +#endif diff --git a/lib/gesspf.c b/lib/gesspf.c new file mode 100644 index 0000000..8dd8c3f --- /dev/null +++ b/lib/gesspf.c @@ -0,0 +1,678 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Implement all routine to manage SMTP low level */ +/* exchange. */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "unidns.h" +#include "gesspf.h" + +#define MXDNS 10 //maximun number of DNS acess + +typedef enum { //mechanism definition + mch_all, //"all" + mch_addr, //'a' + mch_exists, //"existe" + mch_include, //"include" + mch_ip4, //"ip4" + mch_ip6, //"ip6" + mch_mx, //"mx" + mch_ptr, //"mx" + mch_redirect, //"redirect" + mch_unknown //unknown mechanism + }MCHTYP; + +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to display SPF debug information */ +/* */ +/********************************************************/ +static void dbgspf(int dbg,char *proc,char *domain,AFNTYP *afnnum,char *seq,SPFENU status) + +{ +if (debug>=dbg) { + (void) rou_alert(dbg,"Origin=\"%s\"\n" + "\tCurrent SPF Value <%s>\n" + "\tPeer IP=[%s]\n" + "\tdomain=<%s> SPF=<%s>", + proc,spf_spfASCII(status),afnnum->strnumip,domain,seq); + } +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to parse mechanisme string */ +/* */ +/********************************************************/ +static MCHTYP tellmechanism(char *seq) + +{ +//MUST be set in the MCHTYP order +static char *voc[]= + { + "all", //allways match + "a", //addresss + "exists", //allways match + "include", //include sub domain + "ip4", //IPV4 address format + "ip6", //IPV5 address format + "mx", //MX definition + "ptr", //PTR definition + "redirect", //PTR definition + (char *)0 + }; + +MCHTYP mch; + +mch=mch_unknown; +for (int i=0;voc[i]!=(char *)0;i++) { + register int taille; + + taille=strlen(voc[i]); + if (strncmp(voc[i],seq,taille)!=0) + continue; + (void) memmove(seq,seq+taille,strlen(seq+taille)+1); + mch=(MCHTYP)i; + break; + } +return mch; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to get the next SPF component */ +/* return a dynamic char pointer with the isolated */ +/* SPF sequence. */ +/* */ +/********************************************************/ +static char *getspfseq(char *fullspf) + +{ +char *seq; +int phase; +_Bool proceed; + +seq=(char *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Converting the IP number + if (fullspf==(char *)0) + phase=999; //no need to go further + break; + case 1 : //skipping blank + while ((*fullspf==' ')||(*fullspf=='\t')) + fullspf++; //scanning blank + if (strlen(fullspf)==0) + phase=999; //no need to go further + break; + case 2 : //we got a sequence + seq=strdup(fullspf); + break; + case 3 : //sync sequence + if (seq!=(char *)0) { //always + char *ptr; + + if ((ptr=strchr(seq,' '))!=(char *)0) + *ptr='\000'; + if ((ptr=strchr(seq,'\t'))!=(char *)0) + *ptr='\000'; + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return seq; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to check the SPF A value againt the */ +/* current afnnum. */ +/* return true if successful. */ +/* */ +/********************************************************/ +static _Bool checkaddr(char *domain,AFNTYP *afnnum,char *addr) + +{ +#define OPEP "gesspf.c:checkaddr" + +_Bool found; +int cidr; +char *addrdom; +int phase; +_Bool proceed; + +found=false; +cidr=128; +addrdom=domain; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //getting the list of MX + if (addrdom!=(char *)0) { //always + char *ptr; + + if ((ptr=strchr(addrdom,'/'))!=(char *)0) { + *ptr='\000'; + cidr=atoi(ptr+1); + } + if ((ptr=strchr(addrdom,':'))!=(char *)0) { + *ptr='\000'; + addrdom=ptr+1; + } + } + break; + case 1 : //getting the list of address for the domain + found=dns_matchiprec(addrdom,afnnum,cidr); + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return found; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to check the SPF MX values againt the */ +/* current afnnum. */ +/* return true if successful. */ +/* */ +/********************************************************/ +static _Bool checkmx(char *domain,AFNTYP *afnnum,char *mx) + +{ +#define OPEP "gesspf.c:checkmx" + +_Bool found; +int cidr; +char *mxdom; +MXTYP **mxlist; +struct addrinfo hints; +int phase; +_Bool proceed; + +found=false; +cidr=128; +mxdom=domain; +mxlist=(MXTYP **)0; +(void) memset(&hints,'\000',sizeof(hints)); +hints.ai_family=PF_UNSPEC; +hints.ai_socktype=SOCK_STREAM; +hints.ai_flags=HINTFLG; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //getting the list of MX + if (mx!=(char *)0) { //always + char *ptr; + + if ((ptr=strchr(mx,'/'))!=(char *)0) { + *ptr='\000'; + cidr=atoi(ptr+1); + } + if ((ptr=strchr(mx,':'))!=(char *)0) { + *ptr='\000'; + mxdom=ptr+1; + } + } + break; + case 1 : //getting the list of MX for mxdomain + if ((mxlist=dns_getmx(mxdom))==(MXTYP **)0) { + (void) rou_alert(0,"%s empty MX list for domain <%s> (remote DNS config?)", + OPEP,mxdom); + phase=999; //trouble no need to go further + } + break; + case 2 : //getting the list of MX for mxdomain + for (int i=0;(found==false)&&(mxlist[i]!=(MXTYP *)0);i++) { + int status; + struct addrinfo *res; + struct addrinfo *rp; + + status=getaddrinfo(mxlist[i]->mxname,"",&hints,&res); + if (status!=0) { + (void) rou_alert(0,"%s Unable to find addrinfo for <%s> (error=<%s>)", + OPEP,mxlist[i]->mxname,gai_strerror(status)); + continue; + } + rp=res; + for (int j=0;rp!=(struct addrinfo *)0;rp=rp->ai_next,j++) { + AFNTYP *addrnum; + + if ((addrnum=afn_getaddrinfo(rp))==(AFNTYP *)0) { + (void) rou_alert(0,"%s Found unknown inet family for <%s> IP number", + OPEP,mxlist[i]->mxname); + continue; + } + switch (afn_cmpipnum(addrnum,afnnum,cidr)) { + case false : //not found + break; + case true : //found + found=true; + break; + case -1 : //trouble? + (void) rou_alert(0,"%s Unable to compare MX IP for " + "host <%s> (error=<%s>)", + OPEP,mxlist[i]->mxname,strerror(errno)); + break; + } + addrnum=afn_freeipnum(addrnum); + if (found==true) + break; //no need to loop further + } + (void) freeaddrinfo(res); + } + mxlist=dns_freemxlist(mxlist); + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return found; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to check ip peerip is within an */ +/* spf sequence */ +/* */ +/********************************************************/ +static _Bool checkip(char *domain,AFNTYP *afnnum,char *seq) + +{ +#define OPEP "gesspf.c:checkip" +_Bool found; +int cidr; +AFNTYP **target; +int phase; +_Bool proceed; + +found=false; +cidr=128; +target=(AFNTYP **)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Converting the IP number + if (seq==(char *)0) { + (void) rou_alert(2,"%s Sequence missing from domain <%s> " + "(Wrong SPF sequence wrong)",OPEP,domain); + phase=999; + } + break; + case 1 : //calculating the local cidr + if (seq!=(char *)0) { //always + char *ptr; + + if ((ptr=strchr(seq,'/'))!=(char *)0) { + *ptr='\000'; + cidr=atoi(ptr+1); + } + } + break; + case 2 : //computing the target ipnumber + if ((target=afn_getipnums(seq))==(AFNTYP **)0) { + (void) rou_alert(0,"%s Unable to convert <%s> from " + "domain <%s> (SPF bug?)", + OPEP,seq,domain); + phase=999; //no need to go further + } + break; + case 3 : //calculating the local cidr + for (int i=0;(target[i]!=(AFNTYP*)0)&&(found==false);i++) { + switch (afn_cmpipnum(afnnum,target[i],cidr)) { + case -1 : + (void) rou_alert(0,"%s Unable to compare IP [%s] from SPF " + "domain <%s> (errno=<%s>) (SPF?)", + OPEP,seq,domain); + break; + case 1 : + found=true; + break; + case 0 : + break; + } + } + target=(AFNTYP **)rou_freelist((void **)target,(genfree_t)afn_freeipnum); + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return found; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to return an spf status according */ +/* sequence contents */ +/* */ +/********************************************************/ +static SPFENU checkseq(int *try,char *domain,char *seq,AFNTYP *afnnum,SPFENU spf) + +{ +#define OPEP "gesspf.c:checkseq" +SPFENU locspf; +int phase; +_Bool proceed; + +spf=spf_neutral; +locspf=spf_pass; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //is the sequence an SPF Mechanisms + if (strchr("?~-+",seq[0])!=(char *)0) { + switch (seq[0]) { + case '?' : + locspf=spf_neutral; + break; + case '~' : + locspf=spf_softfail; + break; + case '+' : + locspf=spf_pass; + break; + case '-' : + locspf=spf_fail; + break; + } + seq++; + } + break; + case 1 : //check directive + switch (tellmechanism(seq)) { + case mch_all : //usually last in sequence + spf=locspf; + break; + case mch_addr : //check IP addr + if (checkaddr(domain,afnnum,seq)==true) + spf=locspf; + break; + case mch_mx : //This is a MX refrence + if (checkmx(domain,afnnum,seq)==true) + spf=locspf; + break; + case mch_ip4 : //This is IPV4 number + case mch_ip6 : //This is IPV6 number + if (checkip(domain,afnnum,seq+1)==true) + spf=locspf; + (void) dbgspf(5,"checkip",domain,afnnum,seq+1,spf); + break; + case mch_include : //include sub domain + if (seq[0]==':') { + (*try)++; + spf=spf_getstatus(try,seq+1,afnnum); + } + else { + (void) rou_alert(0,"%s wrong SPF include seq <%s> (SPF format?)", + OPEP,seq); + spf=spf_permerr; + } + break; + default : //trouble + break; + case mch_unknown : //trouble + (void) rou_alert(0,"%s unknown mechanism <%s> (bug?, config?)", + OPEP,seq); + spf=spf_permerr; + break; + } + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return spf; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return check if an IP is part of */ +/* spf allowed IP */ +/* */ +/********************************************************/ +static SPFENU is_peerip_ok(int *try,char *domain,AFNTYP *afnnum,char *spfrec) + +{ +#define OPEP "gesspf.c:is_peerip_ok" +SPFENU spf; +int phase; +_Bool proceed; + +spf=spf_neutral; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Converting the IP number + if (spfrec==(char *)0) { + (void) rou_alert(0,"%s SPF record is NULL (bug?)",OPEP); + phase=999; + } + break; + case 1 : //making sure spfrec is an SPF1 + if (strlen(spfrec)>0) { + char *seq; + char *ref; + + ref=spfrec; + while ((seq=getspfseq(spfrec))!=(char *)0) { + spfrec=strstr(spfrec,seq); + spfrec+=strlen(seq); + spf=checkseq(try,domain,seq,afnnum,spf); + seq=rou_freestr(seq); + if (spf!=spf_neutral) + break; //Found a pass status, breaking loop + } + (void) dbgspf(5,"is_peerip_ok",domain,afnnum,ref,spf); + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return spf; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return the SPF status string value */ +/* */ +/********************************************************/ +PUBLIC const char *spf_spfASCII(SPFENU spf) + +{ +#define OPEP "gesspf.c:dns_spfASCII" +static char *spfascii[]= + { + "spf_pass", + "spf_fail", + "spf_softfail", + "spf_neutral", + "spf_timeout", + "spf_missing", + "spf_permerr", + "spf_unknown" + }; + +const char *ascii; + +ascii="Unset (Bug?)"; +switch (spf) { + case spf_pass : + case spf_fail : + case spf_softfail : + case spf_neutral : + case spf_timeout : + case spf_missing : + case spf_permerr : + case spf_unknown : + ascii=spfascii[spf]; + break; + default : + (void) rou_alert(0,"%s, Unexpected '%d' SPF status (Bug!)",OPEP,spf); + break; + } +return ascii; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to get the SPF status according a */ +/* domain name and and an IP. */ +/* */ +/********************************************************/ +PUBLIC SPFENU spf_getstatus(int *try,char *domain,AFNTYP *afnnum) + +{ +#define OPEP "gesspf.c:spf_getstatus" + +SPFENU spf; +char *list; +int phase; +_Bool proceed; + +(*try)++; +spf=spf_permerr; +list=(char *)0; +phase=0; +proceed=true; +while (proceed==true) { + (void) rou_alert(8,"JMPDBG %s, phase='%d', domain=<%s>",OPEP,phase,domain); + switch (phase) { + case 0 : //Are the parameters available + if ((domain==(char *)0)||(afnnum==(AFNTYP *)0)) { + (void) rou_alert(0,"%s missing one or both needed argument",OPEP); + phase=999; //trouble trouble + } + break; + case 1 : //check the number of DNS access + if ((*try)>MXDNS) { + (void) rou_alert(0,"%s SPF record scan is too deep (aborting)",OPEP); + phase=999; //trouble trouble + } + break; + case 2 : //get the spf LIST related to SPF + if ((list=dns_getspf(domain))==(char *)0) + phase=999; //trouble trouble + break; + case 3 : //get the spf LIST related to SPF + spf=is_peerip_ok(try,domain,afnnum,list); + list=rou_freestr(list); + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return spf; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to get the SPF domain/peerip status */ +/* return the SPF status. */ +/* */ +/********************************************************/ +PUBLIC SPFENU spf_getspf(char *mailfrom,char *peerip) + +{ +#define OPEP "gesspf.c:spf_getspf" + +SPFENU spf; +char *domain; + +spf=spf_unknown; +domain=strchr(mailfrom,'@'); +if (domain!=(char *)0) + domain++; +if (domain!=(char *)0) { + AFNTYP **afns; + + afns=afn_getipnums(peerip); + if (afns!=(AFNTYP **)0) { + int try; + + try=0; + for (int i=0;afns[i]!=(AFNTYP *)0;i++) { + spf=spf_getstatus(&try,domain,afns[i]); + (void) rou_dbglive(9,OPEP,"SPF[%d] for [%s]=<%s>", + i,afns[i]->strnumip,spf_spfASCII(spf)); + } + afns=(AFNTYP **)rou_freelist((void **)afns,(genfree_t)afn_freeipnum); + } + } +return spf; + +#undef OPEP +} diff --git a/lib/gesspf.d b/lib/gesspf.d new file mode 100644 index 0000000..fa18e8a --- /dev/null +++ b/lib/gesspf.d @@ -0,0 +1,83 @@ +gesspf.o gesspf.d : gesspf.c /usr/include/stdc-predef.h /usr/include/errno.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/malloc.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/stdio.h /usr/include/bits/libc-header-start.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/types/__fpos_t.h \ + /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/resolv.h \ + /usr/include/sys/param.h /usr/include/sys/types.h \ + /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/time_t.h /usr/include/bits/types/timer_t.h \ + /usr/include/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/endianness.h \ + /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/limits.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h /usr/include/bits/posix2_lim.h \ + /usr/include/signal.h /usr/include/bits/signum-generic.h \ + /usr/include/bits/signum-arch.h /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h /usr/include/bits/types/stack_t.h \ + /usr/include/sys/ucontext.h /usr/include/bits/sigstack.h \ + /usr/include/bits/sigstksz.h /usr/include/bits/ss_flags.h \ + /usr/include/bits/types/struct_sigstack.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h /usr/include/bits/param.h \ + /usr/include/linux/param.h /usr/include/asm/param.h \ + /usr/include/asm-generic/param.h /usr/include/netinet/in.h \ + /usr/include/bits/stdint-uintn.h /usr/include/sys/socket.h \ + /usr/include/bits/types/struct_iovec.h /usr/include/bits/socket.h \ + /usr/include/bits/socket_type.h /usr/include/bits/sockaddr.h \ + /usr/include/asm/socket.h /usr/include/asm-generic/socket.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h /usr/include/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/asm/sockios.h \ + /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/bits/in.h \ + /usr/include/arpa/nameser.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdint.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/bits/stdint-least.h /usr/include/arpa/nameser_compat.h \ + /usr/include/bits/types/res_state.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/stdlib.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/string.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/strings.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h unidns.h subafn.h \ + /usr/include/netdb.h /usr/include/rpc/netdb.h /usr/include/bits/netdb.h \ + gesspf.h diff --git a/lib/gesspf.h b/lib/gesspf.h new file mode 100644 index 0000000..5d5f89a --- /dev/null +++ b/lib/gesspf.h @@ -0,0 +1,34 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Define all procedure to manage SPF entry within */ +/* DNS record. */ +/* */ +/********************************************************/ +#ifndef GESSPF +#define GESSPF + +#include "subafn.h" +#include "gesspf.h" + +typedef enum { + spf_pass, //OK if condition apply + spf_fail, //NOK if condition apply + spf_softfail, //Msg origin is dubious + spf_neutral, //same status as no SPF + spf_timeout, //no answer within time + spf_missing, //SPF not found + spf_permerr, //SPF permanent error + spf_unknown //Unknown SPF directive + }SPFENU; + +//procedure to return spf status as an ASCII string +extern const char *spf_spfASCII(SPFENU spf); + +//get the SPF status for a specific domain and an IP +extern SPFENU spf_getstatus(int *try,char *domain,AFNTYP *afnnum); + +//get the SPF status for a specific domain according remote peer ipnumer +extern SPFENU spf_getspf(char *domain,char *peerip); + +#endif diff --git a/lib/gessql.c b/lib/gessql.c new file mode 100644 index 0000000..d1739ac --- /dev/null +++ b/lib/gessql.c @@ -0,0 +1,966 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Module to manage complexe SQL request */ +/* */ +/********************************************************/ +#include +#include +#include + +#include "subrou.h" +#include "unisql.h" +#include "gessql.h" + +//DATABASE Table names +#define EMLTBL "emails" //Table about user list +#define RMTTBL "remotes" //Table about remotes site +#define ACTTBL "actions" //action tables +#define SESTBL "sessions" //session tables +#define EVTTBL "events" //events tables + +//field available in table "remotes" +static const FLDTYP usrfield[]={ + {1,"remoteip"}, + {2,"lastscan"}, + {3,"lastupdate"}, + {4,"links"}, + {5,"credit"}, + {6,"listing"}, + {7,"reverse"}, + {0,(char *)0} + }; + +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to update database information about */ +/* emails echange current and last status. */ +/* */ +/********************************************************/ +PUBLIC _Bool sql_mngact(SQLPTR *sqlptr,ACTTYP *act) + +{ +#define OPEP "gessql.c:sql_mngact," + +static const char + *del="DELETE FROM "ACTTBL" WHERE sessid=%s AND (rcptto=%s OR rcptto IS NULL)"; +static const char + *ins="INSERT INTO "ACTTBL" (%s) VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%d,%d,%s)"; + +_Bool isok; + +isok=false; +if (act!=(ACTTYP *)0) { + char strcode[10]; + char *gid; + char *gremoteip; //remote IP address + char *greverse; //remote reverse name + char *gsfrom; //SMTP "mail from:" + char *ghfrom; //email Header "From:" + char *ghsubject; //email Header "Subject:" + char *grcpt; + char *gcode; + + (void) memset(strcode,'\000',sizeof(strcode)); + strcode[0]=act->code; + gid=sql_gooddata(sqlptr,act->sessid); + gremoteip=sql_gooddata(sqlptr,act->remoteip); + greverse=sql_gooddata(sqlptr,act->reverse); + gsfrom=sql_gooddata(sqlptr,act->sfrom); + ghsubject=sql_gooddata(sqlptr,act->hsubject); + ghfrom=sql_gooddata(sqlptr,act->hfrom); + grcpt=sql_gooddata(sqlptr,act->rcptto); + gcode=sql_gooddata(sqlptr,strcode); + if (act->resp!=(char **)0) { + char *field; + + field="code,sessid,remoteip,reverse,smtpfrom,emailfrom,subject,rcptto,numline,status,info"; + (void) sql_request(sqlptr,del,gid,grcpt); + if (act->resp!=(char **)0) { + char **resp; + int num; + + resp=act->resp; + num=1; + while (*resp!=(char *)0) { + if ((*resp)[3]==' ') { + char strint[5]; + int status; + char *ginfo; + + + (void) memset(strint,'\000',sizeof(strint)); + (void) strncpy(strint,*resp,3); + status=atoi(strint); + ginfo=sql_gooddata(sqlptr,(*resp)+3); + (void) sql_request(sqlptr,ins,field, + gcode,gid, + gremoteip,greverse, + gsfrom,ghfrom,ghsubject, + grcpt,num,status,ginfo); + ginfo=rou_freestr(ginfo); + } + resp++; + num++; + } + } + } + gcode=rou_freestr(gcode); + grcpt=rou_freestr(grcpt); + ghsubject=rou_freestr(ghsubject); + ghfrom=rou_freestr(ghfrom); + gsfrom=rou_freestr(gsfrom); + greverse=rou_freestr(greverse); + gid=rou_freestr(gid); + isok=true; + } +return isok; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to set all remotes links value to zero*/ +/* */ +/********************************************************/ +PUBLIC void sql_droplinks(SQLPTR *sqlptr) + +{ +(void) sql_request(sqlptr,"update "RMTTBL" set links=0"); +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to update the database with respond */ +/* Record associated with TRA. */ +/* Return the number of record stored within the */ +/* database. */ +/* */ +/********************************************************/ +PUBLIC int sql_update_tradb(SQLPTR *sqlptr,TRATYP **tralist) + +{ +#define OPEP "gesql.c:qlupdate_tradb," + +int num; + +num=0; +if (tralist!=(TRATYP **)0) { + while (*tralist!=(TRATYP *)0) { + if ((*tralist)->resp!=(char **)0) { + ACTTYP action; + + (void) memset(&action,'\000',sizeof(ACTTYP)); + action.sessid=(*tralist)->sessid; + action.code=(*tralist)->code; + action.remoteip=(*tralist)->remoteip; + action.reverse=(*tralist)->reverse; + action.sfrom=(*tralist)->sfrom; + action.hfrom=(*tralist)->hfrom; + action.hsubject=(*tralist)->hsubject; + action.rcptto=(*tralist)->rcptto; + action.resp=(*tralist)->resp; + (void) sql_mngact(sqlptr,&action); + num++; + } + tralist++; + } + } +return num; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to select a user from emails tables */ +/* and return contents; */ +/* */ +/********************************************************/ +static _Bool select_user(SQLPTR *sqlptr,char *email,USRTYP **usr) + +{ +#define OPEP "gessql.c:select_user," + +static const char *sel="SELECT * FROM "EMLTBL" WHERE email=%s"; + +//field available in table "emails" +static const FLDTYP usrfield[]={ + {1,"email"}, + {2,"password"}, + {3,"hash"}, + {4,"space"}, + {5,"mxspace"}, + {6,"locked"}, + {0,(char *)0} + }; + +_Bool isok; +USRTYP *locusr; +SQLRES *rs; +register int phase; +register _Bool proceed; + +isok=false; +locusr=(USRTYP *)0; +rs=(SQLRES *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //checking parameters + if ((usr==(USRTYP **)0)||(email==(char *)0)||(strlen(email)==0)) { + (void) rou_alert(0,"%s usr=<%p> or email=<%s> sing (Bug?)",OPEP,usr,email); + phase=999; + } + break; + case 1 : //Selecting user + if ((rs=sql_gettupple(sqlptr,sel,email))==(SQLRES *)0) { + (void) rou_alert(0,"%s Unable to get data for user <%s> (Database?)", + OPEP,email); + phase=999; //user not found within database + } + break; + case 2 : //do we have ONE user + int nbr; + + nbr=sql_getnbrtupple(sqlptr,rs); + switch (nbr) { + case 0 : //No user email found + phase=999; //User name not in database + break; + case 1 : //we have only one record, found user + break; + default : //such case should never ever happen + (void) rou_alert(0,"%s got '%d' users record %s (Database corrupted?)", + OPEP,nbr,"while only 1 is expected"); + phase=999; + break; + } + break; + case 3 : //user data extraction + isok=true; + locusr=(USRTYP *)calloc(1,sizeof(USRTYP)); + for (int i=0;(usrfield[i].name!=(char *)0)&&(isok==true);i++) { + const char *locval; + + if ((locval=sql_getvalue(sqlptr,rs,0,usrfield[i].name))==(const char *)0) + continue; + switch (usrfield[i].num) { + case 1 : //user email + locusr->email=strdup(locval); + break; + case 2 : //User crypted password + locusr->password=strdup(locval); + break; + case 3 : //'email:realm:password' MD5 + locusr->hash=strdup(locval); + break; + case 4 : //user used space + locusr->space=atoi(locval); + break; + case 5 : //user max space available + locusr->mxspace=atoi(locval); + break; + case 6 : //lock status + locusr->lock=atoi(locval); + break; + default : + (void) rou_alert(0,"%s field <%d:%s> not implemented (Bug?)", + OPEP,usrfield[i].num,usrfield[i].name); + locusr=sql_freeusr(locusr); + isok=false; + break; + } + } + break; + default : //SAFE Guard + rs=sql_droptupple(sqlptr,rs); + proceed=false; + break; + } + phase++; + } +*usr=locusr; +return isok; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to delete a remote record from the */ +/* table. */ +/* */ +/********************************************************/ +static _Bool delete_remote(SQLPTR *sqlptr,char *rmtip,SRVTYP *srv) + +{ +#define OPEP "gessql.c:delete_remote," + +static const char *del="DELETE FROM "RMTTBL" WHERE remoteip=%s"; + +_Bool isok; +register int phase; +register _Bool proceed; + +isok=false; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //checking parameters + if (strlen(rmtip)==0) { + (void) rou_alert(0,"%s rmtip=<%s> missing (Bug?)",OPEP,rmtip); + phase=999; + } + break; + case 1 : //Selecting user + if (sql_request(sqlptr,del,rmtip)!=1) { + (void) rou_alert(0,"%s Unable to delete remote_ip <%s> (Database?)", + OPEP,rmtip); + phase=999; //Trouble trouble + } + break; + case 2 : //everything fine + isok=true; + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return isok; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to select a remote server from remotes*/ +/* table and return contents */ +/* */ +/********************************************************/ +static _Bool select_remote(SQLPTR *sqlptr,char *rmtip,SRVTYP **srv) + +{ +#define OPEP "gessql.c:select_remote," + +static const char *sel="SELECT * FROM "RMTTBL" WHERE remoteip=%s"; + +_Bool isok; +SRVTYP *locsrv; +SQLRES *rs; +register int phase; +register _Bool proceed; + +isok=false; +locsrv=(SRVTYP *)0; +rs=(SQLRES *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //checking parameters + if ((srv==(SRVTYP **)0)||(rmtip==(char *)0)||(strlen(rmtip)==0)) { + (void) rou_alert(0,"%s srv=<%p> or rmtip=<%s> missing (Bug?)", + OPEP,srv,rmtip); + phase=999; + } + break; + case 1 : //Selecting user + if ((rs=sql_gettupple(sqlptr,sel,rmtip))==(SQLRES *)0) { + (void) rou_alert(0,"%s Unable to get data for user <%s> (Database?)", + OPEP,rmtip); + phase=999; //user not found within database + } + break; + case 2 : //do we have ONE user + int nbr; + + nbr=sql_getnbrtupple(sqlptr,rs); + switch (nbr) { + case 1 : //we have only one record, found remote + break; + case 0 : //no record found! + default : //such case should never ever happen + (void) rou_alert(0,"%s got '%d' users record %s (Database corrupted?)", + OPEP,nbr,"while only 1 is expected"); + phase=999; + break; + } + break; + case 3 : //user data extraction + isok=true; + locsrv=(SRVTYP *)calloc(1,sizeof(SRVTYP)); + for (int i=0;(usrfield[i].name!=(char *)0)&&(isok==true);i++) { + const char *locval; + + if ((locval=sql_getvalue(sqlptr,rs,0,usrfield[i].name))==(const char *)0) + continue; + switch (usrfield[i].num) { + case 1 : //user remoteip + locsrv->rmtip=strdup(locval); + break; + case 2 : //lastscan + locsrv->lastscan=sql_tounixtime(sqlptr,locval); + break; + case 3 : //last update + locsrv->update=sql_tounixtime(sqlptr,locval); + break; + case 4 : //Number of links + locsrv->links=atoi(locval); + break; + case 5 : //remote server credibility + locsrv->credit=atoi(locval); + break; + case 6 : //scanning status + locsrv->listing=strdup(locval); + break; + case 7 : //scanning status + locsrv->reverse=strdup(locval); + break; + default : + (void) rou_alert(0,"%s field <%d:%s> not implemented (Bug?)", + OPEP,usrfield[i].num,usrfield[i].name); + locsrv=sql_freesrv(locsrv); + isok=false; + break; + } + } + break; + default : //SAFE Guard + rs=sql_droptupple(sqlptr,rs); + proceed=false; + break; + } + phase++; + } +*srv=locsrv; +return isok; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to select a remote server from remotes*/ +/* table and update contents */ +/* */ +/********************************************************/ +static _Bool update_remote(SQLPTR *sqlptr,char *rmtip,SRVTYP *srv) + +{ +#define OPEP "gessql.c:update_remote," + +static const char *upd= "UPDATE "RMTTBL" SET " + "lastscan='%s',lastupdate='%s'," + "credit=%d,listing=%s,reverse=%s " + "WHERE remoteip='%s'"; + +_Bool isok; +char *lastscan; +char *update; +char *listing; +char *reverse; + +isok=true; +lastscan=sql_fromunixtime(sqlptr,srv->lastscan); +update=sql_fromunixtime(sqlptr,srv->update); +listing=sql_gooddata(sqlptr,srv->listing); +reverse=sql_gooddata(sqlptr,srv->reverse); +if (sql_request(sqlptr,upd,lastscan,update,srv->credit,listing,reverse,srv->rmtip)!=1) { + (void) rou_alert(0,"%s Unable to update remote_ip <%s> (Database?)", + OPEP,srv->rmtip); + isok=false; + } +reverse=rou_freestr(reverse); +listing=rou_freestr(listing); +update=rou_freestr(update); +lastscan=rou_freestr(lastscan); +return isok; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to update a session contents */ +/* */ +/********************************************************/ +static _Bool update_ses(SQLPTR *sqlptr,char *seskey,SESTYP **ses) + +{ +#define OPEP "devseql.c:update_ses," + +static const char *upd="UPDATE "SESTBL" set %s WHERE sessid=%s"; + +//field available in table "sessions" +static const FLDTYP sesfield[]={ + {0,"sessid"}, + {1,"sesstitle"}, + {2,"sessfrom"}, + {3,"emailfrom"}, + {4,"taille"}, + {5,"duration"}, + {6,(char *)0} + }; + +_Bool isok; +char *cmtset; + +isok=true; +cmtset=strdup(""); +for (int i=0;(isok==true)&&(sesfield[i].name!=(char *)0);i++) { + char *data; + char items[50]; + + data=(char *)0; + (void) strcpy(items,""); + switch (sesfield[i].num) { + case 0 : //session ID + break; //nothing to do + case 1 : //title + data=sql_gooddata(sqlptr,(*ses)->hsubject); + break; //nothing to do + case 2 : //sfrom + data=sql_gooddata(sqlptr,(*ses)->sfrom); + break; //nothing to do + case 3 : //efrom + data=sql_gooddata(sqlptr,(*ses)->hfrom); + break; + case 4 : //taille + (void) rou_asprintf(&data,"%lu",(*ses)->taille); + break; + case 5 : //duration + data=sql_gooddata(sqlptr,(*ses)->duration); + break; + default : + isok=false; + (void) rou_alert(0,"%s Unexpected field <%s> (Bug?)",OPEP,sesfield[i]); + break; + } + if (data!=(char *)0) { + char *newset; + char *sep; + + newset=(char *)0; + sep=""; + if (strlen(cmtset)>0) + sep=","; + (void) rou_asprintf(&newset,"%s%s%s=%s",cmtset,sep,sesfield[i].name,data); + cmtset=rou_freestr(cmtset); + cmtset=newset; + data=rou_freestr(data); + } + } +if (isok==true) + isok=(sql_request(sqlptr,upd,cmtset,seskey)==1); +cmtset=rou_freestr(cmtset); +return isok; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to retreive information about user */ +/* known within database. */ +/* */ +/********************************************************/ +PUBLIC _Bool sql_mngusr(SQLPTR *sqlptr,SQLENUM action,char *key,USRTYP **usr) + +{ +#define OPEP "gessql.c:sql_mngusr," + +_Bool isok; +char *gooddata; +int phase; +_Bool proceed; + +isok=false; +gooddata=(char *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //checking SQL and user record + if (sqlptr==(SQLPTR *)0) { + (void) rou_alert(0,"%s SQL pointer is NULL (Bug?)",OPEP); + phase=999; + } + if (usr==(USRTYP **)0) { + (void) rou_alert(0,"%s USER pointer is NULL (Bug?)",OPEP); + phase=999; + } + break; + case 1 : //do we have a good key + if ((gooddata=sql_gooddata(sqlptr,key))==(char *)0) { + (void) rou_alert(0,"%s %s table, key <%s> is empty (Bug?!)", + OPEP,EMLTBL,key); + phase=999; + } + break; + case 2 : //getting user information + switch (action) { + case sql_select : + isok=select_user(sqlptr,gooddata,usr); + break; + default : + (void) rou_alert(0,"%s action='%d' not yet implemented!",OPEP,action); + } + gooddata=rou_freestr(gooddata); + break; + default : + proceed=false; + break; + } + phase++; + } +return isok; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to manage information about email */ +/* exchange session. */ +/* */ +/********************************************************/ +PUBLIC _Bool sql_mngses(SQLPTR *sqlptr,SQLENUM action,SESTYP **ses) + +{ +#define OPEP "gessql.c:sql_mngses," + +static const char *ins="INSERT INTO "SESTBL" (sessid) VALUES(%s)"; + +_Bool isok; +char *gooddata; +int phase; +_Bool proceed; + +isok=false; +gooddata=(char *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //checking SQL + if ((sqlptr==(SQLPTR *)0)||(ses==(SESTYP **)0)||(*ses==(SESTYP *)0)) { + (void) rou_alert(0,"%s SQL pointer is NUll (Bug?)",OPEP); + phase=999; + } + if ((gooddata=sql_gooddata(sqlptr,(*ses)->sessid))==(char *)0) { + (void) rou_alert(0,"%s %s table, key <%s> is empty (Bug?!)", + OPEP,SESTBL,(*ses)->sessid); + phase=999; + } + break; + case 1 : //getting user information + switch (action) { + case sql_insert : + isok=(sql_request(sqlptr,ins,gooddata)==1); + break; + case sql_update : + isok=update_ses(sqlptr,gooddata,ses); + break; + default : + (void) rou_alert(0,"%s action='%d' not yet implemented! (BUG?)", + OPEP,action); + } + gooddata=rou_freestr(gooddata); + break; + default : + proceed=false; + break; + } + phase++; + } +return isok; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to increase (of decrease the remote */ +/* IP connection number. */ +/* */ +/********************************************************/ +PUBLIC int sql_newconnect(SQLPTR *sqlptr,char *rmtip,int delta) + +{ +#define OPEP "gessql.c:sql_newconnect," + +static const char *sel="SELECT * FROM %s WHERE remoteip='%s' FOR UPDATE"; +static const char *upd="UPDATE %s SET links=links+%d,lastupdate=now() WHERE remoteip='%s'"; +static const char *ins="INSERT INTO %s (remoteip) values('%s')"; + +int connect; +SQLRES *sqlres; +SRVTYP *srv; +int phase; +_Bool proceed; + +connect=-1; +srv=(SRVTYP *)0; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"%s JMPDBG phase='%d' connect=%d",OPEP,phase,connect); + switch (phase) { + case 0 : //lets lock table access + if (sql_lock(sqlptr,RMTTBL)==false) { + (void) rou_alert(0,"%s Unable to lock %s table",OPEP,RMTTBL); + phase=999; //Unable to lock table!!!! + } + break; + case 1 : //updating remotes record with links + if ((sqlres=sql_gettupple(sqlptr,sel,RMTTBL,rmtip))==(SQLRES *)0) { + (void) rou_alert(0,"%s Unable to get tupple for remote ip <%s> " + "in table <%s> (DB trouble?)", + OPEP,rmtip,RMTTBL); + phase=999; //no tupple information? + } + break; + case 2 : //is record already existing + if (sql_getnbrtupple(sqlptr,sqlres)==1) { + phase++; //No need to create it + } + sqlres=sql_droptupple(sqlptr,sqlres); + break; + case 3 : //Let create a new unique record + if (sql_request(sqlptr,ins,RMTTBL,rmtip)!=1) { + (void) rou_alert(0,"%s Unable to create entry " + "for remote ip <%s> in table <%s> (DB trouble?)", + OPEP,rmtip,RMTTBL); + (void) sql_unlock(sqlptr,true); + phase=999; + } + else + phase++; //record open + break; + case 4 : //lets update link + if (sql_request(sqlptr,upd,RMTTBL,delta,rmtip)!=1) { + (void) rou_alert(0,"%s Unable to update entry " + "for remote ip <%s> in table <%s> (DB trouble?)", + OPEP,rmtip,RMTTBL); + } + break; + case 5 : //lets find the the number of connection + if (sql_mngremote(sqlptr,sql_select,rmtip,&srv)==false) { + (void) rou_alert(0,"%s Unable to get record " + "for remote ip <%s> in table <%s> (DB trouble?)", + OPEP,rmtip,RMTTBL); + } + else { + connect=srv->links; + srv=sql_freesrv(srv); + } + break; + case 6 : //unlock database + (void) sql_unlock(sqlptr,true); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return connect; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to retreive information about remote */ +/* server and get how reliable/trustable it is. */ +/* */ +/********************************************************/ +PUBLIC _Bool sql_mngremote(SQLPTR *sqlptr,SQLENUM action,char *key,SRVTYP **srv) + +{ +#define OPEP "gessql.c:sql_mnremote," + +_Bool isok; +char *gooddata; +int phase; +_Bool proceed; + +isok=false; +gooddata=(char *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //checking SQL and user record + if (sqlptr==(SQLPTR *)0) { + (void) rou_alert(0,"%s SQL pointer is NULL (Bug?)",OPEP); + phase=999; + } + if (srv==(SRVTYP **)0) { + (void) rou_alert(0,"%s USER pointer is NULL (Bug?)",OPEP); + phase=999; + } + break; + case 1 : //do we have a good key + if ((gooddata=sql_gooddata(sqlptr,key))==(char *)0) { + (void) rou_alert(0,"%s %s table, key <%s> is empty (Bug?!)", + OPEP,EMLTBL,key); + phase=999; + } + break; + case 2 : //getting user information + switch (action) { + case sql_select : + isok=select_remote(sqlptr,gooddata,srv); + break; + case sql_update : + isok=update_remote(sqlptr,gooddata,*srv); + break; + case sql_delete : + isok=delete_remote(sqlptr,gooddata,*srv); + break; + default : + (void) rou_alert(0,"%s action='%d' not yet implemented!",OPEP,action); + break; + } + gooddata=rou_freestr(gooddata); + break; + default : + proceed=false; + break; + } + phase++; + } +return isok; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to retreive a list of newly connected */ +/* remote IP to be scanned to establish credibilty.*/ +/* */ +/********************************************************/ +PUBLIC char **sql_getnewrmtip(SQLPTR *sqlptr,int delay) + +{ +#define OPEP "gessql.c:sql_getnewrmtip," + +static char *cmd="select remoteip from "RMTTBL" WHERE " + "(lastscan + +#include "unieml.h" +#include "devsql.h" + +//procedure to update actions table within database +extern _Bool sql_mngact(SQLPTR *sqlptr,ACTTYP *act); + +//procedure to remove ALL link counts within the remotes tables +extern void sql_droplinks(SQLPTR *sqlptr); + +//procedure to update transaction information +extern int sql_update_tradb(SQLPTR *sqlptr,TRATYP **tralist); + +//procedure to manage information on exiting user +extern _Bool sql_mngusr(SQLPTR *sqlptr,SQLENUM action,char *key,USRTYP **usr); + +//procedure to manage information on email exchange session +extern _Bool sql_mngses(SQLPTR *sqlptr,SQLENUM action,SESTYP **ses); + +//Procedure to increment (or decrement) the remoteip links number +extern int sql_newconnect(SQLPTR *sqlptr,char *rmtip,int delta); + +//procedure to extract the information about remotes server +extern _Bool sql_mngremote(SQLPTR *sqlptr,SQLENUM action,char *key,SRVTYP **srv); + +//procedure to collect a list of "to be checked" remote IP +extern char **sql_getnewrmtip(SQLPTR *sqlptr,int frequency); + +//procedure to create a new event entry +extern int sql_addevent(SQLPTR *sqlptr,char *session,int debut,int fin); + +#endif diff --git a/lib/gestcp.c b/lib/gestcp.c new file mode 100644 index 0000000..f89a5e6 --- /dev/null +++ b/lib/gestcp.c @@ -0,0 +1,293 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Module to manage TCP communication */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "unieml.h" +#include "unisig.h" +#include "uniprc.h" +#include "gestcp.h" + +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to add a line to a TCP buffer */ +/* return the a point to the new busffer */ +/* */ +/********************************************************/ +PUBLIC char *tcp_addline(char *buffer,char *line) + +{ +register int taille; + +taille=0; +if (strlen(line)>0) { + taille=strlen(line)+strlen(CRLF)+3; + if (buffer==(char *)0) + buffer=(char *)calloc(taille,sizeof(char)); + taille+=strlen(buffer); + buffer=realloc(buffer,taille); + (void) strcat(buffer,line); + (void) strcat(buffer,CRLF); + } +return buffer; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to read char from remote peer, wait */ +/* for a CRLF AS EOL. */ +/* - Return "got", which could be: */ +/* - a positive number of character read. */ +/* - 0, reading reach time out */ +/* - -1, signal received */ +/* - -2, remote disconnect */ +/* */ +/********************************************************/ +PUBLIC int tcp_getline(SOCPTR *socptr,u_int secwait,char **lineptr) + +{ +#define OPEP "gestcp.c:tcp_getline" + +int got; +int phase; +_Bool proceed; + +got=0; +phase=0; +proceed=true; +while (proceed==true) { + (void) rou_dbglive(9,OPEP,"phase='%d' line=<%s>",phase,*lineptr); + switch (phase) { + case 0 : //link still open? + if (soc_receive(socptr)<0) { + got=-2; + phase=999; + } + break; + case 1 : //get nextline if ready + if ((got=soc_getnextline(socptr,lineptr))>=0) + phase=999; //we got a line. + break; + case 2 : //lets wait secwait*1000 millisec for input + got=soc_waitforchar(socptr,secwait*1000); + switch (got) { + case -2 : //remote is disconnectd + (void) rou_alert(0,"%s remote found disconnected",OPEP); + break; + case -1 : //trouble? signal? + if ((hangup==true)||(reload==true)) + phase=999; //we got a real signal + break; + case 0 : //normal time out + got=soc_receive(socptr); + phase=999; + break; + default : //char available + phase=0; //is new line ready? + break; + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return got; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to write a string on the socket output*/ +/* return the number of char sent on channel. */ +/* */ +/********************************************************/ +PUBLIC int tcp_write(SOCPTR *socptr,char *buffer) + +{ +int sent; + +sent=-1; +if (socptr!=(SOCPTR *)0) { + int taille; + + taille=strlen(buffer); + if (taille>0) + sent=soc_writebuffer(socptr,buffer,taille); + //(void) rou_alert(0,"tcp_write,JMPDBG <%s>",buffer); + } +return sent; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to wait answer from remote and log */ +/* all answer from remote. */ +/* return an SMTP reply code. */ +/* */ +/********************************************************/ +PUBLIC int tcp_get_smtp_reply(RMTTYP *rmt,int wait,char ***resp) + +{ +#define OPEP "gestcp.c:tcp_get_smtp_reply," + +int code; +int maxlines; + +code=ERRPROC; +maxlines=20; //maximun number of line error +if (debug>0) + wait/=10; //debug mode not waiting for long +while (maxlines>0) { + char *line; + int sofar; + + line=(char *)0; + if (tcp_getline(rmt->socptr,wait,&line)<=0) { + char cmt[100]; + + (void) snprintf(cmt,sizeof(cmt),"%d Timeout waiting '%d' sec for MX <%s>", + ERRPROC,wait,rmt->curmx->mxname); + line=strdup(cmt); + } + (void) log_fprintlog(rmt->logptr,true,line); + if (sscanf(line,"%d%n",&code,&sofar)==1) { + if (line[sofar]==' ') + maxlines=0; //found remote status + else + code=ERRPROC; + } + if (resp==(char ***)0) + line=rou_freestr(line); + else + *resp=(char **)rou_addlist((void **)*resp,(void *)line); + maxlines--; + } +return code; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to build a command and send it to */ +/* remote server, log request and return the */ +/* remote response code. */ +/* */ +/********************************************************/ +PUBLIC int tcp_smtp_command(RMTTYP *rmt,char ***resp,char *fmt,...) + +{ +va_list args; +char strloc[300]; + +va_start(args,fmt); +(void) vsnprintf(strloc,sizeof(strloc)-4,fmt,args); +va_end(args); +(void) log_fprintlog(rmt->logptr,false,strloc); +(void) strcat(strloc,CRLF); +(void) tcp_write(rmt->socptr,strloc); +return tcp_get_smtp_reply(rmt,WAITRMT,resp); +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to send a queued email data contents */ +/* to a remote server. */ +/* Return the number of character sent. */ +/* */ +/********************************************************/ +PUBLIC int tcp_send_smtp_data(RMTTYP *rmt,const char *qemail) + +{ +#define OPEP "gestcpc.c:tcp_send_smtp_data," +#define ENDDATA "."CRLF + +int sent; +FILE *qfile; +int phase; +_Bool proceed; + +sent=-1; +qfile=(FILE *)0; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //opending email data file + if ((qfile=eml_openqfile(qemail,(const char *)0))==(FILE *)0) { + (void) rou_alert(0,"%s, Unable to open file <%s> (bug?)", + OPEP,qemail); + phase=999; //no need to go further + } + break; + case 1 : { //transmitting data to remote + char data[300]; + + sent=0; + while (fgets(data,sizeof(data)-4,qfile)!=(char *)0) { + do { + register int taille; + register char *ptr; + + taille=strlen(data)-1; + if (taille<0) + break; + ptr=data+taille; + if ((*ptr!='\n')&&(*ptr!='\r')) + break; //Line too long! + *ptr='\000'; + } + while (strlen(data)>0); + //dot escape + if ((strlen(data)>0)&&(data[0]=='.')) + (void) memmove(data+1,data,strlen(data)); + (void) strcat(data,CRLF); + sent+=tcp_write(rmt->socptr,data); + } + break; + } + case 2 : //end of transmission + sent+=tcp_write(rmt->socptr,ENDDATA); + break; + case 3 : //closing datafile + qfile=eml_closeqfile(qfile); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return sent; + +#undef ENDDATA +#undef OPEP +} diff --git a/lib/gestcp.d b/lib/gestcp.d new file mode 100644 index 0000000..05d67dd --- /dev/null +++ b/lib/gestcp.d @@ -0,0 +1,121 @@ +gestcp.o gestcp.d : gestcp.c /usr/include/stdc-predef.h /usr/include/sys/wait.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/signal.h \ + /usr/include/bits/signum-generic.h /usr/include/bits/signum-arch.h \ + /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timespec.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/types/stack_t.h /usr/include/sys/ucontext.h \ + /usr/include/bits/sigstack.h /usr/include/bits/sigstksz.h \ + /usr/include/bits/ss_flags.h /usr/include/bits/types/struct_sigstack.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/bits/types/idtype_t.h \ + /usr/include/sys/socket.h /usr/include/bits/types/struct_iovec.h \ + /usr/include/bits/socket.h /usr/include/sys/types.h \ + /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/byteswap.h \ + /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/socket_type.h /usr/include/bits/sockaddr.h \ + /usr/include/asm/socket.h /usr/include/asm-generic/socket.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h /usr/include/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/asm/sockios.h \ + /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/fcntl.h \ + /usr/include/bits/fcntl.h /usr/include/bits/fcntl-linux.h \ + /usr/include/bits/stat.h /usr/include/bits/struct_stat.h \ + /usr/include/netdb.h /usr/include/netinet/in.h \ + /usr/include/bits/stdint-uintn.h /usr/include/bits/in.h \ + /usr/include/rpc/netdb.h /usr/include/bits/netdb.h /usr/include/poll.h \ + /usr/include/sys/poll.h /usr/include/bits/poll.h /usr/include/stdlib.h \ + /usr/include/bits/libc-header-start.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/stdio.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/string.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/strings.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h unieml.h \ + subafn.h unisig.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h uniprc.h gestcp.h unidns.h \ + devlog.h devsoc.h unitls.h /usr/include/openssl/ssl.h \ + /usr/include/openssl/macros.h /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/configuration.h /usr/include/openssl/opensslv.h \ + /usr/include/openssl/e_os2.h /usr/include/inttypes.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdint.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/bits/stdint-least.h /usr/include/openssl/e_ostime.h \ + /usr/include/sys/time.h /usr/include/openssl/comp.h \ + /usr/include/openssl/crypto.h /usr/include/openssl/safestack.h \ + /usr/include/openssl/stack.h /usr/include/openssl/types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/limits.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h /usr/include/bits/posix2_lim.h \ + /usr/include/openssl/cryptoerr.h /usr/include/openssl/symhacks.h \ + /usr/include/openssl/cryptoerr_legacy.h /usr/include/openssl/core.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include-fixed/pthread.h \ + /usr/include/sched.h /usr/include/bits/sched.h \ + /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \ + /usr/include/bits/setjmp.h \ + /usr/include/bits/types/struct___jmp_buf_tag.h \ + /usr/include/openssl/comperr.h /usr/include/openssl/bio.h \ + /usr/include/openssl/bioerr.h /usr/include/openssl/x509.h \ + /usr/include/openssl/buffer.h /usr/include/openssl/buffererr.h \ + /usr/include/openssl/evp.h /usr/include/openssl/core_dispatch.h \ + /usr/include/openssl/indicator.h /usr/include/openssl/params.h \ + /usr/include/openssl/bn.h /usr/include/openssl/bnerr.h \ + /usr/include/openssl/evperr.h /usr/include/openssl/objects.h \ + /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \ + /usr/include/openssl/asn1err.h /usr/include/openssl/objectserr.h \ + /usr/include/openssl/ec.h /usr/include/openssl/ecerr.h \ + /usr/include/openssl/rsa.h /usr/include/openssl/rsaerr.h \ + /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \ + /usr/include/openssl/dherr.h /usr/include/openssl/dsaerr.h \ + /usr/include/openssl/sha.h /usr/include/openssl/x509err.h \ + /usr/include/openssl/x509_vfy.h /usr/include/openssl/lhash.h \ + /usr/include/openssl/pkcs7.h /usr/include/openssl/pkcs7err.h \ + /usr/include/openssl/http.h /usr/include/openssl/conf.h \ + /usr/include/openssl/conferr.h /usr/include/openssl/conftypes.h \ + /usr/include/openssl/pem.h /usr/include/openssl/pemerr.h \ + /usr/include/openssl/hmac.h /usr/include/openssl/async.h \ + /usr/include/openssl/asyncerr.h /usr/include/openssl/ct.h \ + /usr/include/openssl/cterr.h /usr/include/openssl/sslerr.h \ + /usr/include/openssl/sslerr_legacy.h /usr/include/openssl/prov_ssl.h \ + /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \ + /usr/include/openssl/tls1.h /usr/include/openssl/dtls1.h \ + /usr/include/openssl/srtp.h /usr/include/openssl/quic.h diff --git a/lib/gestcp.h b/lib/gestcp.h new file mode 100644 index 0000000..af3b656 --- /dev/null +++ b/lib/gestcp.h @@ -0,0 +1,46 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/************************************************/ +/* */ +/* gestion level to handle TCP */ +/* communication */ +/* */ +/************************************************/ +#ifndef GESTCP +#define GESTCP + +#include + +#include "subrou.h" +#include "unidns.h" +#include "devlog.h" +#include "devsoc.h" + +//structure handling remote +typedef struct { + SOCPTR *socptr; //socket to remote pointer + LOGPTR *logptr; //Log pointer + char *orgdomain; //originator domain + char *dstdomain; //Domain to be reached + MXTYP *curmx; //Current MX number + MXTYP **mxs; //MX list form domain + }RMTTYP; + +//procedure to add a line to a buffer +extern char *tcp_addline(char *buffer,char *line); + +//read a line from contact up to CRLF +extern int tcp_getline(SOCPTR *socptr,u_int secwait,char **lineptr); + +//Transmit formated data to the contact channel +extern int tcp_write(SOCPTR *socptr,char *buffer); + +//wait and answer from remote and return the reply code +extern int tcp_get_smtp_reply(RMTTYP *rmt,int wait,char ***resp); + +//Transmit a command to remote SMTP server +extern int tcp_smtp_command(RMTTYP *rmt,char ***resp,char *fmt,...); + +//send the email data +extern int tcp_send_smtp_data(RMTTYP *rmt,const char *qemail); + +#endif diff --git a/lib/lvleml.c b/lib/lvleml.c new file mode 100644 index 0000000..97085e7 --- /dev/null +++ b/lib/lvleml.c @@ -0,0 +1,3197 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Implement all routine to manage SMTP low level */ +/* exchange. */ +/* */ +/********************************************************/ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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;ifqdn=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 +} +/* + +*/ +/************************************************/ +/* */ +/* 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 +} +/* + +*/ +/************************************************/ +/* */ +/* 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; +} +/* + +*/ +/************************************************/ +/* */ +/* 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); +} +/* + +*/ +/************************************************/ +/* */ +/* Procedure to accept EMAIL contents from */ +/* SMTP peers. */ +/* Return true, if everything is fine */ +/* */ +/************************************************/ +//NOTE +//MAIL FROM [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 ."); + 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 +} +/* + +*/ +/************************************************/ +/* */ +/* 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 +} +/* + +*/ +/************************************************/ +/* */ +/* 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 +} +/* + +*/ +/************************************************/ +/* */ +/* 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 +/* + +*/ +/************************************************/ +/* */ +/* 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 +} +/* + +*/ +/************************************************/ +/* */ +/* 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 +} +/* + +*/ +/************************************************/ +/* */ +/* 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); +} +/* + +*/ +/************************************************/ +/* */ +/* 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'; +} + diff --git a/lib/lvleml.d b/lib/lvleml.d new file mode 100644 index 0000000..37b40a1 --- /dev/null +++ b/lib/lvleml.d @@ -0,0 +1,119 @@ +lvleml.o lvleml.d : lvleml.c /usr/include/stdc-predef.h /usr/include/arpa/inet.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/netinet/in.h /usr/include/bits/stdint-uintn.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/sys/socket.h \ + /usr/include/bits/types/struct_iovec.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/socket.h /usr/include/sys/types.h \ + /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/time_t.h /usr/include/bits/types/timer_t.h \ + /usr/include/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/endianness.h \ + /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/bits/socket_type.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm-generic/socket.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h /usr/include/asm/posix_types.h \ + /usr/include/asm/posix_types_64.h /usr/include/asm-generic/posix_types.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/bits/in.h \ + /usr/include/ctype.h /usr/include/bits/types/locale_t.h \ + /usr/include/bits/types/__locale_t.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/netdb.h \ + /usr/include/rpc/netdb.h /usr/include/bits/netdb.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/stdlib.h /usr/include/bits/libc-header-start.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/bits/floatn.h /usr/include/bits/floatn-common.h \ + /usr/include/alloca.h /usr/include/bits/stdlib-float.h \ + /usr/include/stdio.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/string.h \ + /usr/include/strings.h /usr/include/signal.h \ + /usr/include/bits/signum-generic.h /usr/include/bits/signum-arch.h \ + /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h /usr/include/bits/types/stack_t.h \ + /usr/include/sys/ucontext.h /usr/include/bits/sigstack.h \ + /usr/include/bits/sigstksz.h /usr/include/bits/ss_flags.h \ + /usr/include/bits/types/struct_sigstack.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h /usr/include/time.h \ + /usr/include/bits/time.h /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h subafn.h \ + subrou.h /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + subcnv.h unidig.h unieml.h uniprc.h devlog.h gestcp.h unidns.h devsoc.h \ + unitls.h /usr/include/openssl/ssl.h /usr/include/openssl/macros.h \ + /usr/include/openssl/opensslconf.h /usr/include/openssl/configuration.h \ + /usr/include/openssl/opensslv.h /usr/include/openssl/e_os2.h \ + /usr/include/inttypes.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdint.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/bits/stdint-least.h /usr/include/openssl/e_ostime.h \ + /usr/include/sys/time.h /usr/include/openssl/comp.h \ + /usr/include/openssl/crypto.h /usr/include/openssl/safestack.h \ + /usr/include/openssl/stack.h /usr/include/openssl/types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/limits.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h /usr/include/bits/posix2_lim.h \ + /usr/include/openssl/cryptoerr.h /usr/include/openssl/symhacks.h \ + /usr/include/openssl/cryptoerr_legacy.h /usr/include/openssl/core.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include-fixed/pthread.h \ + /usr/include/sched.h /usr/include/bits/sched.h \ + /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \ + /usr/include/bits/setjmp.h \ + /usr/include/bits/types/struct___jmp_buf_tag.h \ + /usr/include/openssl/comperr.h /usr/include/openssl/bio.h \ + /usr/include/openssl/bioerr.h /usr/include/openssl/x509.h \ + /usr/include/openssl/buffer.h /usr/include/openssl/buffererr.h \ + /usr/include/openssl/evp.h /usr/include/openssl/core_dispatch.h \ + /usr/include/openssl/indicator.h /usr/include/openssl/params.h \ + /usr/include/openssl/bn.h /usr/include/openssl/bnerr.h \ + /usr/include/openssl/evperr.h /usr/include/openssl/objects.h \ + /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \ + /usr/include/openssl/asn1err.h /usr/include/openssl/objectserr.h \ + /usr/include/openssl/ec.h /usr/include/openssl/ecerr.h \ + /usr/include/openssl/rsa.h /usr/include/openssl/rsaerr.h \ + /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \ + /usr/include/openssl/dherr.h /usr/include/openssl/dsaerr.h \ + /usr/include/openssl/sha.h /usr/include/openssl/x509err.h \ + /usr/include/openssl/x509_vfy.h /usr/include/openssl/lhash.h \ + /usr/include/openssl/pkcs7.h /usr/include/openssl/pkcs7err.h \ + /usr/include/openssl/http.h /usr/include/openssl/conf.h \ + /usr/include/openssl/conferr.h /usr/include/openssl/conftypes.h \ + /usr/include/openssl/pem.h /usr/include/openssl/pemerr.h \ + /usr/include/openssl/hmac.h /usr/include/openssl/async.h \ + /usr/include/openssl/asyncerr.h /usr/include/openssl/ct.h \ + /usr/include/openssl/cterr.h /usr/include/openssl/sslerr.h \ + /usr/include/openssl/sslerr_legacy.h /usr/include/openssl/prov_ssl.h \ + /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \ + /usr/include/openssl/tls1.h /usr/include/openssl/dtls1.h \ + /usr/include/openssl/srtp.h /usr/include/openssl/quic.h gessql.h \ + devsql.h unisql.h geseml.h lvleml.h gesspf.h diff --git a/lib/lvleml.h b/lib/lvleml.h new file mode 100644 index 0000000..c5b3d8e --- /dev/null +++ b/lib/lvleml.h @@ -0,0 +1,74 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Define all routine to manage SMTP high level */ +/* exchange. */ +/* */ +/********************************************************/ +#ifndef LVLEML +#define LVLEML + +#include + +#include "devsoc.h" +#include "devsql.h" +#include "gestcp.h" +#include "gesspf.h" +#include "geseml.h" + +typedef struct { + SOCPTR *socptr; //established contact socket context + SQLPTR *sqlptr; //established contact database access + int delay; //communication max delay + _Bool isgoodfqdn; //Remote presented a valid fqdn + char *fqdn; //fully qualified domain from peer + int credit; //Credits to be added or removed from contact + RELTYP privilege; //onnection privilege + char *authname; //Link is authenticated name + AFNTYP **localafns; //local IP as an AFNUM + char *locip; //socket local IP num + char *locname; //socket local hostname + char *locserv; //local service port + char *peername; //socket remote peer FQDN + char *peerip; //socket remote peer IP + AFNTYP **relayok; //List of IP which are relayable + int numreset; //number of SMTP reset received + char *mainsesid; //session main ID + char *termend; //contact ending condition + SESTYP *session; //SMTP current session information + char *mailfrom; //current mail from originator + SPFENU fromspf; //remote email SPF status + RCPTYP **recipients; //List of email recipient + LOGPTR *logptr; //reference to session log + char *transout; //data to be flush out to remote + }CONTYP; + + +//Procedure to transmit data on the contact channel +extern void eml_transmit(CONTYP *contact,_Bool flush,const char *fmt,...); + +//To store connection status and transmit action code to remote +extern void eml_note(CONTYP *contact,char *rcpt,const char *fmt,...); + +//procedure to extract line and proceed with peer contact +extern int eml_docontact(CONTYP *contact); + +//wait for an incoming contact +extern CONTYP *eml_getcontact(SOCPTR *socptr,int pos); + +//drop contact established by remote +extern CONTYP *eml_dropcontact(CONTYP *contact); + +//generate trans file contents +extern _Bool eml_mktransfile(CONTYP *contact,FILE *qfile); + +//store local email within domain proper directory +extern void eml_local_email(TRATYP **tra); + +//sending email to remote recipents +extern void eml_remote_email(TRATYP **tra); + +//Rebouncing Email to the first originator +extern void eml_rebounce_email(TRATYP *tra); + +#endif diff --git a/lib/modrec.c b/lib/modrec.c new file mode 100644 index 0000000..dfc5f7e --- /dev/null +++ b/lib/modrec.c @@ -0,0 +1,516 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Module to handle all email incoming */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "uniprc.h" +#include "unieml.h" +#include "unisig.h" +#include "devsoc.h" +#include "gessql.h" +#include "gestcp.h" +#include "lvleml.h" +#include "modrec.h" + +//env variable to set the rejection level +#define ENVRJCT "RJCTCRED" +#define DFLTRJCT -50 //default reject max level +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to returne the local argv */ +/* */ +/********************************************************/ +static char **getconfargv() + +{ +char **confargv; +char *data; +char *conf; + +confargv=(char **)0; +conf=(char *)0; +if ((conf=getenv("SMTPPORTS"))!=(char *)0) + conf=strdup(conf); +data=conf; +while (data!=(char *)0) { + char *ptr; + char *seg; + + if ((ptr=strchr(data,','))!=(char *)0) { + *ptr='\000'; + ptr++; + } + seg=strdup(data); + confargv=(char **)rou_addlist((void **)confargv,(void *)seg); + data=ptr; + } +conf=rou_freestr(conf); +return confargv; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to scan argument and generate binding */ +/* information. */ +/* build a SOCPTR list and return the number of */ +/* entries. */ +/* */ +/* Possible argument format are: */ +/* protocol:ipnum:port:iteration */ +/* example: */ +/* |ipnum||| -> smtp|ipnum|25|1 */ +/* smtps|ipnum|465|2 */ +/* -> smtps protocol,port 465,2 iteration */ +/* */ +/********************************************************/ +static int prepbinding(SOCPTR ***bindings,int argc,char *argv[]) + +{ +#define OPEP "moderec.c:prepbinding" +#define DFLTSET "smtp|0.0.0.0|25|2" +#define DIP "0.0.0.0" +#define DPORT "25" + +char *locargv[2]; + +(void) memset(locargv,'\000',sizeof(locargv)); +*bindings=(SOCPTR **)0; +if (argc==0) { + argc=1; + locargv[0]=DFLTSET; //very last default configuration + argv=locargv; + } +for (int i=0;i", + OPEP,argv[i]); + proto=pro_smtp; + } + break; + case 1 : + if (strlen(ptr)>0) + ipnum=ptr; + //(void) rou_alert(0,"%s JMPDBG ipnum=[%s]",OPEP,ipnum); + break; + case 2 : + if (strlen(ptr)>0) + port=ptr; + if (strlen(sofar)>0) + iteration=atoi(sofar); + break; + default : + (void) rou_alert(0,"%s, Code fault, '%d' unexpected value",OPEP,j); + break; + } + ptr=sofar; + } + *bindings=soc_mkbindinf(*bindings,proto,ipnum,port,iteration); + } +return rou_nbrlist(*bindings); + +#undef DPORt +#undef DIP +#undef DFLSET +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to detect and accept a contact from */ +/* a remote TCP connection. */ +/* */ +/********************************************************/ +static void docontact(SOCPTR *socptr,int pos) + +{ +#define OPEP "modrec.c:docontact" + +CONTYP *contact; +int intstat; +int phase; +_Bool proceed; + +contact=(CONTYP *)0; +intstat=0; +phase=0; +proceed=true; +while (proceed==true) { + (void) rou_dbglive(9,OPEP,"phase='%d'",phase); + switch (phase) { + case 0 : //waiting contact + if ((contact=eml_getcontact(socptr,pos))==(CONTYP *)0) + phase=999; //No contact! + break; + case 1 : //check if remote link is acceptable + if (sql_newconnect(contact->sqlptr,contact->peerip,1)!=1) { + char *end; + + end="Found ip=[%s] already connected"; + (void) rou_asprintf(&(contact->termend),end,contact->peerip); + end="You have another connection still in progress"; + (void) eml_note(contact,NULL,"%d 6.6.5 contact denied <%s>",NOTNOW,end); + (void) eml_transmit(contact,true,"%d 6.6.5 contact denied <%s>",NOTNOW,end); + contact->credit=-1; //small penalty + (void) sleep(1); //To avoid avalanche + phase=999; //no Need to go further + } + break; + case 2 : { //checking remote credit + static char *cmt="Remote server credit too low"; + int reject; + char *ptr; + SRVTYP *srv; + + reject=DFLTRJCT; + if ((ptr=getenv(ENVRJCT))!=(char *)0) + reject=atoi(ptr); + if (sql_mngremote(contact->sqlptr,sql_select,contact->peerip,&srv)==true) { + if (srv->credit<=reject) { + contact->termend=rou_freestr(contact->termend); + contact->termend=strdup(cmt); + contact->credit=-1; + (void) sleep(2); + (void) eml_note(contact,NULL,"%d remote server, credit (%d) is too low", + DATRJC,srv->credit); + (void) eml_transmit(contact,true,"%d 6.6.6 %s",DATRJC,cmt); + phase=999; //rejecting remote first hand + } + srv=sql_freesrv(srv); + } + } + break; + case 3 : //do contact + intstat=eml_docontact(contact); + switch (intstat) { + case 1 : //command 'quit' recieved + break; + case 0 : //exit under timeout + (void) rou_alert(0,"Contact timeout with peer <%s>",contact->peerip); + break; + case -1 : //Signal received + (void) rou_alert(0,"Signal received within contact"); + break; + case -2 : //Signal received + (void) rou_alert(0,"Remote disconnected"); + break; + default : //trouble trouble + (void) rou_alert(0,"%s Unexpected status='%d' (BUG?!)",OPEP,intstat); + break; + } + break; + default : //SAFE guard + if (contact!=(CONTYP *)0) { + static const char *cmt; + SRVTYP *srv; + + cmt="(Contact terminated, condition=<%s>)"; + if (sql_mngremote(contact->sqlptr,sql_select,contact->peerip,&srv)==true) { + srv=sql_freesrv(srv); + } + (void) log_fprintlog(contact->logptr,true,cmt,contact->termend); + (void) sql_newconnect(contact->sqlptr,contact->peerip,-1); + contact=eml_dropcontact(contact); + } + proceed=false; + break; + } + phase++; + } +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to activate child process if necessary*/ +/* */ +/********************************************************/ +static void setready(SOCPTR *socptr) + +{ +#define OPEP "modrec.c:setready" +#define TSLEEP 5 + +int maxretry; +pid_t *childs; +int iterations; +int phase; +_Bool proceed; + +maxretry=5; +childs=(pid_t *)0; +iterations=soc_getiterations(socptr); +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //empty phase + if (iterations>0) + childs=(pid_t *)calloc(iterations,sizeof(pid_t)); + else + proceed=false; //Empty Soc!?! + break; + case 1 : //empty phase + if (foreground==true) { + (void) docontact(socptr,1); + phase++; //no fork + } + break; + case 2 : //check need to dispatch a process + for (int i=0;ione shot deal + break; + case 4 : //Relax time + phase=0; //lets continue to check childs + (void) rou_alert(10,"%s, start sleep '%d' second",OPEP,TSLEEP); + (void) sleep(TSLEEP); //signal received to exit fast. + if (childout==true) { + (void) rou_alert(9,"%s, Got child out",OPEP); + childout=false; + } + (void) rou_alert(10,"%s, Exit from sleep",OPEP); + if ((hangup==true)||(reload==true)) + phase=999; //exiting under signal + break; + default : //SAFE Guard + (void) prc_killchilds(childs,iterations,maxretry); + (void) free(childs); + proceed=false; + break; + } + phase++; + } +#undef TSLEEP +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to start a binding+waiting process */ +/* */ +/********************************************************/ +static void startwaiter(SOCPTR *socptr) + +{ +#define OPEP "modrec.c:startwaiter" + +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 : //Opening logs + (void) closelog(); + (void) openlog(appname,LOG_NDELAY|LOG_PID,LOG_DAEMON); + break; + case 1 : //binding on channel + if (soc_openbinding(socptr)==false) { + (void) rou_alert(0,"%s Aborting binding (config?)",OPEP); + (void) sleep(5); //to avoid avalanche + phase=999; + } + break; + case 2 : //waiting + (void) rou_alert(0,"JMPDBG waiter starting"); + (void) setready(socptr); + (void) rou_alert(0,"JMPDBG waiter exiting"); + break; + case 3 : //stop binding + (void) soc_closebinding(socptr); + break; + default : //SAFE Guard + (void) closelog(); + proceed=false; + break; + } + phase++; + } +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Waiting and handling smtp request */ +/* */ +/********************************************************/ +PUBLIC void rec_handlesmtp(int argc,char *argv[]) + +{ +#define OPEP "modrec.c:rec_handlesmtp" +#define RELAX 5 //Relax time between process checking + +unsigned long cycle; +pid_t *childs; +char **confargv; +int nbrbind; +_Bool allbusy; +SOCPTR **bindings; +int phase; +_Bool proceed; + +cycle=0; +childs=(pid_t)0; +confargv=getconfargv(); +nbrbind=0; +allbusy=false; +bindings=(SOCPTR **)0; +if (argc==0) { + argc=rou_nbrlist((void **)confargv); + argv=confargv; + } +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //preparing iteration + if ((nbrbind=prepbinding(&bindings,argc,argv))==0) { + (void) rou_alert(0,"%s, No listening IP found (config?)",OPEP); + phase=999; + } + childs=(pid_t *)calloc(nbrbind,sizeof(pid_t)); + break; + case 1 : //Detecting signal + cycle++; + (void) prc_settitle("%s:%s, sleeping mode (cycle=%08d)", + APPNAME,appname,cycle); + if ((hangup==true)||(reload==true)) { + (void) rou_alert(0,"%s got hangup or reload signal",OPEP); + (void) prc_killchilds(childs,nbrbind,10); + phase=999; //No need to have sub process; + } + break; + case 2 : //Opening ALL channels + allbusy=true; + for (int i=0;i)", + OPEP,strerror(errno)); + childs[i]=(pid_t)0; + (void) sleep(2); //Weathering the storm + break; + case 0 : //Child process itself + (void) startwaiter(bindings[i]); + (void) exit(0); + break; + default : //Main process + (void) usleep(10000); + break; + } + } + break; + case 5 : //lets continue within process loop + if (foreground==false) + phase=0; + break; + default : //SAFE Guard + if (childs!=(pid_t *)0) + (void) free(childs); + bindings=soc_freebindinf(bindings); + proceed=false; + break; + } + phase++; + } +confargv=(char **)rou_freelist((void **)confargv,(genfree_t)rou_freestr); +#undef RELAX +#undef OPEP +} diff --git a/lib/modrec.d b/lib/modrec.d new file mode 100644 index 0000000..6ab4ab3 --- /dev/null +++ b/lib/modrec.d @@ -0,0 +1,121 @@ +modrec.o modrec.d : modrec.c /usr/include/stdc-predef.h /usr/include/errno.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/mcheck.h \ + /usr/include/stdio.h /usr/include/bits/libc-header-start.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/types/__fpos_t.h \ + /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/stdlib.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/sys/types.h /usr/include/bits/types/clock_t.h \ + /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/byteswap.h \ + /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \ + /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/string.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/strings.h /usr/include/syslog.h /usr/include/sys/syslog.h \ + /usr/include/bits/syslog-path.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h uniprc.h unieml.h subafn.h \ + /usr/include/netdb.h /usr/include/netinet/in.h \ + /usr/include/bits/stdint-uintn.h /usr/include/sys/socket.h \ + /usr/include/bits/types/struct_iovec.h /usr/include/bits/socket.h \ + /usr/include/bits/socket_type.h /usr/include/bits/sockaddr.h \ + /usr/include/asm/socket.h /usr/include/asm-generic/socket.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/bits/in.h \ + /usr/include/rpc/netdb.h /usr/include/bits/netdb.h unisig.h \ + /usr/include/signal.h /usr/include/bits/signum-generic.h \ + /usr/include/bits/signum-arch.h /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h /usr/include/bits/types/stack_t.h \ + /usr/include/sys/ucontext.h /usr/include/bits/sigstack.h \ + /usr/include/bits/sigstksz.h /usr/include/bits/ss_flags.h \ + /usr/include/bits/types/struct_sigstack.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h devsoc.h unitls.h \ + /usr/include/openssl/ssl.h /usr/include/openssl/macros.h \ + /usr/include/openssl/opensslconf.h /usr/include/openssl/configuration.h \ + /usr/include/openssl/opensslv.h /usr/include/openssl/e_os2.h \ + /usr/include/inttypes.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdint.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/bits/stdint-least.h /usr/include/openssl/e_ostime.h \ + /usr/include/sys/time.h /usr/include/openssl/comp.h \ + /usr/include/openssl/crypto.h /usr/include/openssl/safestack.h \ + /usr/include/openssl/stack.h /usr/include/openssl/types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/limits.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h /usr/include/bits/posix2_lim.h \ + /usr/include/openssl/cryptoerr.h /usr/include/openssl/symhacks.h \ + /usr/include/openssl/cryptoerr_legacy.h /usr/include/openssl/core.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include-fixed/pthread.h \ + /usr/include/sched.h /usr/include/bits/sched.h \ + /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \ + /usr/include/bits/setjmp.h \ + /usr/include/bits/types/struct___jmp_buf_tag.h \ + /usr/include/openssl/comperr.h /usr/include/openssl/bio.h \ + /usr/include/openssl/bioerr.h /usr/include/openssl/x509.h \ + /usr/include/openssl/buffer.h /usr/include/openssl/buffererr.h \ + /usr/include/openssl/evp.h /usr/include/openssl/core_dispatch.h \ + /usr/include/openssl/indicator.h /usr/include/openssl/params.h \ + /usr/include/openssl/bn.h /usr/include/openssl/bnerr.h \ + /usr/include/openssl/evperr.h /usr/include/openssl/objects.h \ + /usr/include/openssl/obj_mac.h /usr/include/openssl/asn1.h \ + /usr/include/openssl/asn1err.h /usr/include/openssl/objectserr.h \ + /usr/include/openssl/ec.h /usr/include/openssl/ecerr.h \ + /usr/include/openssl/rsa.h /usr/include/openssl/rsaerr.h \ + /usr/include/openssl/dsa.h /usr/include/openssl/dh.h \ + /usr/include/openssl/dherr.h /usr/include/openssl/dsaerr.h \ + /usr/include/openssl/sha.h /usr/include/openssl/x509err.h \ + /usr/include/openssl/x509_vfy.h /usr/include/openssl/lhash.h \ + /usr/include/openssl/pkcs7.h /usr/include/openssl/pkcs7err.h \ + /usr/include/openssl/http.h /usr/include/openssl/conf.h \ + /usr/include/openssl/conferr.h /usr/include/openssl/conftypes.h \ + /usr/include/openssl/pem.h /usr/include/openssl/pemerr.h \ + /usr/include/openssl/hmac.h /usr/include/openssl/async.h \ + /usr/include/openssl/asyncerr.h /usr/include/openssl/ct.h \ + /usr/include/openssl/cterr.h /usr/include/openssl/sslerr.h \ + /usr/include/openssl/sslerr_legacy.h /usr/include/openssl/prov_ssl.h \ + /usr/include/openssl/ssl2.h /usr/include/openssl/ssl3.h \ + /usr/include/openssl/tls1.h /usr/include/openssl/dtls1.h \ + /usr/include/openssl/srtp.h /usr/include/openssl/quic.h gessql.h \ + devsql.h unisql.h gestcp.h unidns.h devlog.h lvleml.h gesspf.h geseml.h \ + modrec.h diff --git a/lib/modrec.h b/lib/modrec.h new file mode 100644 index 0000000..e13e747 --- /dev/null +++ b/lib/modrec.h @@ -0,0 +1,15 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/************************************************/ +/* */ +/* Module to handle all incoming email */ +/* */ +/************************************************/ +#ifndef MODREC +#define MODREC + +#include + +//procedure to receive email from outside +extern void rec_handlesmtp(int argc,char *argv[]); + +#endif diff --git a/lib/numver.h b/lib/numver.h new file mode 100644 index 0000000..5a07df1 --- /dev/null +++ b/lib/numver.h @@ -0,0 +1,3 @@ +#define VERSION "0.19" +#define RELEASE "11" +#define BRANCH "dvl" diff --git a/lib/subafn.c b/lib/subafn.c new file mode 100644 index 0000000..5ab94c4 --- /dev/null +++ b/lib/subafn.c @@ -0,0 +1,678 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Sub kevel procedure to manage IP number. */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "subafn.h" + +#define AFT sizeof(struct in6_addr) +/* + +*/ +/********************************************************/ +/* */ +/* procedure to build a list of local server IP */ +/* */ +/********************************************************/ +static char *getlocalipstr() + +{ +#define OPEP "subafn.c:getlocalipstr," + +char *localip; +struct ifaddrs *ifaddr; +int phase; +_Bool proceed; + +localip=strdup(""); +ifaddr=(struct ifaddrs *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Get list of interface + if (getifaddrs(&ifaddr)<0) { + (void) fprintf(stderr,"%s Unable to get local IP (error=<%s> system?)\n", + OPEP,strerror(errno)); + phase=999; //No need to go further; + } + break; + case 1 : //cans list of interface + for (struct ifaddrs *ifa=ifaddr;ifa!=(struct ifaddrs *)0;ifa=ifa->ifa_next) { + int family; + int taille; + int er; + char *newloc; + char host[NI_MAXHOST]; + + if (ifa->ifa_addr==(struct sockaddr *)0) + continue; + family=ifa->ifa_addr->sa_family; + switch (family) { + case AF_INET : + taille=sizeof(struct sockaddr_in); + break; + case AF_INET6 : + taille=sizeof(struct sockaddr_in6); + continue; //No scanning for IPV6 Number (Jun 2025) + break; + default : + continue; + break; + } + er=getnameinfo(ifa->ifa_addr,taille,host,NI_MAXHOST,NULL,0,NI_NUMERICHOST); + if (er!=0) { + (void) fprintf(stderr,"%s getnameinfo() failed: (error=<%s> system?)\n", + OPEP,gai_strerror(er)); + continue; + } + newloc=(char *)calloc(strlen(localip)+strlen(host)+3,sizeof(char)); + if (strlen(localip)>0) { + (void) strcpy(newloc,localip); + (void) strcat(newloc,","); + } + (void) strcat(newloc,host); + (void) free(localip); + localip=newloc; + } + break; + case 2 : //free memory + (void) freeifaddrs(ifaddr); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return localip; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Routine to compare 2 IP num, can be */ +/* IPV4 or IPV6 IP number. */ +/* return true if match within mask. */ +/* */ +/********************************************************/ +static _Bool cmpip(AFNTYP *ipnum1,AFNTYP *ipnum2,int mask) + +{ +_Bool areequal; +int maskbyt; + +areequal=false; +if (mask>128) + mask=128; +maskbyt=mask/8; +if (memcmp(ipnum1->ip,ipnum2->ip,maskbyt)==0) { + areequal=true; + mask%=8; + if (mask!=0) { + int maskbit; + int b1; + int b2; + + maskbit=(~0U<<(8-mask)); + b1=((int)ipnum1->ip[maskbyt])&maskbit; + b2=((int)ipnum2->ip[maskbyt])&maskbit; + if (b1!=b2) + areequal=false; + } + } +return areequal; +} +/* + +*/ +/********************************************************/ +/* */ +/* Routine to fee memory used by an AFNTYP */ +/* */ +/********************************************************/ +PUBLIC AFNTYP *afn_freeipnum(AFNTYP *afnnum) + +{ +if (afnnum!=(AFNTYP *)0) { + if (afnnum->strnumip!=(char *)0) + (void) free(afnnum->strnumip); + (void) free(afnnum); + afnnum=(AFNTYP *)0; + } +return afnnum; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to set IPNUM mask. */ +/* */ +/********************************************************/ +PUBLIC AFNTYP *afn_maskip(AFNTYP *afnnum,int cidr) + +{ +if (afnnum!=(AFNTYP *)0) { + unsigned int num; + int mxcidr; + + mxcidr=32; + if (afnnum->afntype==AF_INET6) + mxcidr=128; + if (cidr>mxcidr) + cidr=mxcidr; + afnnum->afnmask=cidr; + num=cidr/8; + cidr%=8; + if (cidr!=0) { + afnnum->ip[num]&=(~0U<<(8-cidr)); + num++; + } + if (numip+num,'\000',AFT-num); + } +return afnnum; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to return a string with */ +/* ipnum address and MASK in clear format */ +/* Address need to freed. */ +/* */ +/********************************************************/ +PUBLIC char *afn_stripnum(AFNTYP *num) + +{ +#define OPEP "subafn.c:afn_stripnumm," + +char *strip; +const char *markr; +char host[NI_MAXHOST]; +int phase; +_Bool proceed; + +strip=(char *)0; +markr=""; +(void) strcpy(host,""); +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Do we have an IP number + if (num==(AFNTYP *)0) { + (void) fprintf(stderr,"%s No ip provided (bug?)\n",OPEP); + (void) snprintf(host,sizeof(host),"[IP not defined] (Bug?)"); + phase=999; + } + break; + case 1 : //extracting IP + switch (num->afntype) { + case AF_INET6 : + markr=STRIPV6; + //NO break + case AF_INET : + if (inet_ntop(num->afntype,&(num->ip),host,sizeof(host))==(char *)0) + (void) snprintf(host,sizeof(host),"[afn_stripnum error=<%s>] (Bug?)", + strerror(errno)); + break; + default : + (void) snprintf(host,sizeof(host),"[ipvx:0.%d] (Bug?)",num->afntype); + break; + } + break; + default : //SAFE Guard + if (strlen(host)>0) { //always + int taille; + + taille=strlen(markr)+strlen(host)+10; + strip=(char *)calloc(taille,sizeof(char)); + (void) snprintf(strip,taille,"%s%s",markr,host); + } + proceed=false; + break; + } + phase++; + } +return strip; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Routine to convert a addrinfo struct to an */ +/* IP number in AFNTYP structure. */ +/* */ +/********************************************************/ +PUBLIC AFNTYP *afn_getaddrinfo(struct addrinfo *rp) + +{ +AFNTYP *afnnum; + +afnnum=(AFNTYP *)0; +if (rp!=(struct addrinfo *)0) { + u_char *ptr; + + ptr=(u_char *)0; + afnnum=calloc(1,sizeof(AFNTYP)); + afnnum->afntype=rp->ai_family; + switch (rp->ai_family) { + case AF_INET : + afnnum->afnmask=32; + ptr=(u_char *)&(((struct sockaddr_in *)rp->ai_addr)->sin_addr.s_addr); + break; + case AF_INET6 : + afnnum->afnmask=128; + ptr=(u_char *)&(((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr.s6_addr); + break; + default : /*trouble trouble */ + afnnum=afn_freeipnum(afnnum); + break; + } + if (ptr!=(u_char *)0) + (void) memmove(afnnum->ip,ptr,afnnum->afnmask/8); + afnnum->strnumip=afn_getstrip(afnnum); + } +return afnnum; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to transforme ONE clean IP to an AFN */ +/* structure. */ +/* */ +/********************************************************/ +PUBLIC AFNTYP *afn_getoneipnum(char *oneipstr) + +{ +#define OPEP "subafn.c:afn_getoneipnum," +#define ZIPV4 "0.0.0.0" + +AFNTYP *afnnum; +int phase; +int proceed; + +afnnum=(AFNTYP *)0; +phase=0; +proceed=true; +while (proceed==true) { + //(void) fprintf(stderr,"%s JMPDBG phase='%d'\n",OPEP,phase); + switch (phase) { + case 0 : /*lets say ip format ok */ + afnnum=(AFNTYP *)calloc(1,sizeof(AFNTYP)); + afnnum->afntype=AF_INET; + afnnum->afnmask=32; + if (strchr(oneipstr,':')==(char *)0) + phase++; //This is an IPV4 number + break; + case 1 : //IP is an IPV6 format + if (strcasestr(oneipstr,STRIPV6)==oneipstr) + oneipstr+=strlen(STRIPV6); + afnnum->afntype=AF_INET6; + afnnum->afnmask=128; + break; + case 2 : //lets convert it + switch (inet_pton(afnnum->afntype,oneipstr,afnnum->ip)) { + case 1 : //success + break; + case 0 : //Invalid IP number + (void) fprintf(stderr,"Unable to convert IP <%s> (Invalid IP number)\n", + oneipstr); + afnnum=afn_freeipnum(afnnum); + phase=999; //no need to go further + break; + case -1 : //Invalid IP number + (void) fprintf(stderr,"Unable to convert IP <%s> (error=<%s>)\n", + oneipstr,strerror(errno)); + afnnum=afn_freeipnum(afnnum); + phase=999; //no need to go further + break; + default : //Unexpected Result + (void) fprintf(stderr,"Unexpected status to convert IP <%s> " + "(error=<%s> BUG!?)\n", + oneipstr,strerror(errno)); + afnnum=afn_freeipnum(afnnum); + phase=999; //no need to go further + } + break; + case 3 : //lets convert it + afnnum->strnumip=afn_getstrip(afnnum); + //(void) printf("JMPDBG <%s> -> to <%s>\n",oneipstr,afnnum->strnumip); + break; + default : /*SAFE guard */ + proceed=false; + break; + } + phase++; + } +return afnnum; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Routine to convert clean string list to an */ +/* IP number in AFNTYP list. */ +/* */ +/********************************************************/ +PUBLIC AFNTYP **afn_getipnums(char *seqipstr) + +{ +#define OPEP "subafn.c:afn_getipnums" +#define ZIPV4 "0.0.0.0" + +AFNTYP **afnlist; +char *iplist; +int phase; +int proceed; + +afnlist=(AFNTYP **)calloc(1,sizeof(AFNTYP *)); +iplist=(char *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Do we have an IP string + if (seqipstr==(char *)0) { + (void) fprintf(stderr,"%s No ip provided (bug?)\n",OPEP); + phase=999; //No need to go further + } + break; + case 1 : //checking '0' situation + if (strcmp(seqipstr,"0")==0) + seqipstr=ZIPV4; + break; + case 2 : //checking '0' situation + iplist=strdup(seqipstr); + if (strcmp(iplist,ZIPV4)==0) { + (void) free(iplist); + iplist=getlocalipstr(); + } + if (strlen(iplist)==0) + phase++; //No need to scan + break; + case 3 : //scanning the iplist + char *ptr; + int num; + + ptr=iplist; + num=0; + while (ptr!=(char *)0) { + char *next; + AFNTYP *afnloc; + + if ((next=strchr(ptr,','))!=(char *)0) { + *next='\000'; + next++; + } + if ((afnloc=afn_getoneipnum(ptr))!=(AFNTYP *)0) { + afnlist=(AFNTYP **)realloc(afnlist,(num+2)*sizeof(AFNTYP *)); + afnlist[num]=afnloc; + num++; + afnlist[num]=(AFNTYP *)0; + } + ptr=next; + } + break; + case 4 : //free memory used + (void) free(iplist); + break; + default : /*SAFE guard */ + proceed=false; + break; + } + phase++; + } +return afnlist; + +#undef ZIPV4 +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to normalize IP number format */ +/* Memory allocated need to be freed later */ +/* on. */ +/* */ +/* */ +/********************************************************/ +char *afn_getstrip(AFNTYP *afnnum) + +{ +#define OPEP "subafn.c:afn_getstrip" + +char *ipnorm; +char buffer[300]; + +ipnorm=(char *)0; +(void) strcpy(buffer,""); +if (afnnum!=(AFNTYP *)0) { + switch (afnnum->afntype) { + case AF_INET : + (void) snprintf(buffer,sizeof(buffer),"%d.%d.%d.%d", + afnnum->ip[0],afnnum->ip[1], + afnnum->ip[2],afnnum->ip[3]); + break; + case AF_INET6 : + (void) snprintf(buffer,sizeof(buffer),"%02x%02x:%02x%02x:%02x%02x:%02x%02x:" + "%02x%02x:%02x%02x:%02x%02x:%02x%02x", + afnnum->ip[0],afnnum->ip[1], + afnnum->ip[2],afnnum->ip[3], + afnnum->ip[4],afnnum->ip[5], + afnnum->ip[6],afnnum->ip[7], + afnnum->ip[8],afnnum->ip[9], + afnnum->ip[10],afnnum->ip[11], + afnnum->ip[12],afnnum->ip[13], + afnnum->ip[14],afnnum->ip[15]); + break; + default : + (void) fprintf(stderr,"%s, unable to find IP type (bug?)",OPEP); + } + } +if (strlen(buffer)>0) + ipnorm=strdup(buffer); +return ipnorm; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return a revers address as */ +/* dynamically alocated memory. */ +/* */ +/********************************************************/ +char *afn_reversipnum(AFNTYP *afnnum) + +{ +char * reversip; + +reversip=(char *)0; +if (afnnum!=(AFNTYP *)0) { + int i; + char revers[200]; + + (void) memset(revers,'\000',sizeof(revers)); + switch (afnnum->afntype) { + case AF_INET6 : + for (i=16;i>0;i--) { + char local[20]; + + (void) snprintf(local,sizeof(local),"%x.%x.", + afnnum->ip[i-1]&0xf, + afnnum->ip[i-1]>>4); + (void) strncat(revers,local,sizeof((revers)-1)-strlen(revers)); + } + break; + case AF_INET : + for (i=4;i>0;i--) { + char local[10]; + + (void) snprintf(local,sizeof(local),"%d.",afnnum->ip[i-1]); + (void) strncat(revers,local,(sizeof(revers)-1)-strlen(revers)); + } + break; + default : + (void) snprintf(revers,sizeof(revers),"%d.0.0.0.0.ukn.",afnnum->afntype); + break; + } + revers[strlen(revers)-1]='\000'; + reversip=strdup(revers); + } +return reversip; +} + +/* +^L +*/ +/********************************************************/ +/* */ +/* Routine to compare two ipnum by taking */ +/* mask ip_ipbits, return true if ipbits */ +/* are identical, false otherwise. */ +/* return -1 if unexpected type */ +/* */ +/********************************************************/ +PUBLIC int afn_cmpipnum(AFNTYP *afnnum1,AFNTYP *afnnum2,int mask) + +{ +int areequal; +int phase; +int proceed; + +areequal=0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : /*two ipnum really */ + if ((afnnum1==(AFNTYP *)0)||(afnnum2==(AFNTYP *)0)) + proceed=false; /*no need to go further */ + break; + case 1 : /*is mask 0, all IP ok */ + if (mask==0) { + areequal=1; + proceed=false; + } + break; + case 2 : /*two ipnum same type */ + if (afnnum1->afntype!=afnnum2->afntype) + proceed=false; /*no need to go further */ + break; + case 3 : /*lets compare ip */ + if (mask>128) + mask=128; + switch(afnnum1->afntype) { + case AF_INET : + if (mask>32) + mask=32; + // fall through + case AF_INET6 : + areequal=(int)cmpip(afnnum1,afnnum2,mask); + break; + default : + errno=EAFNOSUPPORT; + areequal=-1; + break; + } + break; + default : /*SAFE guard */ + proceed=false; + break; + } + phase++; + } +return areequal; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to check if a remote IP is part of */ +/* acceptable to be relayed list. */ +/* */ +/********************************************************/ +PUBLIC _Bool afn_is_ip_relayable(char *iptocheck,AFNTYP **list) + +{ +#define OPEP "subafn.c:afn_ip_inlist," + +_Bool isok; +AFNTYP *afn; +int phase; +_Bool proceed; + +isok=false; +afn=(AFNTYP *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //converting IP + if ((afn=afn_getoneipnum(iptocheck))==(AFNTYP *)0) { + (void) fprintf(stderr,"%s, Unable to convert IP=<%s> (bug?)", + OPEP,iptocheck); + phase=999; + } + break; + case 1 : //do we have a list + if (list==(AFNTYP **)0) + phase=999; //No need to go further + break; + case 2 : //do we have a list + while ((isok==false)&&(*list!=(AFNTYP *)0)) { + switch (afn_cmpipnum(*list,afn,(*list)->afnmask)) { + case -1 : //trouble! + (void) fprintf(stderr,"%s, Unable to check IP=<%s> (error=<%s> bug?)", + OPEP,iptocheck,strerror(errno)); + break; + case 0 : //no match, nothing to do + break; + case 1 : //found a match + isok=true; + break; + } + list++; + } + break; + default : //SAFE Guard + afn=afn_freeipnum(afn); + proceed=false; + break; + } + phase++; + } +return isok; + +#undef OPEP +} diff --git a/lib/subafn.d b/lib/subafn.d new file mode 100644 index 0000000..40a1321 --- /dev/null +++ b/lib/subafn.d @@ -0,0 +1,48 @@ +subafn.o subafn.d : subafn.c /usr/include/stdc-predef.h /usr/include/ifaddrs.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/sys/socket.h /usr/include/bits/types/struct_iovec.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/socket.h /usr/include/sys/types.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/types/clock_t.h \ + /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/byteswap.h \ + /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \ + /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/bits/socket_type.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm-generic/socket.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h /usr/include/asm/posix_types.h \ + /usr/include/asm/posix_types_64.h /usr/include/asm-generic/posix_types.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/malloc.h \ + /usr/include/stdio.h /usr/include/bits/libc-header-start.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/string.h /usr/include/bits/types/locale_t.h \ + /usr/include/bits/types/__locale_t.h /usr/include/strings.h \ + /usr/include/arpa/inet.h /usr/include/netinet/in.h \ + /usr/include/bits/stdint-uintn.h /usr/include/bits/in.h \ + /usr/include/errno.h /usr/include/bits/errno.h \ + /usr/include/linux/errno.h /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + subafn.h /usr/include/netdb.h /usr/include/rpc/netdb.h \ + /usr/include/bits/netdb.h diff --git a/lib/subafn.h b/lib/subafn.h new file mode 100644 index 0000000..15a93c9 --- /dev/null +++ b/lib/subafn.h @@ -0,0 +1,66 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/************************************************/ +/* */ +/* Define all routine to manage all */ +/* procedure to manage IP number conversion*/ +/* */ +/************************************************/ +#ifndef SUBAFN +#define SUBAFN + +#include + +//IPV6 ip number marker +#define STRIPV6 "ipv6:" + +//space to store (at least) IPV6 number +#define AFT sizeof(struct in6_addr) + +//Need to have GNU_SOURCE define within CFLAGS +#ifdef AI_ALL +#define HINTFLG AI_ALL|AI_CANONNAME|AI_CANONIDN +#else /*AI_ALL is not defined in linux <= rh9 */ +#define HINTFLG AI_CANONNAME +#endif + +typedef struct { + char *strnumip; //IP in string format + int afntype; //IP type + int afnmask; //IP Mask + u_char ip[AFT]; //IP number + }AFNTYP; + +//procedure to free memory used by an AFNTYP structure +extern AFNTYP *afn_freeipnum(AFNTYP *afnnum); + +//procedure to set IPNUM mask +extern AFNTYP *afn_maskip(AFNTYP *afnnum,int cidr); + +//procedure to convert a AFNTYP structure to an standardised +//IP number +extern char *afn_stripnum(AFNTYP *afnnum); + +//procedure to extract a dynamic string with the +//clean IP number from a AFNTYP struct. +extern char *afn_getstrip(AFNTYP *afnnum); + +//procedure to convert a addrinfo struct to an +//IP number in AFNTYP structure. +extern AFNTYP *afn_getaddrinfo(struct addrinfo *rp); + +//procedure to convert on IP seen as a string to an AFNTYP structure +extern AFNTYP *afn_getoneipnum(char *oneipstr); + +//procedure to convert multiple IP seen as a string to an AFNTYP list +extern AFNTYP **afn_getipnums(char *listipstr); + +//procedure to 'compute' a reverss-addres from the IP +extern char *afn_reversipnum(AFNTYP *afnnum); + +//procedure to compare 2 same class IP according a mask value +extern int afn_cmpipnum(AFNTYP *afnnum1,AFNTYP *afnnum2,int mask); + +//procedure to check if a remote ip is part of the relayable list +extern _Bool afn_is_ip_relayable(char *iptocheck,AFNTYP **list); + +#endif diff --git a/lib/subcnv.c b/lib/subcnv.c new file mode 100644 index 0000000..17c8204 --- /dev/null +++ b/lib/subcnv.c @@ -0,0 +1,223 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Define all routine to manage language string */ +/* conversion. */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include + +#include "subcnv.h" + +/* + +*/ +/********************************************************/ +/* */ +/* Routine to check if all char within a B64 */ +/* string are indeed Base-64 character. */ +/* */ +/********************************************************/ +static int checkb64(char *b64) + +{ +int ok; + +ok=true; +while ((*b64!='\000')&&(ok==true)) { + switch (*b64) { + case '+' : + case '/' : + case '=' : + break; + default : + if (isalnum(*b64)==0) { + ok=false; + *b64='\000'; + } + break; + } + b64++; + } +return ok; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to convert an ASCII B64 sequence to a */ +/* plain ASCII sequence. */ +/* */ +/********************************************************/ +PUBLIC char *cnv_getb64(char *b64) + +{ +#define OPEP "subcnv.c:cnv_getb64," + +char *decoded; +BIO *mbio; +BIO *bbio; +int retour; + +(void) checkb64(b64); +decoded=(char *)calloc(strlen(b64)+3,sizeof(char)); +mbio=BIO_new(BIO_s_mem()); +bbio=BIO_new(BIO_f_base64()); +BIO_set_flags(bbio,BIO_FLAGS_BASE64_NO_NL); +bbio=BIO_push(bbio,mbio); +(void) BIO_write(mbio,b64,strlen(b64)); +(void) BIO_flush(mbio); +switch(retour=BIO_read(bbio,decoded,strlen(b64))) { + case -2 : + (void) fprintf(stderr,"%s Can't proceed! decoding <%s> (bug?)",OPEP,b64); + break; + case -1 : + case 0 : + (void) fprintf(stderr,"%s Need a retry! decoding <%s> (bug?)",OPEP,b64); + break; + default : + if (retour>0) { /*always */ + register int scan; + register int skip; + + scan=retour; + skip=strlen(IOBNULL); + while (scan>0) { + scan--; + if (decoded[scan]=='\000') { + register int taille; + char *n_deco; + + taille=retour+skip+1; + if ((n_deco=(char *)realloc(decoded,taille*sizeof(char)))!=(char *)0) { + decoded=n_deco; + (void) memmove(decoded+scan+skip,decoded+scan+1,(retour-scan)+1); + (void) memmove(decoded+scan,IOBNULL,skip); + } + retour+=skip; + } + } + } + break; + } +if (retour<=0) { + (void) free(decoded); + decoded=(char *)0; + } +(void) BIO_free_all(bbio); +return decoded; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to convert a plain ASCII sequence to a*/ +/* B64 ASCII sequence. */ +/* */ +/********************************************************/ +PUBLIC char *cnv_setb64(const char *str) + +{ +#define OPEP "unicnv.c:tls_setb64," + +register int skip; + +char *coded; +BIO *bmem; +BIO *b64; +BUF_MEM *bptr; +int taille; +char *buffer; +char *ptr; + +skip=strlen(IOBNULL)-1; +coded=(char *)0; +b64=BIO_new(BIO_f_base64()); +BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL); +bmem=BIO_new(BIO_s_mem()); +b64=BIO_push(b64,bmem); +buffer=strdup(str); +taille=strlen(buffer); +ptr=buffer; +while ((ptr=strstr(ptr,IOBNULL))!=(char *)0) { + *ptr='\000'; + ptr++; + (void) memmove(ptr,ptr+skip,strlen(ptr+skip)+1); + taille-=skip; + } +(void) BIO_write(b64,buffer,taille); +(void) BIO_flush(b64); +BIO_get_mem_ptr(b64,&bptr); +(void) free(buffer); +coded=(char *)calloc(bptr->length+1,sizeof(char)); +(void) memcpy(coded,bptr->data,bptr->length); +(void) BIO_free_all(b64); +return coded; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to convert a string of character as */ +/* an hexadecimale string sequence */ +/* */ +/********************************************************/ +PUBLIC char *cnv_tohexa(const char *str,int taille) + +{ +char *hexa; + +hexa=(char *)0; +if ((str!=(char *)0)&&(taille>0)) { + hexa=(char *)calloc((taille*2)+1,sizeof(char)); + for (int i=0;i0) { + rndstr=(char *)calloc(length+1,sizeof(char)); + for (size_t t=0;t +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "numver.h" + + +//Public variables +PUBLIC int debug=0; //debug level +PUBLIC char *dbglive; //procedure reference to be debugged live + +PUBLIC _Bool foreground=false; //process is always started in background mode +PUBLIC char *rootdir=(char *)0;//working directory (debugging) +PUBLIC char *appname; //application "official" name + +//application binary name +PUBLIC char execname[20]=APPNAME; + +//static variables +static _Bool modopen; //boolean module open/close + +//Time offset (for debug purpose only) +static time_t off64_time=(time_t)0; +static time_t off_date=(time_t)0; +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to find out a possible drop zone */ +/* for abort() core memory dump. */ +/* */ +/********************************************************/ +static char *get_dropzone() + +{ +char *dropzone; +char command[100]; + +(void) strcpy(command,"/tmp/"); +(void) strcat(command,APPNAME); +(void) strcat(command,"-crash"); +dropzone=rou_apppath(command); +(void) rou_do_mkpdir(dropzone); +return dropzone; +} +/* + +*/ +/********************************************************/ +/* */ +/* This procedure is working tandem with libleak */ +/* to detect memory leak within specfic part of */ +/* code. */ +/* Tools as valgrind can not be used as most of */ +/* the application is forked in daemon state. */ +/* memory leak must be detected on a "long" run */ +/* forgetting about parent process apparent leak. */ +/* (forked process are created with parent memory */ +/* copy) */ +/* */ +/********************************************************/ +PUBLIC void rou_checkleak(_Bool onoff) + +{ +#define ENABLE "/tmp/libleak.enabled" + +static _Bool current=false; + +if ((debug>2)&&(current!=onoff)) { + int status; + char cmd[200]; + + switch (onoff) { + case true : + (void) snprintf(cmd,sizeof(cmd),"echo %d >> %s",getpid(),ENABLE); + break; + case false : + (void) snprintf(cmd,sizeof(cmd),"sed -i '/%d/d' %s",getpid(),ENABLE); + break; + } + if ((status=system(cmd))!=0) { + (void) rou_alert(0,"status '%d' to memleak command <%s> (bug?)",status,cmd); + } + current=onoff; + } +#undef ENABLE +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to assign enough memory to format */ +/* a string with va_list parameter. */ +/* Known as vasprintf in GNU_SOURCE. */ +/* */ +/********************************************************/ +PUBLIC int rou_vasprintf(char **str,const char *fmt,va_list ap) + +{ +int taille; +va_list sup; +char loc[10]; + +taille=0; +(void) va_copy(sup,ap); +if (strlen(fmt)==0) + *str=strdup(""); +else { + if ((taille=vsnprintf(loc,4,fmt,ap))>0) { + *str=calloc(taille+2,sizeof(char)); + taille=vsnprintf(*str,taille+1,fmt,sup); + } + } +return taille; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to return the current application */ +/* working realm */ +/* */ +/********************************************************/ +PUBLIC const char *rou_getrealm() + +{ +const char *realm; + +if ((realm=getenv("REALM"))==(const char *)0) + realm=REALM; +return realm; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to assign enough memory to format */ +/* a string. */ +/* Known as asprintf in GNU_SOURCE. */ +/* */ +/********************************************************/ +PUBLIC int rou_asprintf(char **str,const char *fmt,...) + +{ +int taille; + +taille=0; +if (strlen(fmt)==0) + *str=strdup(""); +else { + va_list args; + va_start(args,fmt); + char loc[10]; + + if ((taille=vsnprintf(loc,4,fmt,args))>0) { + va_list argssup; + + va_start(argssup,fmt); + *str=calloc(taille+2,sizeof(char)); + taille=vsnprintf(*str,taille+1,fmt,argssup); + va_end(argssup); + } + va_end(args); + } +return taille; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to create directory with all up */ +/* directories if they are missing. */ +/* Return true if successfull. */ +/* */ +/********************************************************/ +PUBLIC _Bool rou_do_mkpdir(char *dirpath) + +{ +#define OPEP "subrou.c:rou_do_mkpdir," +_Bool done; +int taille; +char *ptr; +char locdir[PATH_MAX]; +int phase;; +_Bool proceed; + +done=false; +(void) strcpy(locdir,dirpath); +ptr=(char *)0; +taille=strlen(locdir); +phase=0; +proceed=(taille>0); +while (proceed==true) { + switch (phase) { + case 0 : //make sur directory is starting with / + if (locdir[0]!='/') { + (void) rou_alert(0,"%s, <%s> is not a directory name (Bug?)",OPEP,locdir); + phase=999; //Trouble No need to go further! + } + break; + case 1 : //cleaning directory ending buy '/' + taille--; + if ((taille>1)&&(locdir[taille]=='/')) + locdir[taille]='\000'; + break; + case 2 : //is directory existing? + DIR *dirp; + + if ((dirp=opendir(locdir))!=(DIR *)0) { + (void) closedir(dirp); + done=true; + phase=999; //No need to go further + } + break; + case 3 : //is directory up existing? + if ((ptr=strrchr(locdir,'/'))!=(char *)0) { + *ptr='\000'; + if (rou_do_mkpdir(locdir)==false) + phase=999; //unable to create up directory! + } + break; + case 4 : //creating the requested directory + if (mkdir(dirpath,0755)<0) { + (void) rou_alert(0,"%s, unable to create directory <%s> (error=<%s>)", + OPEP,dirpath,strerror(errno)); + phase=999; //unable to create directory! + } + break; + case 5 : //everything fine + done=true; + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return done; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to return the time difference between */ +/* current real-time at nano-second level and */ +/* time reference. */ +/* time difference unit is millisec. */ +/* */ +/********************************************************/ +PUBLIC unsigned int rou_getdifftime(TIMESPEC *start) + +{ +unsigned int result; + +result=0; +if (start!=(TIMESPEC *)0) { + TIMESPEC current; + + (void) clock_gettime(CLOCK_REALTIME,¤t); + result=(current.tv_sec-start->tv_sec)*1000; + result+=(current.tv_nsec-start->tv_nsec)/1000000; + } +return result; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to return the current time */ +/* expressed with a millisecond precision starting */ +/* from the firt time it was called. */ +/* */ +/********************************************************/ +PUBLIC unsigned int rou_getmillisec() + +{ +struct timeval newtime; +(void) gettimeofday(&newtime,(struct timezone *)0); +return (unsigned int)((newtime.tv_usec/1000)); +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to transform the local system time in */ +/* ASCII time stamp. */ +/* Stored in STATIC memory area. */ +/* */ +/********************************************************/ +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to transform the local system time in */ +/* ASCII time stamp. */ +/* Stored in STATIC memory area. */ +/* */ +/********************************************************/ +PUBLIC char *rou_ascsysstamp(time_t curtime) + +{ +#define TSTAMP "%a, %d %b %Y %T %z" + +static char ascstamp[100]; + +(void) strftime(ascstamp,sizeof(ascstamp),TSTAMP,localtime(&curtime)); +return ascstamp; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Returne the version number and application */ +/* name. */ +/* */ +/********************************************************/ +PUBLIC const char *rou_getversion() + +{ +char *vers; + +vers=VERSION"."RELEASE; +if (strlen(BRANCH)>0) + vers=VERSION"."RELEASE"-"BRANCH; +return vers; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to free memory used by a */ +/* string, do not proceed if pointer is NULL. */ +/* */ +/********************************************************/ +PUBLIC char *rou_freestr(register char *str) + +{ +if (str!=(char *)0) { + (void) free(str); + str=(char *)0; + } +return str; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to get rid of any \r or \n at the end */ +/* of a string. */ +/* */ +/********************************************************/ +char *rou_stripcrlf(char *line) + +{ +if (line!=(char *)0) + line[strcspn(line,"\r\n")]='\000'; +return line; +} + +/* + +*/ +/********************************************************/ +/* */ +/* Subroutine to count the number of items within */ +/* a list of pointer. */ +/* */ +/********************************************************/ +PUBLIC int rou_nbrlist(void **list) + + +{ +int num; + +num=0; +if (list!=(void **)0) { + while (*list!=(void *)0) { + num++; + list++; + } + } +return num; +} +/* + +*/ +/********************************************************/ +/* */ +/* Subroutine to add a pointer (not null) */ +/* to a list of pointer. */ +/* */ +/********************************************************/ +PUBLIC void **rou_addlist(void **list,void *entry) + +{ +if (entry!=(void *)0) { + register int num; + + num=0; + if (list==(void **)0) + list=(void **)calloc(num+2,sizeof(void *)); + else { + register void **ptr; + + ptr=list; + while (*ptr!=(void *)0) { + num++; + ptr++; + } + list=realloc((void *)list,(num+2)*sizeof(void *)); + } + list[num]=entry; + num++; + list[num]=(void *)0; + } +return list; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to free one entry part of list */ +/* return true if found, false otherwize. */ +/* */ +/********************************************************/ +PUBLIC _Bool rou_rmlist(void **list,void *entry,genfree_t handler) + +{ +_Bool found; + +found=false; +if ((list!=(void **)0)&&(entry!=(void **)0)) { + void **ptr; + + ptr=list; + while (*ptr!=(void *)0) { + if (*ptr==entry) { + void **nxt; + + nxt=ptr+1; + if (handler!=(genfree_t)0) + (void) handler(*ptr); + while (*ptr!=(void *)0) { + *ptr=*nxt; + ptr++; + nxt++; + } + found=true; + break; + } + ptr++; + } + } +return found; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to free all list entries, return a */ +/* NULL pointer. */ +/* */ +/********************************************************/ +PUBLIC void **rou_freelist(void **list,genfree_t handler) + +{ +if (list!=(void **)0) { + void **ptr; + + ptr=list; + while (*ptr!=(void *)0) { + (void) handler(*ptr); + ptr++; + } + (void) free(list); + list=(void **)0; + } +return list; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Returne set a new application name to be used in*/ +/* logs. */ +/* */ +/********************************************************/ +PUBLIC char *rou_setappname(const char *newname) + +{ +char *name; + +name=(char *)0; +if (newname!=(char *)0) { + if (appname!=(char *)0) + (void) free(appname); + appname=strdup(newname); + name=appname; + } +return name; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Returne set a new exec/binary name. */ +/* logs. */ +/* */ +/********************************************************/ +PUBLIC const char *rou_setexecname(const char *newexecname) + +{ +(void) memset(execname,'\000',sizeof(execname)); +(void) strncpy(execname,newexecname,sizeof(execname)-1); +return execname; +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to allocate a path within the root */ +/* directory if needed */ +/* */ +/********************************************************/ +PUBLIC char *rou_apppath(const char *path) + +{ +char *root; +char *newpath; + +root=""; +newpath=(char *)0; +if (rootdir!=(char *)0) + root=rootdir; +(void) rou_asprintf(&newpath,"%s%s",root,path); +return newpath; +} +/* + +*/ +/********************************************************/ +/* */ +/* Subroutine to log event on syslog */ +/* */ +/********************************************************/ +PUBLIC void rou_valert(const int dlevel,const char *fmt,va_list ap) + +#define DEBMAX 140 + +{ +char lvl[10]; +char strloc[10000]; + +(void) snprintf(lvl,sizeof(lvl),"(dl=%02d) ",dlevel); +(void) memset(strloc,'\000',sizeof(strloc)); +(void) vsnprintf(strloc,sizeof(strloc)-1,fmt,ap); +if (foreground==true) + (void) fprintf(stderr,"%s%s\n",lvl,strloc); +else { + char *ptr; + ptr=strloc; + while (strlen(ptr)>DEBMAX) { + char locline[DEBMAX+10]; + + (void) strncpy(locline,ptr,DEBMAX); + locline[DEBMAX]='\000'; + (void) syslog(LOG_INFO,"%s%s",lvl,locline); + ptr +=DEBMAX; + (void) strcpy(lvl,""); + } + if (strlen(ptr)>0) + (void) syslog(LOG_INFO,"%s%s",lvl,ptr); + } +} +/* + +*/ +/********************************************************/ +/* */ +/* Subroutine to log event on syslog */ +/* */ +/********************************************************/ +PUBLIC void rou_alert(const int dlevel,const char *fmt,...) + +{ +if (debug>=dlevel) { + va_list args; + + va_start(args,fmt); + (void) rou_valert(dlevel,fmt,args); + va_end(args); + } +} +/* + +*/ +/********************************************************/ +/* */ +/* Subroutine to do live debug on a specific */ +/* function. */ +/* */ +/********************************************************/ +PUBLIC void rou_dbglive(const int dlevel,const char *prcref,const char *fmt,...) + +{ +if ((debug>=dlevel)&&(dbglive!=(char *)0)) { + if (strstr(dbglive,prcref)!=(char *)0) { + char *nstr; + va_list args; + + va_start(args,fmt); + (void) rou_asprintf(&nstr,"%s: %s",prcref,fmt); + (void) rou_valert(dlevel,nstr,args); + va_end(args); + (void) free(nstr); + } + } +} +/* + +*/ +/********************************************************/ +/* */ +/* Subroutine to CORE-DUMP the application */ +/* */ +/********************************************************/ +PUBLIC void rou_crash(const char *fmt,...) + +{ +#define RELAX 5 +va_list args; +char strloc[10000]; + +va_start(args,fmt); +(void) vsnprintf(strloc,sizeof(strloc),fmt,args); +(void) rou_alert(0,"Crashed on purpose:"); +(void) rou_alert(0,"\t--> '%s'",strloc); +(void) rou_alert(0,"Crash delayed by '%d' second",RELAX); +(void) sleep(RELAX); //To avoid immediat restart +va_end(args); +(void) kill(getpid(),SIGSEGV); +(void) exit(-1); //unlikely to reach here +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to display an core_dump */ +/* message and terminate application */ +/* */ +/********************************************************/ +PUBLIC void rou_core_dump(const char *fmt,...) + +{ +#define MAXCRASH 10 //maximun crash file within drop zone +#define COREDELAY 5 //number of second for core delay + +va_list args; +char *crashdir; +_Bool doabort; +_Bool proceed; +int phase; + +va_start(args,fmt); +crashdir=(char *)0; +doabort=false; +phase=0; +proceed=true; +(void) rou_valert(0,fmt,args); +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG core phase='%d'",phase); + switch (phase) { + case 0 : //find out if crashdir is existing + if ((crashdir=get_dropzone())==(char *)0) + phase=999; //no need to go further. + break; + case 1 : //can we access the crash dir + if (chdir(crashdir)<0) { //Unable to access crashdir + (void) free(crashdir); + phase=999; //no need to go further. + } + break; + case 2 : //no too much crash so fare? + DIR *dirp; + + (void) rou_alert(0,"Trying to store core-dump within directory <%s>", + crashdir); + if ((dirp=opendir("."))!=(DIR *)0) { + int nument; + struct dirent *entry; + + nument=0; + while ((entry=readdir(dirp))!=(struct dirent *)0) { + if (entry->d_type==DT_REG) + nument++; + } + (void) closedir(dirp); + if (nument>MAXCRASH) { + (void) rou_alert(0,"Aborting Coredump file generation!"); + (void) rou_alert(0,"Too many crash files already within <%s>", + crashdir); + phase=999; //No allowed to do abort + } + } + else + (void) rou_alert(0,"Unable to open crashdir <%s> PWD=%s (error=<%s>", + crashdir,get_current_dir_name(),strerror(errno)); + (void) free(crashdir); + break; + case 3 : //Ok we can call abort + doabort=true; + break; + default : + proceed=false; + break; + } + phase++; + } +(void) sleep(COREDELAY); /*to avoid crash avalanche */ +va_end(args); +if (doabort==true) { + (void) abort(); /*doing to do the abort */ + } +(void) rou_alert(0,"Unable to dump core memory"); +(void) exit(-1); //Theoriticaly unreachabe if + //abort was allowed +#undef MAXCRASH +#undef COREDELAY +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to clean a line form a configuration */ +/* line, removing comment part and end of space */ +/* within the line. */ +/* */ +/********************************************************/ +PUBLIC char *rou_clean_conf_line(char *line) + +{ +if (line!=(char *)0) { + char *ptr; + int taille; + + if ((ptr=strchr(line,'#'))!=(char *)0) + *ptr='\000'; + taille=strlen(line); + while (taille>0) { + taille--; + ptr=line+taille; + switch (*ptr) { + case ' ' : //Space characteres + case '\t' : + case '\r' : + case '\n' : + *ptr='\000'; + break; + default : //end of search + taille=0; + break; + } + } + } +return line; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to load the configuartion file */ +/* message and terminate application */ +/* */ +/********************************************************/ +PUBLIC void rou_loadconfig(char *conffile,_Bool load) + +{ +#define OPEP "subrou.c:rou_loadconfig," + +FILE *fichier; +char line[300]; +char *name; +char *value; +char *ptr; +int phase; +_Bool proceed; + +fichier=(FILE *)0; +(void) memset(line,'\000',sizeof(line)); +name=(char *)0; +value=(char *)0; +ptr=(char *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Opening the config file + if ((fichier=fopen(conffile,"r"))==(FILE *)0) { + char cwd[PATH_MAX]; + + (void) getcwd(cwd, sizeof(cwd)); + (void) fprintf(stdout,"%s exiting!, Unable to open file <%s> " + "within <%s> (error=<%s>)\n", + OPEP,conffile,cwd,strerror(errno)); + (void) exit(-1);//Big Trouble + } + break; + case 1 : //scanning file + (void) memset(line,'\000',sizeof(line)); + if ((ptr=fgets(line,sizeof(line)-1,fichier))==(char *)0) + phase=999; //scan terminated + break; + case 2 : //trimming line + (void) rou_clean_conf_line(line); + //check remaining clean line + if (strlen(line)==0) + phase=0; //next line + break; + case 3 : //Spliting data + if ((ptr=strchr(line,'='))==(char *)0) + phase=0; //line without '=' + break; + case 4 : //set name and value + name=line; + value=ptr+1; + *ptr='\000'; + while ((ptr=strrchr(name,' '))!=(char *)0) + *ptr='\000'; + while ((ptr=strrchr(name,'\t'))!=(char *)0) + *ptr='\000'; + while ((value[0]==' ')||(value[0]=='\t')) + value++; + //removing quote if present + if (value[0]=='"') + value++; + if ((ptr=strrchr(value,'"'))!=(char *)0) + *ptr='\000'; + //make sure we have data to set + if ((strlen(name)==0)||(strlen(value)==0)) + phase=0; //No name or value?? + break; + case 5 : //set name and value + if (load==true) + (void) setenv(name,value,true); + else + (void) unsetenv(name); + phase=0; + break; + default : //SAFE Guard + (void) fclose(fichier); + proceed=false; + break; + } + phase++; + } +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to "open/close" module and do */ +/* homework purpose */ +/* return zero if everything right */ +/* */ +/********************************************************/ +PUBLIC int rou_modesubrou(_Bool mode) + +{ +#define OPEP "subrou.c:rou_modesubrou" + +int status; + +status=0; +if (mode!=modopen) { + switch ((int)mode) { + case true : + off64_time=(time_t)0; + off_date=(time_t)0; + (void) srand(getpid()*355); + if (foreground==true) + (void) srand((int)(M_PI*100000000)); + if (appname==(char *)0) + appname=strdup(APPNAME); + (void) openlog(appname,LOG_NDELAY|LOG_PID,LOG_DAEMON); + break; + case false : + (void) closelog(); + appname=rou_freestr(appname); + rootdir=rou_freestr(rootdir); + break; + default : + (void) fprintf(stderr,"Calling %s with wrong mode='%d' (Bug?!):", + OPEP,(int)mode); + status=-1; + break; + } + modopen=mode; + } +return status; +#undef OPEP +} diff --git a/lib/subrou.d b/lib/subrou.d new file mode 100644 index 0000000..25829e7 --- /dev/null +++ b/lib/subrou.d @@ -0,0 +1,72 @@ +subrou.o subrou.d : subrou.c /usr/include/stdc-predef.h /usr/include/sys/stat.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/endian.h /usr/include/bits/endianness.h \ + /usr/include/bits/types/time_t.h /usr/include/bits/stat.h \ + /usr/include/bits/struct_stat.h /usr/include/sys/time.h \ + /usr/include/bits/types/struct_timeval.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \ + /usr/include/bits/types/__sigset_t.h /usr/include/dirent.h \ + /usr/include/bits/dirent.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/dirent_ext.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/math.h \ + /usr/include/bits/libc-header-start.h /usr/include/bits/math-vector.h \ + /usr/include/bits/libm-simd-decl-stubs.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/bits/flt-eval-method.h \ + /usr/include/bits/fp-logb.h /usr/include/bits/fp-fast.h \ + /usr/include/bits/mathcalls-macros.h \ + /usr/include/bits/mathcalls-helper-functions.h \ + /usr/include/bits/mathcalls.h /usr/include/signal.h \ + /usr/include/bits/signum-generic.h /usr/include/bits/signum-arch.h \ + /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h /usr/include/bits/types/stack_t.h \ + /usr/include/sys/ucontext.h /usr/include/bits/sigstack.h \ + /usr/include/bits/sigstksz.h /usr/include/bits/ss_flags.h \ + /usr/include/bits/types/struct_sigstack.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h /usr/include/stdio.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/stdlib.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/sys/types.h /usr/include/bits/types/clock_t.h \ + /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \ + /usr/include/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \ + /usr/include/alloca.h /usr/include/bits/stdlib-float.h \ + /usr/include/string.h /usr/include/bits/types/locale_t.h \ + /usr/include/bits/types/__locale_t.h /usr/include/strings.h \ + /usr/include/syslog.h /usr/include/sys/syslog.h \ + /usr/include/bits/syslog-path.h /usr/include/time.h \ + /usr/include/bits/time.h /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h numver.h diff --git a/lib/subrou.h b/lib/subrou.h new file mode 100644 index 0000000..c7318a2 --- /dev/null +++ b/lib/subrou.h @@ -0,0 +1,129 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/************************************************/ +/* */ +/* Low level subroutine declaration */ +/* */ +/************************************************/ +#ifndef SUBROU +#define SUBROU + +#include +#include +#include +#include + + +#define APPNAME "mailleur" //application name +#define REALM APPNAME"-email" //application REALM (DIGEST-MD5) +#define ITSOK 0 //to check errno against no error + +//defining database #define +#define USE_NODB 0 //No DB TYPE defined +#define USE_POSTGRESQL 1 +#define USE_MYSQL 2 + +#define SQLENV 5 //number of ENV parameters for + //SQL definition + +typedef void (*genfree_t)(void *); + +typedef struct timespec TIMESPEC; + +//--- Variables defined within subrou.c --------- +extern int debug; //application debug mode +extern _Bool foreground; //process is in foreground mode + +extern char *dbglive; //string to check for live debugging +extern char *rootdir; //application root directory +extern char *appname; //application "official" name +extern char execname[]; //Application exec/binary name + +//--- Routines implemented within subrou.c --------- + +//open/close memory leak detector. +extern void rou_checkleak(_Bool onoff); + +//procedure to assign memory according a format and va list +extern int rou_vasprintf(char **str,const char *fmt,va_list ap); + +//procedure to assign memory according a format and parameter list +extern int rou_asprintf(char **str,const char *fmt,...); + +//procedure to return the application working realm +extern const char *rou_getrealm(); + +//procedure to create needed subdirectory +extern _Bool rou_do_mkpdir(char *dirpath); + +//procedure to get the time difference between the current +//time and a TIMESPEC starttime +extern unsigned rou_getdifftime(TIMESPEC *start); + +//procedure to return the current number of milli-second +extern unsigned int rou_getmillisec(); + +//transform local system time in ASCII stamp. +extern char *rou_ascsysstamp(time_t curtime); + +//return program version +extern const char *rou_getversion(); + +//Procedure to free a string pointer and return +//a NULL pointer +extern char *rou_freestr(char *str); + +//procedure to remove '\r' or '\n' at end of a line +extern char *rou_stripcrlf(char *line); + +//to return the number of element within a list +extern int rou_nbrlist(void **list); + +//to add a not null pointer to a list of pointer +extern void **rou_addlist(void **list,void *entry); + +//Procedure to free one entry part of list +//return true if found, false otherwise. +extern _Bool rou_rmlist(void **list,void *entry,genfree_t handler); + +//Procedure to free all entries of list +extern void **rou_freelist(void **list,genfree_t handler); + +//change the application name +extern char *rou_setappname(const char *newname); + +//change the execname name +extern const char *rou_setexecname(const char *newexecname); + +//to compute an application path with the root directory +extern char *rou_apppath(const char *path); + +//to display message on console (verbose mode) or +//via syslog (LOG_INFO) using variable argument list macros +void rou_valert(const int dlevel,const char *fmt,va_list ap); + +//return a difference between 2 chrono +//to display message on console (verbose mode) or +//via syslog (LOG_DAEMON) +extern void rou_alert(const int dlevel,const char *fmt,...); + +//procedure to debug live daemon process +extern void rou_dbglive(const int dlevel,const char *prcref,const char *fmt,...); + +//To do an on purpose crash the application with an +//explication message +extern void rou_crash(const char *fmt,...); + +//To do an on purpose application memory core dump +//with an explication message +extern void rou_core_dump(const char *fmt,...); + +//clean configuration file line +extern char *rou_clean_conf_line(char *line); + +//load/unload environement configuration +extern void rou_loadconfig(char *conffile,_Bool load); + +//homework to be done before starting/stoping module. +extern int rou_modesubrou(_Bool mode); + +#endif diff --git a/lib/toremake b/lib/toremake new file mode 100644 index 0000000..e69de29 diff --git a/lib/unidig.c b/lib/unidig.c new file mode 100644 index 0000000..e746563 --- /dev/null +++ b/lib/unidig.c @@ -0,0 +1,501 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Implement all procedure to use digest-md5 */ +/* authentication exchange. */ +/* */ +/********************************************************/ +#include +#include +#include +#include + +#include "subrou.h" +#include "subcnv.h" +#include "unidig.h" + +#define ALGO "md5-sess" +#define MAXBUF 2000 +#define CHARSET "utf-8" +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to scan data and take care of the */ +/* data format "abc\"def" to become abc\"def */ +/* */ +/********************************************************/ +static void scanliteral(char *data) + +{ +if (*data=='"') { + char *ptr; + + (void) memmove(data,data+1,strlen(data+1)+1); + while ((ptr=strchr(data,'"'))!=(char *)0) { + if (strlen(data)>strlen(ptr)) { + if (*(ptr-1)=='\\') { + data=ptr+1; + continue; + } + } + *ptr='\000'; + } + } +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to scan ONE entry from the challenge */ +/* response. */ +/* */ +/********************************************************/ +static void scanfield(RSPTYP *resp,char *entry) + +{ +static char *voc[]={ + "charset", + "cnonce", + "digest-uri", + "nc", + "nonce", + "qop", + "realm", + "response", + "username", + (char*)0 + }; + +if (strlen(entry)>0) { + char *ptr; + + if ((ptr=strchr(entry,'='))!=(char *)0) { + int num; + + *ptr='\000'; + ptr++; + (void) scanliteral(ptr); + for (num=0;voc[num]!=(char *)0;num++) { + if (strcasecmp(voc[num],entry)!=0) + continue; + switch (num) { + case 0 : //charset + resp->charset=rou_freestr(resp->charset); + resp->charset=strdup(ptr); + break; + case 1 : //cnonce + resp->cnonce=rou_freestr(resp->cnonce); + resp->cnonce=strdup(ptr); + break; + case 2 : //digest-uri + resp->digesturi=rou_freestr(resp->digesturi); + resp->digesturi=strdup(ptr); + break; + case 3 : //nc (unsigned long) + (void) sscanf(ptr,"%lx",&(resp->nc)); + break; + case 4 : //nonce + resp->nonce=rou_freestr(resp->nonce); + resp->nonce=strdup(ptr); + break; + case 5 : //qop + resp->qop=rou_freestr(resp->qop); + resp->qop=strdup(ptr); + break; + case 6 : //realm + resp->realm=rou_freestr(resp->realm); + resp->realm=strdup(ptr); + break; + case 7 : //response + resp->response=rou_freestr(resp->response); + resp->response=strdup(ptr); + break; + case 8 : //username + resp->username=rou_freestr(resp->username); + resp->username=strdup(ptr); + break; + default : + (void) rou_alert(0,"name=<%s> field=<%s>",entry,ptr); + break; + } + } + } + } +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to free all memroy used by a response */ +/* type structure. */ +/* */ +/********************************************************/ +PUBLIC RSPTYP *dig_freeresp(RSPTYP *resp) + +{ +if (resp!=(RSPTYP *)0) { + resp->response=rou_freestr(resp->response); + resp->charset=rou_freestr(resp->charset); + resp->qop=rou_freestr(resp->qop); + resp->cnonce=rou_freestr(resp->cnonce); + resp->nonce=rou_freestr(resp->nonce); + resp->digesturi=rou_freestr(resp->digesturi); + resp->realm=rou_freestr(resp->realm); + resp->username=rou_freestr(resp->username); + (void) free(resp); + resp=(RSPTYP *)0; + } +return resp; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to parse the challenge structure and */ +/* return an RSPTYP pointer structure */ +/* */ +/********************************************************/ +PUBLIC RSPTYP *dig_parseresp(char *response) + +{ +#define OPEP "unidig.c:dig_parseresp," + +RSPTYP *resp; + +resp=(RSPTYP *)0; +if ((response!=(char *)0)&&(strlen(response)>0)) { + char *cpy; + char *next; + + resp=calloc(1,sizeof(RSPTYP)); + cpy=strdup(response); + next=cpy; + while (next!=(char *)0) { + char *ptr; + + if ((ptr=strchr(next,','))!=(char *)0) { + *ptr='\000'; + ptr++; + } + (void) scanfield(resp,next); + next=ptr; + } + cpy=rou_freestr(cpy); + } +return resp; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to hash a string with MD5 hash */ +/* an return a 16+1 Bytes. */ +/* */ +/********************************************************/ +PUBLIC MD5TYP *dig_hashmd5(unsigned char *seq,unsigned int length) + +{ +#define OPEP "subdig.c:dig_hashmd5," + +MD5TYP *md5; +EVP_MD_CTX *mdctx; +int phase; +_Bool proceed; + +md5=(MD5TYP *)0; +mdctx=(EVP_MD_CTX *)0; +phase=1; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //do we hae a sequence? + if ((seq==(unsigned char *)0)&&(length==0)) + phase=999; //no need to go further + break; + case 1 : //getting md5 context + if ((mdctx=EVP_MD_CTX_new())==(EVP_MD_CTX *)0) { + (void) rou_alert(0,"%s Unable to open MD5 context (System?)",OPEP); + phase=999; //no need to go further + } + break; + case 2 : //doing hashing + (void) EVP_DigestInit_ex(mdctx,EVP_md5(),(ENGINE *)0); + (void) EVP_DigestUpdate(mdctx,seq,length); + break; + case 3 : { //assign memory + unsigned int s; + + md5=calloc(1,sizeof(MD5TYP)); + (void) EVP_DigestFinal_ex(mdctx,(unsigned char *)md5,&s); + EVP_MD_CTX_free(mdctx); + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return md5; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to crypt a string with MD5 hash */ +/* function. */ +/* */ +/********************************************************/ +PUBLIC char *dig_cryptmd5(const void *key,unsigned char *seq) + +{ +#define OPEP "subdig.c:dig_hashmd5," + +char *hashmd5; //function result +unsigned char *d5; //md5 hash result +u_int reslen; +int phase; +int proceed; + +hashmd5=(char *)0; +d5=(unsigned char *)0; +reslen=-1; +phase=1; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //do ve have good parameters + if ((key==(const void *)0)||(seq==(unsigned char *)0)) { + (void) rou_alert(0,"%s key or seq undefined (Bug?)",OPEP); + phase=999; + } + break; + case 1 : //computing sequence + d5=HMAC(EVP_md5(),key,strlen(key),seq,strlen((const char *)seq),d5,&reslen); + if (d5==(unsigned char *)0) { + (void) rou_alert(0,"%s No MD5 for key=<%s> and seq=<%s> (Bug?)", + OPEP,(char *)key,seq); + phase=999; + } + break; + case 2 : //duplicate md5 result + if (reslen>0) { + hashmd5=(char *)calloc(reslen+1,sizeof(char)); + (void) memmove((void *)hashmd5,(void *)d5,reslen); + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return hashmd5; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to convert an MD5TYP array in */ +/* hexadecimal structure to be a pure/plain MD5TYP */ +/* array. */ +/* Return (MD5TYP *)0 if trouble. */ +/* */ +/********************************************************/ +PUBLIC MD5TYP *dig_get_plain_md5(char *hexa) + +{ +MD5TYP *plain; + +plain=(MD5TYP *)0; +if (strlen(hexa)==sizeof(MD5TYP)*2) { + _Bool ok; + MD5TYP travail; + char tmp[3]; + + ok=true; + (void) memset(travail,'\000',sizeof(travail)); + (void) memset(tmp,'\000',sizeof(tmp)); + for (register int i=0;i0) + (void) strcat(challenge,loc); + } +return challenge; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to compute local response to challenge*/ +/* and check if the compupted answer is the same as*/ +/* reponse available within RSPTYP record. */ +/* */ +/********************************************************/ +PUBLIC char *dig_hashresp(RSPTYP *resp,char *mode,char *hash) + +{ +#define OPEP "unidig.c:dig_hashresp," + +char *HA0; +char *HA1; +char *HA2; +MD5TYP *A1; +char seq[400]; +int phase; +_Bool proceed; + + +HA0=(char *)0; +HA1=(char *)0; +HA2=(char *)0; +(void) memset(seq,'\000',sizeof(seq)); +phase=0; +proceed=(resp!=(RSPTYP *)0); +while (proceed==true) { + switch (phase) { + case 0 : //computing A1 from data-base contents + A1=dig_get_plain_md5(hash); + if (A1==(MD5TYP *)0) { + (void) rou_alert(0,"%s Unable to convert hash=<%s>",OPEP,hash); + phase=999; //trouble trouble + } + break; + case 1 : { //computing hash HA1 + char *ptr; + int max; + + //starting algorithm value is "MD5-sess" + (void) memset(seq,'\000',sizeof(seq)); + (void) memmove(seq,(char *)A1,sizeof(MD5TYP)); + (void) free(A1); + ptr=seq+sizeof(MD5TYP); + max=sizeof(seq)-sizeof(MD5TYP); + (void) snprintf(ptr,max,":%s:%s",resp->nonce,resp->cnonce); + A1=dig_hashmd5((unsigned char *)seq,sizeof(MD5TYP)+strlen(ptr)); + //ending algorithm value is "MD5-sess" + HA1=cnv_tohexa((char *)A1,sizeof(MD5TYP)); + (void) free(A1); + } + break; + case 2 : { //computing HA2 + MD5TYP *A2; + + (void) snprintf(seq,sizeof(seq),"%s:%s",mode,resp->digesturi); + A2=dig_hashmd5((unsigned char *)seq,strlen(seq)); + HA2=cnv_tohexa((char *)A2,sizeof(MD5TYP)); + (void) free(A2); + } + break; + case 3 : { //computing response + MD5TYP *A0; + + (void) snprintf(seq,sizeof(seq),"%s:%s:%08lx:%s:%s:%s", + HA1,resp->nonce,resp->nc, + resp->cnonce,resp->qop,HA2); + A0=dig_hashmd5((unsigned char *)seq,strlen(seq)); + HA0=cnv_tohexa((char *)A0,sizeof(MD5TYP)); + (void) free(A0); + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +HA2=rou_freestr(HA2); +HA1=rou_freestr(HA1); +(void) rou_alert(0,"JMPDBG mode=<%s> HA0=<%s>",mode,HA0); +return HA0; + +#undef OPEP +} diff --git a/lib/unidig.d b/lib/unidig.d new file mode 100644 index 0000000..774d5b5 --- /dev/null +++ b/lib/unidig.d @@ -0,0 +1,72 @@ +unidig.o unidig.d : unidig.c /usr/include/stdc-predef.h /usr/include/openssl/evp.h \ + /usr/include/openssl/macros.h /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/configuration.h /usr/include/openssl/opensslv.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/stdio.h /usr/include/bits/libc-header-start.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/types/__fpos_t.h \ + /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/openssl/types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/limits.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h /usr/include/bits/posix2_lim.h \ + /usr/include/openssl/e_os2.h /usr/include/sys/types.h \ + /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/time_t.h /usr/include/bits/types/timer_t.h \ + /usr/include/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/endianness.h \ + /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/inttypes.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdint.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/bits/stdint-uintn.h /usr/include/bits/stdint-least.h \ + /usr/include/openssl/safestack.h /usr/include/openssl/stack.h \ + /usr/include/openssl/core.h /usr/include/openssl/core_dispatch.h \ + /usr/include/openssl/indicator.h /usr/include/openssl/params.h \ + /usr/include/openssl/bn.h /usr/include/openssl/crypto.h \ + /usr/include/stdlib.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/time.h \ + /usr/include/bits/time.h /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/openssl/cryptoerr.h /usr/include/openssl/symhacks.h \ + /usr/include/openssl/cryptoerr_legacy.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include-fixed/pthread.h \ + /usr/include/sched.h /usr/include/bits/sched.h \ + /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \ + /usr/include/bits/setjmp.h \ + /usr/include/bits/types/struct___jmp_buf_tag.h \ + /usr/include/openssl/bnerr.h /usr/include/openssl/bio.h \ + /usr/include/openssl/bioerr.h /usr/include/openssl/evperr.h \ + /usr/include/openssl/objects.h /usr/include/openssl/obj_mac.h \ + /usr/include/openssl/asn1.h /usr/include/openssl/asn1err.h \ + /usr/include/openssl/objectserr.h /usr/include/openssl/hmac.h \ + /usr/include/string.h /usr/include/strings.h subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h subcnv.h \ + unidig.h diff --git a/lib/unidig.h b/lib/unidig.h new file mode 100644 index 0000000..8b1856c --- /dev/null +++ b/lib/unidig.h @@ -0,0 +1,51 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Define all procedure to use digest-md5 */ +/* authentication exchanges. */ +/* */ +/********************************************************/ +#ifndef UNIDIG +#define UNIDIG + +typedef struct { //DIGEST-MD5 challange response structure + char *username; //username requesting authentication + char *realm; //Challenge realm + char *digesturi;//Type of digest + char *nonce; //server nonce + char *cnonce; //client nonce + u_long nc; //nonce count + char *qop; //protection quality (authentication) + char *charset; //used carset + char *response; //Challenge md5 response + }RSPTYP; + +//MD5 hashing result +typedef unsigned char MD5TYP[16]; + +//procedure to free the response structure +extern RSPTYP *dig_freeresp(RSPTYP *resp); + +//procedure to parse a challenge answer and return +//the structure +extern RSPTYP *dig_parseresp(char *response); + +//procedure to hash (md5) a string result is a MD5 arrays +extern MD5TYP *dig_hashmd5(unsigned char *seq,unsigned int length); + +//procedure to convert an MD5 string (HEXA representation) +//to an pure MD5TYP structure +extern MD5TYP *dig_get_plain_md5(char *hexa); + +//Procedure to crypt a string with MD5 hash function +extern char *dig_cryptmd5(const void *key,unsigned char *seq); + +//Procedure to generate a DISGEST-MD5 challaneg as a +//b64 string. +extern char *dig_getchallenge(); + +//Procedure to compute local response to challenge and +//check if the remote session is the same +extern char *dig_hashresp(RSPTYP *resp,char *mode,char *hash); + +#endif diff --git a/lib/unidns.c b/lib/unidns.c new file mode 100644 index 0000000..ba7dc40 --- /dev/null +++ b/lib/unidns.c @@ -0,0 +1,814 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Implement all routine to manage SMTP low level */ +/* exchange. */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "unidns.h" + +//spf1 marker within DNS record +#define SPF1 "v=spf1 " + +#define B64K 65536 //according US Cert VU#738331 +typedef union { + HEADER hdr; //defined in resolv.h + u_char buf[B64K]; //according US Cert VU#738331 + }RSPTYP; + +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to compare 2 MX and return */ +/* a value according preference value */ +/* */ +/********************************************************/ +static int cmpmx(const void *p1,const void *p2) + +{ +MXTYP *m1; +MXTYP *m2; + +m1=((MXTYP **)p1)[0]; +m2=((MXTYP **)p2)[0]; +return m1->preference-m2->preference; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to query DNS information */ +/* */ +/********************************************************/ +static int myquery(const char *dname,int class,int type, + unsigned char *answer, int anslen) + +{ +#define OPEP "unidns.c:myquery," + +int got; + +if ((got=res_query(dname,class,type,answer,anslen))<0) { + got=-1; /*trouble trouble*/ + switch (errno) { + case 0 : /* do not care */ + got=0; /*NO answer! */ + break; + case ETIMEDOUT : /*rqst timed out*/ + (void) rou_alert(0,"%s Timeout on domain <%s>!",OPEP,dname); + break; + default : + (void) rou_alert(0,"%s query error for domain <%s> type='%d' " + "(error=<%d/%s>)",OPEP,dname,type,errno,strerror(errno)); + } + } +else { + if (got>anslen) { + (void) rou_alert(0,"%s query too by for domain <%s> type='%d' (got=%d)", + OPEP,dname,type,got); + got=anslen; + } + } +return got; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to extract text information */ +/* from DNS record. */ +/* */ +/********************************************************/ +static char **extracting(RSPTYP *rsp,int rsplen,const char *request,char *field) + +{ +#define OPEP "unidns.c:extracting," + +char **list; +int question; +int answer; +const unsigned char *msg; +const unsigned char *eom; +const unsigned char *cp; +int rc; +char buf[NS_PACKETSZ+1]; + +list=(char **)0; +question=ntohs(rsp->hdr.qdcount); +answer=ntohs(rsp->hdr.ancount); +msg=(unsigned char *)rsp; +eom=(unsigned char *)rsp+rsplen; +cp=(unsigned char *)rsp+sizeof(HEADER); +while ((question-->0)&&(cp0)&&(cp0) { + int type; + int class; + long ttl; + int dlen; + int collected; + const unsigned char *txtptr; + char *dynbuf; + + cp+=rc; + GETSHORT(type,cp); + GETSHORT(class,cp); + GETLONG(ttl,cp); + GETSHORT(dlen,cp); + if (class!=1) { + (void) rou_alert(0,"%s unexpected class='%d' on request " + "<%s> field=<%s> (ttl='%d')", + OPEP,class,request,field,ttl); + cp+=dlen; + break; /*no need to go further */ + } + collected=0; + dynbuf=(char *)0; + switch (type) { + case T_MX : + if ((rc=dn_expand(msg,eom,cp+2,(char *)buf,sizeof(buf)-1))>0) { + int pref; + char info[30]; + + pref=(((unsigned int)cp[0])<<8)|((unsigned int)cp[1]); + (void) snprintf(info,sizeof(info),"%d",pref); + list=(char **)rou_addlist((void **)list,(void *)strdup(info)); + list=(char **)rou_addlist((void **)list,(void *)strdup(buf)); + } + break; + case T_CNAME : + #ifdef GETCNAME_2011 + /*we are not interested to collect CNAME for now (JMP Feb 2011) */ + if ((rc=dn_expand(msg,eom,cp,(char *)buf,sizeof(buf)))>0) { + list=(char **)rou_addlist((void **)list,(void *)strdup("100")); + list=(char **)rou_addlist((void **)list,(void *)strdup(buf)); + } + #endif + break; + case T_SPF : + case T_TXT : + txtptr=cp; + dynbuf=(char *)calloc(10,sizeof(char)); + while (collected0) { + list=(char **)rou_addlist((void **)list,(void *)strdup(buf)); + } + break; + default : + (void) rou_alert(0,"%s Unexpected '%d' field",OPEP,type); + break; + } + cp+=dlen; + } + } +return list; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to extract a domain TXT */ +/* If the domain doesn't exist or domain */ +/* do not have a TXT, a void pointer is */ +/* returned. */ +/* */ +/********************************************************/ +static char **gettxt(char *domain,int ttype,char *field) + +{ +char **inftxt; +int answer; +RSPTYP rsp; + +inftxt=(char **)0; +(void) memset(rsp.buf,'\000',sizeof(rsp.buf)); +switch (answer=myquery(domain,C_IN,ttype,rsp.buf,sizeof(rsp.buf))) { + case -1 : /*timeout */ + break; + case 0 : /*no data available */ + break; + default : /*data */ + inftxt=extracting(&rsp,answer,domain,field); + break; + } +return inftxt; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Routine to extract ipaddr from addr */ +/* */ +/********************************************************/ +static char *addrip(struct addrinfo *addinf) + +{ +static char straddr[INET6_ADDRSTRLEN]; + +char *ipaddr; +void *addr; + +ipaddr=straddr; +addr=(void *)0; +switch (addinf->ai_family) { + case AF_INET6 : /*IPV6 */ + addr=&(((struct sockaddr_in6 *)addinf->ai_addr)->sin6_addr); + break; + case AF_INET : /*IPV4 */ + default : + addr=&(((struct sockaddr_in *)addinf->ai_addr)->sin_addr); + break; + } +if (inet_ntop(addinf->ai_family,addr,straddr,sizeof(straddr))==(char *)0) { + (void) rou_alert(0,"%s Unable to find IP for hostname <%s> (error=<%s>)", + "unidns.c:dns_addrip,",addinf->ai_canonname,strerror(errno)); + ipaddr=(char *)0; + } +return ipaddr; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Routine to extract iplist in string format from */ +/* addr list. */ +/* */ +/********************************************************/ +static char **addriplist(struct addrinfo *addrlst) + +{ +char **iplist; +struct addrinfo *pif; + +iplist=(char **)0; +for (pif=addrlst;pif!=(struct addrinfo *)0;pif=pif->ai_next) { + char *straddr; + + if ((straddr=addrip(pif))!=(char *)0) + iplist=(char **)rou_addlist((void **)iplist,(void *)strdup(straddr)); + } +return iplist; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to free memory used by BLKTYP entry */ +/* */ +/********************************************************/ +PUBLIC BLKTYP *dns_freeblk(BLKTYP *blk) + +{ +if (blk!=(BLKTYP *)0) { + blk->sitename=rou_freestr(blk->sitename); + blk->targets=(char **)rou_freelist((void **)blk->targets, + (genfree_t)rou_freestr); + (void) free(blk); + blk=(BLKTYP *)0; + } +return blk; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to add and entry with the list of */ +/* blacklist site. */ +/* */ +/********************************************************/ +PUBLIC BLKTYP **dns_addblklist(BLKTYP **blklist,char *entry) + + +{ +#define OPEP "unidns.c:dns_addblklist," + +if ((entry!=(char *)0)&&(strlen(entry)>0)) { + int delta; + int sofar; + char sitename[300]; + + (void) memset(sitename,'\000',sizeof(sitename)); + sofar=0; + if (sscanf(entry,"%d %s%n",&delta,sitename,&sofar)==2) { + char **targets; + BLKTYP *blk; + char *ptr; + + targets=(char **)0; + blk=calloc(1,sizeof(BLKTYP)); + blk->delta=delta; + blk->sitename=strdup(sitename); + ptr=entry+sofar; + while ((ptr!=(char *)0)&&(strlen(ptr)>0)) { + char *coma; + + while ((*ptr==' ')||(*ptr=='\t')) + ptr++; + if ((coma=strchr(ptr,','))!=(char *)0) { + *coma='\000'; + coma++; + } + targets=(char **)rou_addlist((void **)targets,(void *)strdup(ptr)); + ptr=coma; + } + blk->targets=targets; + blklist=(BLKTYP **)rou_addlist((void **)blklist,(void *)blk); + } + else + (void) rou_alert(0,"%s, entry wrong format <%s> (config?)",OPEP,entry); + } +return blklist; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to extract IPs from an hostname */ +/* */ +/********************************************************/ +PUBLIC char **dns_get_ip_list(const char *hostname) + +{ +char **iplst; +struct addrinfo hints; +struct addrinfo *res; + +iplst=(char **)0; +(void) memset(&hints,'\000',sizeof(hints)); +hints.ai_family=PF_UNSPEC; +hints.ai_socktype=SOCK_STREAM; +if (getaddrinfo(hostname,(char *)0,&hints,&res)==0) { + iplst=addriplist(res); + (void) freeaddrinfo(res); + } +return iplst; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to extract a hostname SPF */ +/* Search first for an SPF record, if not */ +/* implemented search for a TXT record */ +/* If the domain doesn't exist or domain */ +/* do not have a TXT or SPF, a void pointer */ +/* is returned. */ +/* */ +/********************************************************/ +PUBLIC char *dns_getspf(char *domain) + +{ +char *spfrec; +char **list; + +spfrec=(char *)0; +if ((list=gettxt(domain,T_SPF,"SPF"))==(char **)0) + list=gettxt(domain,T_TXT,"TXT"); +if (list!=(char **)0) { + char **ptr; + + ptr=list; + while (*ptr!=(char *)0) { + if (strstr(*ptr,SPF1)==*ptr) { + spfrec=strdup(*ptr+strlen(SPF1)); + break; + } + ptr++; + } + list=(char **)rou_freelist((void **)list,(genfree_t)rou_freestr); + } +return spfrec; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to free memory used by a list of */ +/* MXTYP. */ +/* */ +/********************************************************/ +PUBLIC MXTYP **dns_freemxlist(MXTYP **mxlist) + +{ +if (mxlist!=(MXTYP **)0) { + for (int i=0;mxlist[i]!=(MXTYP *)0;i++) { + mxlist[i]->mxip=(char **)rou_freelist((void **)mxlist[i]->mxip, + (genfree_t)rou_freestr); + mxlist[i]->mxname=rou_freestr(mxlist[i]->mxname); + (void) free(mxlist[i]); + } + (void) free(mxlist); + mxlist=(MXTYP **)0; + } +return mxlist; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to extract a domain MX. */ +/* If the domain doesn't exist or domain */ +/* do not have a MX, a void pointer is */ +/* returned. */ +/* Retuned list is ordered according */ +/* MX preference (low preference first) */ +/* */ +/********************************************************/ +PUBLIC MXTYP **dns_getmx(const char *domain) + +{ +#define OPEP "unidns.c:dns_getmx" + +MXTYP **mxlist; +char **list; +int answer; +RSPTYP rsp; +int phase; +_Bool proceed; + +mxlist=(MXTYP **)0; +list=(char **)0; +answer=0; +(void) memset(&rsp,'\000',sizeof(rsp)); +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Are the parameters available + if ((domain==(char *)0)||(strlen(domain)==0)) { + (void) rou_alert(0,"%s missing domainname",OPEP); + phase=999; //trouble trouble + } + break; + case 1 : //cleaning domain + if (domain!=(char *)0) { //always + char *ptr; + + if ((ptr=strchr(domain,'@'))!=(char *)0) { + ptr++; + if (strlen(ptr)==0) { + (void) rou_alert(0,"%s Incorrect domainname <%s>",OPEP,domain); + phase=999; //trouble trouble + } + domain=ptr; + } + } + break; + case 2 : //Requesting MX for domain + answer=myquery(domain,C_IN,T_MX,rsp.buf,sizeof(rsp.buf)); + if (answer<=0) + phase=999; //Trouble trouble to get MX + break; + case 3 : //extracting result + if (answer>=sizeof(rsp.buf)) + answer=sizeof(rsp.buf)-1; + list=extracting(&rsp,answer,domain,"MX"); + if (list==(char **)0) + phase=999; //list empty? + break; + case 4 : //ordering list + answer=0; + for (int i=0;list[i]!=(char *)0;i+=2) { + if ((list[i+1]!=(char *)0)&&(strlen(list[i+1])>0)) { + MXTYP *mx; + + mx=(MXTYP *)calloc(1,sizeof(MXTYP)); + mx->preference=atoi(list[i]); + mx->mxname=strdup(list[i+1]); + mx->mxip=dns_get_ip_list(mx->mxname); + //(void) rou_alert(0,"%s JMPDBG MX[%d]=<%s>",OPEP,i,mx->mxname); + mxlist=(MXTYP **)rou_addlist((void **)mxlist,(void *)mx); + answer++; + } + } + if (answer>0) + (void) qsort((void *)mxlist,answer,sizeof(MXTYP *),cmpmx); + list=(char **)rou_freelist((void **)list,(genfree_t)rou_freestr); + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return mxlist; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to check if an IP (Origin IP) is */ +/* part of domain A record list */ +/* */ +/********************************************************/ +_Bool dns_matchiprec(char *hostname,AFNTYP *afnnum,int mask) + +{ +#define OPEP "unidns.c:dns_matchiprec," + +_Bool match; +struct addrinfo hints; +struct addrinfo *res; +int status; + +match=false; +(void) memset(&hints, 0, sizeof(hints)); +hints.ai_family=PF_UNSPEC; +hints.ai_socktype=SOCK_STREAM; +hints.ai_flags=HINTFLG; +if ((status=getaddrinfo(hostname,"",&hints,&res))==0) { + match=true; + if (mask!=0) {/*do not compare IP with 0/0,::0*/ + int proceed; + struct addrinfo *rp; + + proceed=true; + match=false; + for (rp=res;rp!=(struct addrinfo *)0;rp=rp->ai_next) { + AFNTYP *addrnum; + + if ((addrnum=afn_getaddrinfo(rp))==(AFNTYP *)0) { + (void) rou_alert(0,"%s Unable to resolve addr struct for " + "hostname <%s> (bug?)", + OPEP,hostname,strerror(errno)); + continue; + } + switch (afn_cmpipnum(addrnum,afnnum,mask)) { + case false :/*no equal continue */ + break; + case true :/*found it equal! */ + match=true; + proceed=false; + break; + case -1 :/*trouble trouble */ + (void) rou_alert(0,"%s Unable to compare IP for hostname " + "<%s> (error=<%s>)", + OPEP,hostname,strerror(errno)); + proceed=false; + break; + } + addrnum=afn_freeipnum(addrnum); + if (proceed==false) + break; + } + } + (void) freeaddrinfo(res); + } +else { + (void) rou_alert(0,"%s Unable to get '%s' host IP (error='%s')", + OPEP,hostname,gai_strerror(status)); + } +return match; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to check if a domain is handle by the */ +/* local interface (serveur is primary MX). */ +/* */ +/********************************************************/ +PUBLIC LOCTYP dns_is_domain_local(const char *domain,AFNTYP **afns) + + +{ +#define OPEP "unidns.c:dns_is_domain_local," + +LOCTYP status; +MXTYP **dns; +int phase; +_Bool proceed; + +status=dns_nomx; +dns=(MXTYP **)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 domain + if ((domain==(char *)0)||(strlen(domain)==0)) + phase=999; //No domain (Bug?) + break; + case 1 : //getting MX list + if ((dns=dns_getmx(domain))!=(MXTYP **)0) + phase++; //Ok, we have an MX list + break; + case 2 : { //what is the domain IP + char **ipl; + + if ((ipl=dns_get_ip_list(domain))!=(char **)0) { + MXTYP *mx0; + + ipl=(char **)rou_freelist((void **)ipl,(genfree_t)rou_freestr); + mx0=(MXTYP *)calloc(1,sizeof(MXTYP)); + mx0->preference=0; + mx0->mxname=strdup(domain); + dns=(MXTYP **)rou_addlist((void **)dns,(void *)mx0); + } + else + phase=999; //no MX, no IP! + } + break; + case 3 : //establishing MX IP + status=dns_remote; + if (afns==(AFNTYP **)0) //No local IP? + phase=999; + break; + case 4 : //checking best MX with local interface + while (*afns!=(AFNTYP *)0) { + _Bool ismx; + + ismx=dns_matchiprec((*dns)->mxname,*afns,32); + if (ismx==true) { + status=dns_local; + break; + } + afns++; + } + break; + default : //SAFE Guard + dns=dns_freemxlist(dns); //cleaning MX + proceed=false; + break; + } + phase++; + } +return status; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to probe one black list site about the*/ +/* remote IP and return a TXT if it is blacklisted.*/ +/* */ +/********************************************************/ +PUBLIC char *dns_is_blacklisted(BLKTYP *blk,char *reversip) + +{ +#define OPEP "unidns.c:dns_is_blacklisted," + +char *listed; +char **txt; +char dnsquest[300]; +int phase; +_Bool proceed; + +listed=(char *)0; +phase=0; +proceed=(blk->targets!=(char **)0); +while (proceed==true) { + switch (phase) { + case 0 : //Building the request + (void) snprintf(dnsquest,sizeof(dnsquest),"%s.%s",reversip,blk->sitename); + break; + case 1 : //do we have a list of IP + if ((txt=gettxt(dnsquest,T_A,"TXT"))==(char **)0) + phase=999; //No answer no need to go further + break; + case 2 : { //chek is the list of IP ia amongs targets + char *foundit; + char **ptr; + + foundit=(char *)0; + ptr=txt; + while ((*ptr!=(char *)0)&&(foundit==(char *)0)) { + char **tgt; + + tgt=blk->targets; + while (*tgt!=(char *)0) { + if (strcmp(*tgt,*ptr)==0) { + foundit=*tgt; + break; + } + tgt++; + } + ptr++; + } + txt=(char **)rou_freelist((void **)txt,(genfree_t)rou_freestr); + if (foundit==(char *)0) + phase=999; + } + break; + case 3 : //get the explainantion + if ((txt=gettxt(dnsquest,T_TXT,"TXT"))!=(char **)0) { + (void) rou_asprintf(&listed,"%s -> %s",blk->sitename,txt[0]); + txt=(char **)rou_freelist((void **)txt,(genfree_t)rou_freestr); + phase=999; //every thing found + } + break; + case 4 : //blakc list but no explaination? + (void) rou_alert(0,"%s <%s> blacklisted but no explainantion!", + OPEP,dnsquest); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return listed; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to extract the IP reverse address */ +/* Return "No-reverse" if unknown. */ +/* */ +/********************************************************/ +PUBLIC char *dns_get_reverse_addr(char *reversip) + +{ +#define OPEP "unidns.c:dns_get_reverse_addr," + +char *reverse; +char **txt; +char dnsquest[300]; + +reverse=(char *)0; +(void) snprintf(dnsquest,sizeof(dnsquest),"%s.%s",reversip,"in-addr.arpa"); +//(void) rou_alert(0,"%s JMPDBG checking <%s>",OPEP,dnsquest); +if ((txt=gettxt(dnsquest,T_PTR,"PTR"))!=(char **)0) { + (void) rou_asprintf(&reverse,"%s",txt[0]); + txt=(char **)rou_freelist((void **)txt,(genfree_t)rou_freestr); + } +if (reverse==(char *)0) + reverse=strdup(NORVERS); +return reverse; + +#undef OPEP +} diff --git a/lib/unidns.d b/lib/unidns.d new file mode 100644 index 0000000..df2c0d2 --- /dev/null +++ b/lib/unidns.d @@ -0,0 +1,82 @@ +unidns.o unidns.d : unidns.c /usr/include/stdc-predef.h /usr/include/arpa/inet.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/netinet/in.h /usr/include/bits/stdint-uintn.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/sys/socket.h \ + /usr/include/bits/types/struct_iovec.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/socket.h /usr/include/sys/types.h \ + /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/time_t.h /usr/include/bits/types/timer_t.h \ + /usr/include/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/endianness.h \ + /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/bits/socket_type.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm-generic/socket.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h /usr/include/asm/posix_types.h \ + /usr/include/asm/posix_types_64.h /usr/include/asm-generic/posix_types.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/bits/in.h \ + /usr/include/errno.h /usr/include/bits/errno.h \ + /usr/include/linux/errno.h /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/malloc.h /usr/include/stdio.h \ + /usr/include/bits/libc-header-start.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/resolv.h \ + /usr/include/sys/param.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/limits.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h /usr/include/bits/posix2_lim.h \ + /usr/include/signal.h /usr/include/bits/signum-generic.h \ + /usr/include/bits/signum-arch.h /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h /usr/include/bits/types/stack_t.h \ + /usr/include/sys/ucontext.h /usr/include/bits/sigstack.h \ + /usr/include/bits/sigstksz.h /usr/include/bits/ss_flags.h \ + /usr/include/bits/types/struct_sigstack.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h /usr/include/bits/param.h \ + /usr/include/linux/param.h /usr/include/asm/param.h \ + /usr/include/asm-generic/param.h /usr/include/arpa/nameser.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdint.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/bits/stdint-least.h /usr/include/arpa/nameser_compat.h \ + /usr/include/bits/types/res_state.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/stdlib.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/string.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/strings.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h unidns.h subafn.h \ + /usr/include/netdb.h /usr/include/rpc/netdb.h /usr/include/bits/netdb.h diff --git a/lib/unidns.h b/lib/unidns.h new file mode 100644 index 0000000..3a7860c --- /dev/null +++ b/lib/unidns.h @@ -0,0 +1,68 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Define all procedure to check SPF entry within */ +/* DNS record. */ +/* */ +/********************************************************/ +#ifndef UNIDNS +#define UNIDNS + +#include "subafn.h" + +#define NORVERS "No.Reverse" + +//defining an MX structure +typedef struct { + int preference; //MX preference + char *mxname; //MX hostname + char **mxip; //MX IPNUM list + }MXTYP; + +//defining a blacklist entrry +typedef struct { + int delta; //black list delta value + char *sitename; //black lister domain entry + char **targets; //listing entry; + }BLKTYP; + +typedef enum { //domain MX status + dns_nomx, //Domain without MX + dns_local, //Domain is local + dns_remote, //Domain is remote + dns_unknown //Unknow domain status. + }LOCTYP; + +//procedure to free on blklist entry +extern BLKTYP *dns_freeblk(BLKTYP *blk); + +extern BLKTYP **dns_addblklist(BLKTYP **blklist,char *entry); + +//Procedure to get a list of IP related to a hostname +extern char **dns_get_ip_list(const char *hostname); + +//Procedure to get ONE SPF entry within domain dns +extern char *dns_getspf(char *domain); + +//procedure to free a list of MX related to domain +extern MXTYP **dns_freemxlist(MXTYP **mxlist); + +//procedure to get a list of MX IP releated to a specific +//domain. +extern MXTYP **dns_getmx(const char *domain); + +//Procedure to check if an IP (Origin IP) is part +//of domain A record list +extern _Bool dns_matchiprec(char *hostname,AFNTYP *afnnum,int mask); + +//procedure to detect if a domain is served by a local +//smtp server +extern LOCTYP dns_is_domain_local(const char *domain,AFNTYP **afns); + +//procedure returning a string if remote IP si blacklisted +extern char *dns_is_blacklisted(BLKTYP *blk,char *reversip); + +//procedure returning the IP reverss address as a string +extern char *dns_get_reverse_addr(char *reversip); + +#endif diff --git a/lib/unieml.c b/lib/unieml.c new file mode 100644 index 0000000..5aedee3 --- /dev/null +++ b/lib/unieml.c @@ -0,0 +1,1079 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Implement all routine to manage SMTP low level */ +/* exchange. */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "subafn.h" +#include "subrou.h" +#include "unieml.h" + +//defining queued email repository +#define QDIR "/var/spool/"APPNAME"/queue" + +typedef struct { + CODTYP code; //keyword code + const char *key; //keyword itself + }VOCTYP; + +//this list order by key length +static VOCTYP vocsmtp[]={ + {c_auth,"AUTH"}, + {c_data,"DATA"}, + {c_ehlo,"EHLO"}, + {c_helo,"HELO"}, + {c_help,"HELP"}, + {c_mail,"MAIL FROM:"}, + {c_noop,"NOOP"}, +#if MODEDEBUG + {c_orgn,"ORGN:"}, +#endif + {c_quit,"QUIT"}, + {c_rcpt,"RCPT TO:"}, + {c_rset,"RSET"}, + {c_starttls,"STARTTLS"}, + {c_unknown,(const char *)0} + }; +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to free memory used by a list of */ +/* recipient. */ +/* */ +/********************************************************/ +PUBLIC RCPTYP *eml_freerecipient(RCPTYP *info) + +{ +if (info!=(RCPTYP *)0) { + info->userid=rou_freestr(info->userid); + info->domain=rou_freestr(info->domain); + (void) free(info); + info=(RCPTYP *)0; + } +return info; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to free memory used by the TRATYP */ +/* response part. */ +/* */ +/********************************************************/ +PUBLIC void eml_freetra_resp(TRATYP *tra) + +{ +if (tra!=(TRATYP *)0) { + tra->resp=(char **)rou_freelist((void **)tra->resp,(genfree_t)rou_freestr); + } +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to free memory used by a TRATYP record*/ +/* */ +/********************************************************/ +PUBLIC TRATYP *eml_freetra(TRATYP *tra) + +{ +if (tra!=(TRATYP *)0) { + (void) eml_freetra_resp(tra); + tra->hfrom=rou_freestr(tra->hfrom); + tra->hsubject=rou_freestr(tra->hsubject); + tra->reverse=rou_freestr(tra->reverse); + tra->remoteip=rou_freestr(tra->remoteip); + tra->rcptto=rou_freestr(tra->rcptto); + tra->sessid=rou_freestr(tra->sessid); + tra->sfrom=rou_freestr(tra->sfrom); + (void) free(tra); + tra=(TRATYP *)0; + } +return tra; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to free memory used by a tra list */ +/* */ +/********************************************************/ +PUBLIC TRATYP **eml_freeall_tra(TRATYP **tra) + +{ +return (TRATYP **)rou_freelist((void **)tra,(genfree_t)eml_freetra); +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to store an recipient information */ +/* within the contact list. */ +/* retuurn RCPTYP ** if successful, NULL otherwise.*/ +/* */ +/********************************************************/ +PUBLIC _Bool eml_addrecipient(RCPTYP ***list,RCPTYP *rcpt) + +{ +_Bool todo; + +todo=true; +if (*list!=(RCPTYP **)0) { + RCPTYP **ptr; + + ptr=*list; + while (*ptr!=(RCPTYP *)0) { + if ((strcasecmp((*ptr)->userid,rcpt->userid)==0) && + (strcasecmp((*ptr)->domain,rcpt->domain)==0)) { + todo=false; + break; //already within list + } + ptr++; + } + } +if (todo==true) { + *list=(RCPTYP **)rou_addlist((void **)(*list),(void *)rcpt); + } +return todo; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to format and return a dynamicaly */ +/* allocated char array filled with uniq session ID*/ +/* */ +/********************************************************/ +PUBLIC char *eml_getmainsesid() + +{ +#define UFTIME "%Y%m%d%H%M%S" +#define UNIQUE "%05d-%s-%04d" + +char *sesid; +time_t curtime; +char asctemps[100]; + +sesid=(char *)0; +curtime=time((time_t)0); +(void) strftime(asctemps,sizeof(asctemps),UFTIME,localtime(&curtime)); +(void) rou_asprintf(&sesid,UNIQUE,getpid(),asctemps,rou_getmillisec()); +return sesid; +#undef UNIQUE +#undef UFTIME +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to format and return a dynamicaly */ +/* allocated char array with the current seesion ID*/ +/* */ +/********************************************************/ +PUBLIC char *eml_getcursesid(char *mainsesid,int numreset) + +{ +char *sesid; + +sesid=(char *)0; +(void) rou_asprintf(&sesid,"%s-%04d",mainsesid,numreset); +return sesid; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return a protocol keywork code */ +/* */ +/********************************************************/ +PUBLIC CODTYP eml_getcode(char *keyword) + +{ +#define OPEP "unieml.c:eml_getcode" + +CODTYP code; +VOCTYP *ptr; + +code=c_unknown; +for (ptr=vocsmtp;ptr->key!=(char *)0;ptr++) { + if (strncasecmp(ptr->key,keyword,strlen(ptr->key))==0) { + char *par; + + code=ptr->code; + par=keyword+strlen(ptr->key); + *keyword='\000'; //lets say no parameters + if (*par=='\000') + break; //no parameters + //removing unneeded space + while ((*par==' ')||(*par=='\t')) + par++; + (void) memmove(keyword,par,strlen(par)+1); + break; + } + } +return code; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to remove crlf at the end of the */ +/* return true if CRLF was removed */ +/* */ +/********************************************************/ +PUBLIC int eml_removecrlf(char *string) + +{ +_Bool done; + +done=false; +if (string!=(char *)0) { + register int taille; + register char *ptr; + + taille=strlen(string)-1; + ptr=string+taille; + while ((*ptr=='\n') || (*ptr=='\r')) { + *ptr='\000'; + taille--; + done=true; + if (taille<0) + break; + ptr--; + } + } +return done; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to change qfile extension */ +/* directory. */ +/* */ +/********************************************************/ +PUBLIC _Bool eml_renameqfile(char *qfilename,const char *oldext,const char *newext) + +{ +#define OPEP "unieml.c:eml_renameqfile," + +_Bool status; +char *filename; +char fold[300]; +char fnew[300]; + +status=true; +filename=rou_apppath(QDIR); +(void) snprintf(fold,sizeof(fold),"%s/%s.%s",filename,qfilename,oldext); +(void) snprintf(fnew,sizeof(fnew),"%s/%s.%s",filename,qfilename,newext); +if (rename(fold,fnew)<0) { + char *cwd; + + cwd=get_current_dir_name(); + (void) rou_alert(0,"%s Unable to rename file <%s> to <%s> (error=<%s>)", + OPEP,fold,fnew,strerror(errno)); + (void) rou_alert(0,"%s current working dir=<%s>",OPEP,cwd); + cwd=rou_freestr(cwd); + status=false; + } +filename=rou_freestr(filename); +return status; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to remove a file from the queue */ +/* directory. */ +/* */ +/********************************************************/ +PUBLIC _Bool eml_deleteqfile(char *qfilename) + +{ +#define OPEP "unieml.c:eml_deleteqfile," + +_Bool done; +char *filename; +char fpath[300]; + +done=true; +filename=rou_apppath(QDIR); +(void) snprintf(fpath,sizeof(fpath),"%s/%s",filename,qfilename); +if (unlink(fpath)<0) { + (void) rou_alert(0,"%s Unable to delete file <%s> (error=<%s>) (Bug?)", + OPEP,fpath,strerror(errno)); + done=false; + } +filename=rou_freestr(filename); +return done; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to open a file within the queue */ +/* directory. */ +/* */ +/********************************************************/ +PUBLIC FILE *eml_createqfile(char *qfilename,const char *ext) + +{ +#define OPEP "unieml.c:eml_createqfile," + +FILE *qfile; +int handle; +char *filename; +int phase; +int proceed; + +qfile=(FILE *)0; +handle=-1; +filename=(char *)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 session ID + if ((qfilename==(char *)0)||(strlen(qfilename)==0)) { + (void) rou_core_dump("%s qfilename is not set (bug?)",OPEP); + phase=999; //never reached + } + break; + case 1 : //"Computing" the file new queue filename + filename=rou_apppath(QDIR); + filename=(char *)realloc(filename,strlen(filename)+strlen(qfilename)+10); + (void) strcat(filename,"/"); + (void) strcat(filename,qfilename); + if ((ext!=(char *)0)&&(strlen(ext)>0)) { + filename=(char *)realloc(filename,strlen(filename)+strlen(ext)+10); + (void) strcat(filename,"."); + (void) strcat(filename,ext); + } + break; + case 2 : //creating and opening the file + if ((handle=open(filename,O_EXCL|O_CREAT|O_WRONLY|O_TRUNC,0640))<0) { + (void) rou_alert(0,"%s Unable to open file <%s> (error=<%s>)", + OPEP,filename,strerror(errno)); + phase=999; //Trouble trouble + } + break; + case 3 : //convert handle to FILE * + if ((qfile=fdopen(handle,"w"))==(FILE *)0) { + (void) rou_alert(0,"%s Unable to fdopen file <%s> (error=<%s>)", + OPEP,filename,strerror(errno)); + } + break; + default : //SAFE guard + filename=rou_freestr(filename); + proceed=false; + break; + } + phase++; + } +return qfile; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to close the file to the email stored */ +/* stored within queue. */ +/* */ +/********************************************************/ +PUBLIC FILE *eml_closeqfile(FILE *qfile) + +{ +#define OPEP "unieml.c:eml_closeqfile," + +if (qfile!=(FILE *)0) { + if (fclose(qfile)<0) { + (void) rou_alert(0,"%s Unable to close qfile (error=<%s>)", + OPEP,strerror(errno)); + } + else + qfile=(FILE *)0; + } +return qfile; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to load a list of IP from which email */ +/* to a NONE local domain can be accepted and */ +/* relayed. */ +/* */ +/********************************************************/ +PUBLIC AFNTYP **eml_load_relayed(char *relayedfile) + +{ +#define OPEP "unieml.c:eml_load_relayed," + +AFNTYP **list; +char *filename; +FILE *relays; +int phase; +_Bool proceed; + +list=(AFNTYP **)0; +filename=(char *)0; +relays=(FILE *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Check if we have a ffilename + if ((relayedfile==(char *)0)||(strlen(relayedfile)==0)) { + (void) rou_alert(0,"%s No file name config?)",OPEP); + phase=999; //*no need to go further + } + break; + case 1 : //let open the relayable file + filename=rou_apppath(relayedfile); + if ((relays=fopen(filename,"r"))==(FILE *)0) { + (void) rou_alert(0,"%s Unable to open file <%s> (error=<%s>, config?)", + OPEP,filename,strerror(errno)); + phase=999; //No need to go further + } + break; + case 2 : { //scanning relayable contents + int num; + char format[40]; + char ip[80]; + char line[300]; + + num=0; + snprintf(format,sizeof(format),"%%%ld[^/]/%%d",sizeof(ip)); + while (fgets(line,sizeof(line)-1,relays)!=(char *)0) { + AFNTYP *afn; + int mask; + + num++; + (void) rou_clean_conf_line(line); + if (strlen(line)==0) + continue; + (void) memset(ip,'\000',sizeof(ip)); + if (sscanf(line,format,ip,&mask)<1) + continue; + if ((afn=afn_getoneipnum(ip))==(AFNTYP *)0) { + (void) rou_alert(0,"%s line='%03d' <%s> not a valid IP " + "(error=<%s>, config?)", + OPEP,num,line,strerror(errno)); + continue; + } + (void) afn_maskip(afn,mask); + list=(AFNTYP **)rou_addlist((void **)list,(void *)afn); + } + } + break; + case 3 : //closing file + (void) fclose(relays); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +filename=rou_freestr(filename); +return list; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to list all file with a specific */ +/* extension with the queue directory. */ +/* Return a list or NULL if no file. */ +/* */ +/********************************************************/ +PUBLIC char **eml_getqfilelist(char **dnames,const char *ext) + +{ +#define OPEP "unieml.c:eml_getqfilelist" + +DIR *dir; +int phase; +_Bool proceed; + +dir=(DIR *)0; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //lets open the queue directory + char *dirname; + + dirname=rou_apppath(QDIR); + if ((dir=opendir(dirname))==(DIR *)0) { + (void) rou_alert(0,"%s Unable to open director <%s> (error=<%s>, config?)", + OPEP,dirname,strerror(errno)); + phase=999; //No need to go further + } + dirname=rou_freestr(dirname); + break; + case 1 : //scanning directory contents + struct dirent *data; + register int taille; + + taille=0; + if (ext!=(char *)0) + taille=strlen(ext); + while ((data=readdir(dir))!=(struct dirent *)0) { + register char *ptr; + + ptr=data->d_name; + if (*ptr=='.') + continue; //hidden file + if (taille>0) + ptr=strstr(data->d_name,ext); + if (ptr==(char *)0) + continue; //extension not found + if ((strlen(ptr)!=taille)&&(*(ptr-1)!='.')) + continue; //Not the right extension + (void) rou_alert(6,"%s got <%s>",OPEP,data->d_name); + dnames=(char **)rou_addlist((void **)dnames,(void *)strdup(data->d_name)); + } + break; + case 2 : //closing directory + if (closedir(dir)<0) { + (void) rou_alert(0,"%s Unable to close queue directory (error=<%s>, bug?)", + OPEP,strerror(errno)); + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return dnames; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to open a fine within the MTA queue */ +/* directory. */ +/* */ +/********************************************************/ +PUBLIC FILE *eml_openqfile(const char *qfilename,const char *ext) + +{ +#define OPEP "unieml.c:eml_openqfile," + +FILE *qfile; +char *dirname; +char fullname[300]; + +qfile=(FILE *)0; +dirname=rou_apppath(QDIR); +(void) snprintf(fullname,sizeof(fullname),"%s/%s",dirname,qfilename); +if ((ext!=(const char *)0)&&((strlen(fullname)+strlen(ext)+3) (error-<%s> bug?)", + OPEP,fullname,strerror(errno)); + } +dirname=rou_freestr(dirname); +return qfile; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to store an email to a list of email */ +/* return true if successful, false otherwise. */ +/* */ +/********************************************************/ +PUBLIC _Bool eml_addemail(char ***emails,char *email) + +{ +_Bool status; +char **ptr; + +status=true; +ptr=*emails; +if (ptr!=(char **)0) { + while (*ptr!=(char *)0) { + if (strcasecmp(*ptr,email)==0) { + status=false; + break; //already within list + } + ptr++; + } + } +if (status==true) + *emails=(char **)rou_addlist((void **)*emails,strdup(email)); +return status; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to duplication a sessid file (email) */ +/* to user directory. */ +/* Return true if successful, false otherwise */ +/* */ +/********************************************************/ +PUBLIC _Bool eml_dupqfile(char *qfilename,const char *dest) + +{ +#define OPEP "unieml.c:eml_dupqfile," +_Bool status; +char *filename; +FILE *fin; +FILE *fout; +int phase; +_Bool proceed; + +status=false; +filename=rou_apppath(QDIR); +fin=(FILE *)0; +fout=(FILE *)0; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //lets open the queue directory + if ((qfilename==(char *)0)||(dest==(char *)0)) { + (void) rou_alert(0,"%s filename=<%s> or dest=<%s> missing (Bug?)", + OPEP,qfilename,dest); + phase=999; //Big trouble + } + break; + case 1 : //opening origin file + if (qfilename!=(char *)0) { //always + char name[300]; + + (void) snprintf(name,sizeof(name),"%s/%s",filename,qfilename); + if ((fin=fopen(name,"r"))==(FILE *)0) { + (void) rou_alert(0,"%s unable to open source <%s> (error=<%s>)", + OPEP,name,strerror(errno)); + phase=999; //Big trouble + } + } + break; + case 2 : //opening destination file + if (fin!=(FILE *)0) { //always + char name[300]; + + (void) snprintf(name,sizeof(name),"%s/%s",dest,qfilename); + if ((fout=fopen(name,"w"))==(FILE *)0) { + (void) rou_alert(0,"%s unable to open destination <%s> (error=<%s>)", + OPEP,name,strerror(errno)); + (void) fclose(fin); + phase=999; //Big trouble + } + } + break; + case 3 : //lock the fout file + if (flock(fileno(fout),LOCK_EX)<0) { + (void) rou_alert(0,"%s unable to lock destination file <%s> " + "(error=<%s> (Bug?))", + OPEP,qfilename,strerror(errno)); + (void) fclose(fout); + (void) fclose(fin); + phase=999; //Big trouble + } + break; + case 4 : //duplicating file + if (fout!=(FILE *)0) { + int count; + char buffer[2048]; + + while ((count=fread(buffer,sizeof(char),sizeof(buffer),fin))>0) { + if (fwrite(buffer,sizeof(char),count,fout)!=count) { + (void) rou_alert(0,"%s unable to fully write destination file " + "<%s> (error=<%s>)", + OPEP,qfilename,strerror(errno)); + phase=999; + } + } + (void) flock(fileno(fout),LOCK_UN); + (void) fclose(fout); + (void) fclose(fin); + } + break; + case 5 : //duplication is a success + status=true; + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +filename=rou_freestr(filename); +return status; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to increase or decrase the "count" */ +/* session id file. */ +/* return 0 or a positive count number. */ +/* return -1 if trouble. */ +/* */ +/********************************************************/ +PUBLIC int eml_countqfile(char *qfilename,int count) + +{ +#define OPEP "unieml.c:eml_countqfile," + +int result; +FILE *fcount; +char *filename; +int phase; +_Bool proceed; + +result=-1; +fcount=(FILE *)0; +filename=rou_apppath(QDIR); +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //lets open the queue directory + if (qfilename==(char *)0) { + (void) rou_alert(0,"%s filename=<%s> missing (Bug?)",OPEP,qfilename); + phase=999; //Big trouble + } + break; + case 1 : //opening count file + char name[300]; + + (void) snprintf(name,sizeof(name),"%s/%s.%s",filename,qfilename,EXTCNT); + if ((fcount=fopen(name,"r+"))==(FILE *)0) { + (void) rou_alert(0,"%s unable to open count file <%s> (error=<%s>)", + OPEP,name,strerror(errno)); + phase=999; //Big trouble + } + break; + case 2 : //locking access + int try; + + try=100; //wait 1 sec total + while (try>0) { + if (flock(fileno(fcount),LOCK_EX|LOCK_NB)==0) + break; //We have the lock + else { + switch (errno) { + case (EWOULDBLOCK) : + try--; + if (try>0) + (void) usleep(10000); //Wait 10 millisec + else + (void) rou_alert(0,"%s unable to lock count file <%s> in time", + OPEP,name); + break; + default : + (void) rou_alert(0,"%s unable to lock count file <%s> (error=<%s>)", + OPEP,name,strerror(errno)); + (void) fclose(fcount); + phase=999;// trouble trouble + try=0; + break; + } + } + } + break; + case 3 : //reading count + if (fscanf(fcount,"%d",&result)!=1) { + (void) rou_alert(0,"%s unable to read file <%s> contents (error=<%s>)", + OPEP,name,strerror(errno)); + (void) fclose(fcount); + phase=999; //trouble trouble + } + break; + case 4 : //doing count + result+=count; + if (result<0) + result=-1; + (void) rewind(fcount); + if (fprintf(fcount,"%d\n",result)<0) { + (void) rou_alert(0,"%s unable to write file <%s> count value (error=<%s>)", + OPEP,name,strerror(errno)); + } + (void) fclose(fcount); + break; + case 5 : //removing file count if result is zero + if (result==0) + (void) eml_deleteqfile(qfilename); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +filename=rou_freestr(filename); +return result; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to check if email address is */ +/* acceptable. */ +/* */ +/********************************************************/ +PUBLIC RCPTYP *eml_isemailok(char *email,char **report) + +{ +#define OPEP "unieml.c:eml_isemailok" + +RCPTYP *info; +char *localpart; +char *domain; +int phase; +_Bool proceed; + +info=(RCPTYP *)0; +*report=(char *)0; +localpart=(char *)0; +domain=(char *)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 an email + if ((email==(char *)0)||strlen(email)==0) { + (void) rou_alert(0,"%s Email missing! (bug?)",OPEP); + proceed=false; + } + break; + case 1 : //splitting local domain part + if ((domain=strchr(email,'@'))==(char *)0) { + *report=strdup("Missing domain part"); + phase=999; //trouble trouble + } + break; + case 2 : //double checking domain part + domain++; + if (strchr(domain,'@')!=(char *)0) { + *report=strdup("malformed domain part"); + phase=999; //trouble trouble + } + break; + case 3 : //duplicating email to localpart + localpart=strdup(email); + *(strchr(localpart,'@'))='\000'; //removing domain + if (strlen(localpart)==0) { + *report=strdup("email address is empty"); + phase=999; //trouble trouble + } + break; + case 4 : //checking localpart email + if (strlen(localpart)>0) { //always + char *ptr; + char cmt[200]; + + ptr=localpart; + while (*ptr!='\000') { + switch (*ptr) { + case ' ' : + case '<' : + case '>' : + case '(' : + case '[' : + case ']' : + case ';' : + case ':' : + (void) snprintf(cmt,sizeof(cmt),"'%c' not allowed in email",*ptr); + *report=strdup(cmt); + *(ptr+1)='\000'; //exiting; + phase=999; //No need to go further + break; + } + ptr++; + } + } + break; + case 5 : //everythin fine + info=(RCPTYP *)calloc(1,sizeof(RCPTYP)); + info->code='N'; //Not assigned code + info->domain=strdup(domain); + info->userid=strdup(localpart); + break; + default : //SAFE guard + localpart=rou_freestr(localpart); + proceed=false; + break; + } + phase++; + } +return info; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to attach a part of text to a file */ +/* acceptable. */ +/* */ +/********************************************************/ +PUBLIC int eml_attache(FILE *qout,char *toaddfile,char **explain,int nbrlines) + +{ +#define OPEP "unieml.c:eml_attache," +#define CNT "Content-" + + +int success; +FILE *qfile; +uuid_t id; +char marker[40]; +int phase; +_Bool proceed; + +success=false; +qfile=(FILE *)0; +(void) uuid_generate(id); +(void) uuid_unparse(id,marker); +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //Open the file + if ((qfile=eml_openqfile(toaddfile,(char *)0))==(FILE *)0) { + (void) rou_alert(0,"%s unable to open file <%s> to be attached", + OPEP,toaddfile); + phase=999; //No need to go further + } + break; + case 1 : //mime starting part + (void) fprintf(qout,"MIME-Version: 1.0\n"); + (void) fprintf(qout,"%sType: multipart/mixed; boundary=\"%s\"\n",CNT,marker); + (void) fprintf(qout,"\nThis is a multi-part message in MIME format.\n\n"); + (void) fprintf(qout,"--%s\n",marker); + (void) fprintf(qout,"%sType: text/plain; charset=\"iso-8859-1\"\n",CNT); + (void) fprintf(qout,"%sTransfer-Encoding: 8bit\n\n",CNT); + break; + case 2 : //mime starting part + (void) fprintf(qout,"Sending Email was not successful\n"); + (void) fprintf(qout,"here is the status returned by remote serveur:\n"); + (void) fprintf(qout,"--->\n"); + if (explain!=(char **)0) { + while (*explain!=(char *)0) { + (void) fprintf(qout,"\t%s\n",*explain); + explain++; + } + } + (void) fprintf(qout,"---<\n"); + break; + case 3 : //mime starting part + (void) fprintf(qout,"--%s%s",marker,CRLF); + (void) fprintf(qout,"%sType: message/rfc822;\n\tname=\"%s\"\n", + CNT,toaddfile); + (void) fprintf(qout,"%sTransfer-Encoding: 8bit\n",CNT); + (void) fprintf(qout,"%sDisposition: attachment;\n\tfilename=\"%s\"\n\n", + CNT,toaddfile); + break; + case 4 : //appending addfile + _Bool count; //reading at most nbrlines + char line[300]; + + count=false; + while (fgets(line,sizeof(line),qfile)!=(char *)0) { + if (count==true) + nbrlines--; + (void) fprintf(qout,"%s",line); + if (strlen(line)<1) + count=true; + if (nbrlines==0) + break; + } + break; + case 5 : //end attachement marker + (void) fprintf(qout,"\n--%s--\n\n",marker); + qfile=eml_closeqfile(qfile); + success=true; + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return success; + +#undef CNT +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to format a string with remote server */ +/* credit report. */ +/* */ +/********************************************************/ +PUBLIC char *eml_showcredit(char *rmtip,char *reverse,int delta,int credit) + +{ +static const char *cmt="%s\tRVS='%s'\tdelta='%3d' -> new credit='%3d'"; + +char *fmt; + +fmt=(char *)0; +(void) rou_asprintf(&fmt,cmt,rmtip,reverse,delta,credit); +return fmt; +} diff --git a/lib/unieml.d b/lib/unieml.d new file mode 100644 index 0000000..8df0219 --- /dev/null +++ b/lib/unieml.d @@ -0,0 +1,65 @@ +unieml.o unieml.d : unieml.c /usr/include/stdc-predef.h /usr/include/arpa/inet.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/netinet/in.h /usr/include/bits/stdint-uintn.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/sys/socket.h \ + /usr/include/bits/types/struct_iovec.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/socket.h /usr/include/sys/types.h \ + /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/time_t.h /usr/include/bits/types/timer_t.h \ + /usr/include/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/bits/endian.h /usr/include/bits/endianness.h \ + /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/bits/socket_type.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm-generic/socket.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h /usr/include/asm/posix_types.h \ + /usr/include/asm/posix_types_64.h /usr/include/asm-generic/posix_types.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/bits/in.h \ + /usr/include/sys/file.h /usr/include/fcntl.h /usr/include/bits/fcntl.h \ + /usr/include/bits/fcntl-linux.h /usr/include/bits/stat.h \ + /usr/include/bits/struct_stat.h /usr/include/dirent.h \ + /usr/include/bits/dirent.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h /usr/include/bits/dirent_ext.h \ + /usr/include/errno.h /usr/include/bits/errno.h \ + /usr/include/linux/errno.h /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/stdio.h /usr/include/bits/libc-header-start.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/stdlib.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/alloca.h /usr/include/bits/stdlib-float.h \ + /usr/include/string.h /usr/include/bits/types/locale_t.h \ + /usr/include/bits/types/__locale_t.h /usr/include/strings.h \ + /usr/include/unistd.h /usr/include/bits/posix_opt.h \ + /usr/include/bits/environments.h /usr/include/bits/confname.h \ + /usr/include/bits/getopt_posix.h /usr/include/bits/getopt_core.h \ + /usr/include/bits/unistd_ext.h /usr/include/uuid/uuid.h \ + /usr/include/sys/time.h /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h subafn.h \ + /usr/include/netdb.h /usr/include/rpc/netdb.h /usr/include/bits/netdb.h \ + subrou.h /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + unieml.h diff --git a/lib/unieml.h b/lib/unieml.h new file mode 100644 index 0000000..45623e9 --- /dev/null +++ b/lib/unieml.h @@ -0,0 +1,178 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Define all routine to manage SMTP low level */ +/* exchange. */ +/* */ +/********************************************************/ +#ifndef UNIEML +#define UNIEML + +#include + +#include "subafn.h" + +#define HFROM "From: " //Then email header header from +#define HTITLE "Subject: " //Then email subject entry + +#define MXMSIZE "52428800" //52 Megabytes +#define CRLF "\r\n" //EOL within SMTP protocol +#define GOTHELP 214 //Help message (A response to the HELP command) +#define SIGNON 220 //signon information +#define QUITOK 221 //status on quit +#define IDOK 235 //Authentication ID OK +#define CMDOK 250 //Everything OK +#define SENDB64 334 //send a B64 sequence +#define DATAOK 354 //Ready to accept EMAIL data +#define ERRPROC 451 //local processing error +#define ALREADY 456 //remote server already connected +#define BADSITE 457 //Site credential is too low +#define NOTNOW 459 //Site already connected +#define NOANSWR 460 //no answer from remote +#define BADPAR 501 //error in parameters +#define CMDBAD 502 //command not implemented +#define BADSEQ 503 //out of sequence command +#define BADAUTH 504 //Posting user Authentication not successful +#define DATRJC 521 //Data Rejected +#define EXPIRED 536 //Contract date expired +#define REJECT 550 //E-mail/domain rejected +#define UKNUSER 551 //Unknown user +#define MALABRT 552 //email data rejected +#define NOTEML 553 //Not an email address +#define FAILED 554 //transaction failed +#define NORELAY 555 //we do not relay email +#define BLCKLST 556 //remote site Black listed +#define MISSMX 563 //NO MX found for recipient + +//defining extensions +#define EXTODO "todo" //todo qfile extension +#define EXDONE "done" //todo qfile processing completed +#define EXDOING "doing" //todo qfile in sending mode +#define EXTRANS "trans" //trans qfile extension +#define EXTCNT "count" //count sessid by email extension +#define EXTOBE "tobedone" //in progess qfile extension + + +#define SBINDIR "/usr/sbin/" //appliaction installation directory +#define SENDER "sender" //application email sender +#define SORTER "sorter" //application email sorter + +#define EMLPORT "25" //Default SMTP email port +#define WAITRMT 60 //how long to wait answer from remote SMTP + +typedef enum { //list of email relayable status + rel_authentic, //connection/user is authenticated + rel_isrelay, //remote IP is relayable + rel_plain, //remote IP is a "plain" stranger + rel_unknown //Wrong status + }RELTYP; + +//list of keyword +typedef enum { //list of SMTP protocol keyword + c_auth, //Requesting authentication + c_data, //DATA email contents transfer request + c_ehlo, //EHLO command + c_helo, //Basic Helo command + c_help, //HELP command + c_mail, //'mail from:' sequence detected + c_noop, //No Operation request +#ifdef MODEDEBUG +//command available ONLY if compiled in debug mode + c_orgn, //to force remote IP to a specific value +#endif + c_quit, //quit exchange + c_rcpt, //'rcpt to:' sequence detected + c_rset, //resetting session + c_starttls, //Starting a TLS crypted link + c_unknown //key word unknown + }CODTYP; + +typedef struct { //*definition of recipient + char code; //'L' rcipient local, 'R' recipient remote + char *domain; //Recipient domain + char *userid; //recipient email userid + }RCPTYP; + +//structure to define an email transport directive +typedef struct { + char code; //Transaction code + time_t date; //Transaction date + u_int delay; //Transaction execution delay + char *hfrom; //Email HEADER originator + char *hsubject; //Email HEADER subject + char *remoteip; //remote server pure IP + char *reverse; //remote server reverse-address + char *rcptto; //Email Recipient + char *sessid; //session id + char *sfrom; //Email SMTP Originator + int sendcode; //Email sending status; + char **resp; //Transfer response status + }TRATYP; + +//procedure to Free one recipient info +extern RCPTYP *eml_freerecipient(RCPTYP *info); + +//procedure to fee memory used by the resp record within TRATYP structure +extern void eml_freetra_resp(TRATYP *tra); + +//procedure to Free one transaction info +extern TRATYP *eml_freetra(TRATYP *tra); + +//procedure to Free all transaction inf +extern TRATYP **eml_freeall_tra(TRATYP **tra); + +//procedure to add recipient to a recipient list +extern _Bool eml_addrecipient(RCPTYP ***list,RCPTYP *rcpt); + +//get a session unique id +extern char *eml_getmainsesid(); + +//get the current session ID +extern char *eml_getcursesid(char *mainid,int numreset); + +//convert SMTP keyword to CODTYP +extern CODTYP eml_getcode(char *keyword); + +//remove CRLF from string +extern int eml_removecrlf(char *string); + +//procedure to delete a file within the queue +extern _Bool eml_deleteqfile(char *qfilename); + +//procedure to change qfile extension +extern _Bool eml_renameqfile(char *qfilename,const char *oldext,const char *newext); + +//procedure to open a file within queue directory +extern FILE *eml_createqfile(char *qfilename,const char *ext); + +//procedure to close a file within the queue directory +extern FILE *eml_closeqfile(FILE *qfile); + +//Procedure to load the list of IP/Network from +//which incoming email can be relayed to another domain MX +extern AFNTYP **eml_load_relayed(char *relayedfile); + +//Procedure to list all file within queue directory +//and with a specific extenstion +extern char **eml_getqfilelist(char **dnames,const char *ext); + +//procedure to open a specific qfile +extern FILE *eml_openqfile(const char *qfilename,const char *ext); + +//procedure to duplicate a specific qfile to another file +extern _Bool eml_dupqfile(char *qfilename,const char *dest); + +//procedure to increase or decrease the "count" file contents +extern int eml_countqfile(char *qfilename,int count); + +//procedure to check email address format +//of an email address +extern RCPTYP *eml_isemailok(char *email,char **report); + +//procedure to create an attachement for email data part. +extern int eml_attache(FILE *qout,char *toaddfile,char **explain,int nbrlines); + +//Procedure to format a remote server credit report +extern char *eml_showcredit(char *rmtip,char *reverse,int delta,int credit); + +#endif diff --git a/lib/unimar.c b/lib/unimar.c new file mode 100644 index 0000000..e817329 --- /dev/null +++ b/lib/unimar.c @@ -0,0 +1,558 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Low level subroutine implementation */ +/* to handle POSTGRES SQL request */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "unimar.h" + +//checking if MYSQL database need to compiled +#if DATABASE==USE_MYSQL + #define DB_MYSQL +#endif + +#ifdef DB_MYSQL +char *marenv[SQLENV]= { + "MYSQL", + "localhost", + "3306", + "mailleur", + (char *)0 + }; +#else +char *marenv[SQLENV]= { + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0 + }; +#endif + +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to detect and 'clean' any single quote*/ +/* within a string, this is mandatory for string */ +/* variable in the database. */ +/* Single quote and double quote are translated to */ +/* '\'' and '\"' */ +/* */ +/********************************************************/ +char *mar_cleanquote(char *dstr) + +{ +char *cleanstr; +int taille; +char *ptr; + +taille=3; +cleanstr=calloc(3,sizeof(char)); +cleanstr[0]='\''; +if (dstr!=(char *)0) { + char *nptr; + + ptr=dstr; + while (((nptr=strchr(ptr,'\''))!=(char *)0)||((nptr=strchr(ptr,'\"'))!=(char *)0)) { + char lit[3]; + char *newclean; + + (void) strcpy(lit,"\\'"); + if (*nptr=='"') + lit[1]='"'; + *nptr='\000'; /*to segment string */ + taille+=strlen(ptr)+2; + if ((newclean=(char *)realloc(cleanstr,taille))!=(char *)0) { + cleanstr=newclean; + (void) strcat(cleanstr,ptr); + (void) strcat(cleanstr,lit); + *nptr=lit[1]; /*to glue back string */ + ptr=nptr+1; + } + } + if (*ptr!='\000') { + char *newclean; + + taille+=strlen(ptr); + if ((newclean=(char *)realloc(cleanstr,taille))!=(char *)0) { + cleanstr=newclean; + (void) strcat(cleanstr,ptr); + } + } + } +(void) strcat(cleanstr,"'"); +return cleanstr; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to return a dynamicaly allocated */ +/* char * with an MYSQL date computation sequenc */ +/* */ +/********************************************************/ +PUBLIC char *mar_caldate(char *expression,int second) + +{ +char *seq; + +seq=(char *)0; +(void) rou_asprintf(&seq,"(addtime(%s,%d))",expression,second); +return seq; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to establish a link with the */ +/* postgresq SQL server. */ +/* */ +/********************************************************/ +MARPTR *mar_opensql(const char *host,const char *sqlport,const char *dbname) + +{ +#define OPEP "unimar.c:mar_opensql," + +MARPTR *marptr; + +marptr=(MARPTR *)0; +#ifdef DB_MYSQL + { + struct passwd *pw; + MYSQL *mysql; + int port; + + if ((pw=getpwuid(geteuid()))==(struct passwd *)0) { + (void) rou_core_dump("%s is unable to find name for uid '%s'", + OPEP,geteuid()); + //never ever REACHED + } + mysql=mysql_init((MYSQL *)0); + port=0; + if (sqlport!=(char *)0) + port=atoi(sqlport); + if (mysql_real_connect(mysql,host,pw->pw_name,(char *)0,dbname,port, + (char *)0,CLIENT_FOUND_ROWS)==(MYSQL *)0) { + (void) rou_alert(0,"%s Connection to database '%s' failed, cause '%s'", + OPEP,dbname,mysql_error(mysql)); + (void) free(mysql); + mysql=(MYSQL *)0; + } + marptr=(MARPTR *)mysql; + } +#else + (void) fprintf(stderr,"%s not compiled to be used with mysql\n",OPEP); +#endif +return marptr; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to close the link with the designated */ +/* postgresql SQL server. */ +/* */ +/********************************************************/ +MARPTR *mar_closesql(MARPTR *marptr) + +{ +#define OPEP "sqlmar.c:mar_closesql," + +#ifdef DB_MYSQL + (void) mysql_close((MYSQL *)marptr); +#else + (void) fprintf(stderr,"%s not compiled to be used with mysql\n",OPEP); +#endif +marptr=(MARPTR *)0; +return marptr; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to return a unix time in acsii */ +/* format (data-base compatible). */ +/* */ +/********************************************************/ +PUBLIC const char *mar_fromunixtime(time_t timestamp) + +{ +#define TSTAMP "%Y-%m-%d %H:%M:%S" + +static char unixdate[50]; + +(void) memset(unixdate,'\000',sizeof(unixdate)); + +#ifdef DB_MYSQL +/*Note: + *syntax MYSQL ("FROM_UNIXTIME(%ld)",timestamp) + */ + { + struct tm *tminfo; + + tminfo=localtime(×tamp); + (void) strftime(unixdate,sizeof(unixdate),TSTAMP,tminfo); + } +#endif + +return unixdate; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to return a unix time_t from an ASCII*/ +/* string (data-base compatible). */ +/* */ +/********************************************************/ +PUBLIC time_t mar_tounixtime(const char *date) + +{ +#define OPEP "unimar.c:mar_tounixtime," + +time_t datetime; + +datetime=(time_t)0; +#ifdef DB_MYSQL + { + static const char *stampeon="0000-00-00 00:00:00"; + + if ((date!=(char *)0)&&(strcmp(date,stampeon)!=0)) { + static const char *dbtounix="%Y-%m-%d %H:%M:%S"; + + char *ptr; + struct tm tm; + + if ((ptr=strchr(date,'.'))!=(char *)0) { + *ptr='\000'; + } + (void) memset(&tm,'\000',sizeof(struct tm)); + tm.tm_isdst=-1; + if (strptime(date,dbtounix,&tm)!=(char *)0) { + datetime=mktime(&tm); + } + else { + (void) rou_alert(0," Unable to convert <%s> to time_t (Bug?)",OPEP,date); + } + } + } +#endif + +return datetime; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to lock access to a specific table */ +/* within database. */ +/* */ +/********************************************************/ +PUBLIC _Bool mar_lock(MARPTR *marptr,char *tablename) + +{ +#define OPEP "unimar.c:mar_lock," + +_Bool locked; + +locked=false; +#ifdef DB_MYSQL + { + static const char *cmd="LOCK TABLE %s WRITE"; + + char fullcmd[300]; + int phase; + _Bool proceed; + + (void) snprintf(fullcmd,sizeof(fullcmd),cmd,tablename); + phase=0; + proceed=true; + while (proceed==true) { + //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //Starting lock + if (mar_request(marptr,"BEGIN")<0) { + (void) rou_alert(0,"%s Unable to BEGIN to lock table <%s>", + OPEP,tablename); + phase=999; //no need to go further + } + break; + case 1 : //lock table itself + if (mar_request(marptr,fullcmd)<0) { + (void) rou_alert(0,"%s Unable to lock table <%s>", + OPEP,tablename); + phase=999; //no need to go further + } + break; + case 2 : //lock done + locked=true; + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } + } +#endif +return locked; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to unlock access to a previously */ +/* locked table within database. */ +/* */ +/********************************************************/ +PUBLIC _Bool mar_unlock(MARPTR *marptr,_Bool commit) + +{ +#define OPEP "unimar.c:mar_unlock," + +_Bool unlocked; + +unlocked=false; +#ifdef DB_MYSQL + { + char *cmd; + + unlocked=true; + cmd="ROLLBACK"; + if (commit==true) + cmd="COMMIT"; + if (mar_request(marptr,cmd)<0) { + unlocked=false; + (void) rou_alert(0,"%s Unable to commit/rollback table (Bug?) ",OPEP); + } + if (mar_request(marptr,"UNLOCK TABLE")<0) { + unlocked=false; + (void) rou_alert(0,"%s Unable to unlock table (Bug?) ",OPEP); + } + } +#endif +return unlocked; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to drop/free all result information */ +/* */ +/********************************************************/ +PUBLIC MARRES *mar_dropresult(MARRES *rs) + +{ +#ifdef DB_MYSQL +(void) mysql_free_result((MYSQL_RES *)rs); +#endif +return (MARRES *)0; +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to retrieve specific field value in */ +/* tupple under fieldname. */ +/* */ +/********************************************************/ +PUBLIC const char *mar_getvalue(MARRES *rs,int tuple,const char *fieldname) + +{ +#define OPEP "unimar.c:pos_getfield," +register char *got; + +got=(char *)0; +#ifdef DB_MYSQL + { + register int position; + + register uint numfields; + MYSQL_FIELD *fields; + + position=-1; + numfields=mysql_num_fields((MYSQL_RES *)rs); + fields=mysql_fetch_fields((MYSQL_RES *)rs); + for (int i=0;i",OPEP,command); + } + else { + (void) rou_alert(0,"%s pid='%05d' Unable to carry cmd=<%s>, error=<%s>", + OPEP,getpid(),command,mysql_error((MYSQL *)ms)); + } + marres=(MARRES *)mysstatut; + } +#endif +return marres; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to return the number of tupple related*/ +/* related to a previous search. */ +/* */ +/********************************************************/ +PUBLIC int mar_nbrtupple(MARRES *marres) + +{ +#define OPEP "unimar.c:mar_nbrtupple," + +register int numrow; + +numrow=0; +#ifdef DB_MYSQL + numrow=mysql_num_rows((MYSQL_RES *)marres); +#endif +return numrow; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to request an action (insert,update */ +/* delete) to the database. */ +/* return the number of tupple affected by the */ +/* command. */ +/* */ +/********************************************************/ +PUBLIC int mar_request(MARPTR *marptr,char *command) + +{ +#define OPEP "unipos.c:pos_action," + +int number; + +number=-1; +#ifdef DB_MYSQL + { + register MYSQL *ms; + + ms=(MYSQL *)marptr; + if (mysql_query(ms,command)==0) + number=mysql_affected_rows(ms); + else + (void) rou_alert(0,"%s pid='%05d' Unable to carry cmd=<%s>, error=<%s>", + OPEP,getpid(),command,mysql_error(ms)); + } +#endif +return number; +} diff --git a/lib/unimar.d b/lib/unimar.d new file mode 100644 index 0000000..f1f3b67 --- /dev/null +++ b/lib/unimar.d @@ -0,0 +1,51 @@ +unimar.o unimar.d : unimar.c /usr/include/stdc-predef.h /usr/include/pwd.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/types/FILE.h /usr/include/stdio.h \ + /usr/include/bits/libc-header-start.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/stdlib.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/sys/types.h /usr/include/bits/types/clock_t.h \ + /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/byteswap.h \ + /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \ + /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/string.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/strings.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h \ + /usr/include/mysql/mysql.h /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h \ + /usr/include/mysql/mariadb_com.h /usr/include/mysql/mariadb_version.h \ + /usr/include/mysql/ma_list.h /usr/include/mysql/mariadb_ctype.h \ + /usr/include/ctype.h /usr/include/mysql/mariadb_stmt.h subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h unimar.h diff --git a/lib/unimar.h b/lib/unimar.h new file mode 100644 index 0000000..613ace9 --- /dev/null +++ b/lib/unimar.h @@ -0,0 +1,64 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Base level subroutine declaration */ +/* to handle MYSQL/MARIADB SQL request. */ +/* */ +/********************************************************/ +#ifndef UNIMAR +#define UNIMAR + +//reference to a SQL pointer reference +typedef void MARPTR; + +//reference to a MariaDB result +typedef void MARRES; + +//Database env variable +extern char *marenv[SQLENV]; + +//Procedure to detect and 'clean' any single quote within a string +extern char *mar_cleanquote(char *sequence); + +//procedure to return a dynamicaly allocated string +//to do SQL compute a date with a delta in second +extern char *mar_caldate(char *expression,int second); + +//Opening a postscript database +extern MARPTR *mar_opensql(const char *host,const char *sqlport,const char *dbname); + +//closing a postscript database +extern MARPTR *mar_closesql(MARPTR *marptr); + +//converting a time to a database representation +extern const char *mar_fromunixtime(time_t timestamp); + +//converting a database time representation to unix time +extern time_t mar_tounixtime(const char *date); + +//locking database one table access +extern _Bool mar_lock(MARPTR *marptr,char *tablename); + +//unlocking the current database table lock access +extern _Bool mar_unlock(MARPTR *marptr,_Bool commit); + +//procedure to drop/free all result information +extern MARRES *mar_dropresult(MARRES *rs); + +//procedure to extract specific field within database +extern char *mar_getfield(MARRES *rs,int tuple,int position); + +//procedure to extract specific field value within database +extern const char *mar_getvalue(MARRES *rs,int tuple,const char *fieldname); + +//procedure to extract data from database +extern MARRES *mar_gettupple(MARPTR *marptr,char *command); + +//procedure to return the number of entry within a result +extern int mar_nbrtupple(MARRES *marres); + +//procedure to submit an action (insert,update,delete) +//to a MySAL database +extern int mar_request(MARPTR *marptr,char *command); + +#endif diff --git a/lib/unipar.c b/lib/unipar.c new file mode 100644 index 0000000..8c9372f --- /dev/null +++ b/lib/unipar.c @@ -0,0 +1,231 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Low level subroutine declaration */ +/* to handle an argv list and extract */ +/* parameters. */ +/* */ +/********************************************************/ +#include +#include +#include +#include + +#include "subrou.h" +#include "unipar.h" + +//application default config file +PUBLIC char config[200]="/etc/"APPNAME"/"APPNAME".conf"; +PUBLIC char srcip[200]=""; + +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to init the argument list */ +/* */ +/********************************************************/ +static ARGTYP *initparams() + +{ +ARGTYP *params; + +params=(ARGTYP *)calloc(1,sizeof(ARGTYP)); +params->argv=(char **)0; +return params; +} +/* + +*/ +/********************************************************/ +/* */ +/* Display aid, usage parameter */ +/* */ +/********************************************************/ +static void usage_aid(char *name,const char *select) + +{ +static char *prg[]={ + "chkspf domain ip_number", + (char *)0 + }; + +static char *options[]={ + "c[-c config]", + "d[-d debug]", + "D[-D dbglive]", + "f[-f]", + "h[-h]", + "i[-i IP]", + "r[-r root]", + "v[-v]", + (char *)0 + }; + +static char *details[]={ + "-c config\t: set config file\n", + "-d level\t: debug level [1-10]\n", + "-D dbglive\t: Procedure name to use with live debug\n", + "-f\t\t: start program in foreground (CLI) mode\n", + "-h\t\t: print this help message\n", + "-i IP\t\t: IP to be used as source IP\n", + "-r root\t\t: root working directory\n", + "-v\t\t: Print program version number\n", + (char *)0 + }; + +int num; +char *pars; +char msg[200]; +char explain[1000]; + +num=0; +pars=(char *)0; +while (prg[num]!=(char *)0) { + if (strstr(prg[num],name)==prg[num]) { + pars=strchr(prg[num],' '); + if (pars!=(char *)0) + pars++; + break; + } + num++; + } +num=0; +(void) sprintf(explain,"\twhere:\n"); +(void) fprintf(stderr,"usage:\n "); +(void) sprintf(msg,"%s\t",name); +while (options[num]!=(char *)0) { + char *ptr; + + ptr=options[num]; + if (strchr(select,*ptr)!=(char *)0) { + ptr++; + (void) strcat(msg," "); + (void) strcat(msg,ptr); + (void) strcat(explain,"\t\t"); + (void) strcat(explain,details[num]); + } + num++; + } +(void) fprintf(stderr,"%s",msg); +if (pars!=(char *)0) + (void) fprintf(stderr," %s",pars); +(void) fprintf(stderr,"\n"); +if ((select!=(char *)0)&&(strlen(select)>0)) { + (void) fprintf(stderr,"%s",explain); + } +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to free memory used by an arg */ +/* list */ +/* */ +/********************************************************/ +PUBLIC ARGTYP *par_freeparams(ARGTYP *params) + +{ +if (params!=(ARGTYP *)0) { + if (params->argv!=(char **)0) { + char **ptr; + + ptr=params->argv; + while (*ptr!=(char *)0) { + (void) free(*ptr); + ptr++; + } + (void) free(params->argv); + } + (void) free(params); + params=(ARGTYP *)0; + rou_freestr(dbglive); + dbglive=(char *)0; + } +return params; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to extract argument list */ +/* but cherry-pick only the one allowed by */ +/* sequence optstring. */ +/* on error return an null argtype */ +/* */ +/********************************************************/ +PUBLIC ARGTYP *par_getparams(int argc,char * const argv[],const char *optstring) + +{ +ARGTYP *params; +char *shortname; +int c; + +params=initparams(); +if ((shortname=strrchr(argv[0],'/'))==(char *)0) + shortname=argv[0]; +else + shortname++; +opterr=0; //no error message from getopt library routine +while (((c=getopt(argc,argv,optstring))!=EOF)&&(params!=(ARGTYP *)0)) { + switch(c) { + case 'c' : //config file + (void) memset(config,'\000',sizeof(config)); + (void) strncpy(config,optarg,sizeof(config)-1); + break; + case 'd' : //debug level + debug=atoi(optarg); + (void) rou_alert(1,"debug level is now '%d'",debug); + break; + case 'D' : //debug level + dbglive=strdup(optarg); + (void) rou_alert(1,"debug live string=<%s>",dbglive); + break; + case 'f' : //background/daemon mode + foreground=true; + (void) fprintf(stdout,"%s-%s, foreground mode requested\n", + shortname,rou_getversion()); + break; + case 'h' : //requestion program help + (void) fprintf(stdout,"%s-%s\n",shortname,rou_getversion()); + (void) usage_aid(shortname,optstring); + params=par_freeparams(params); //no going further + break; + case 'i' : //ser the Interface source IP to be used + (void) memset(srcip,'\000',sizeof(srcip)); + (void) strncpy(srcip,optarg,sizeof(srcip)-1); + break; + case 'r' : + if (rootdir!=(char *)0) + (void) free(rootdir); + rootdir=strdup(optarg); + break; + case 'v' : + (void) fprintf(stdout,"%s:\tVersion:%s\n", + shortname,rou_getversion()); + (void) exit(0); //just display version + break; + default : + (void) fprintf(stdout,"%s-%s\n",shortname,rou_getversion()); + (void) fprintf(stdout,"\"%s\" unexpected argument designator\n\n", + argv[optind-1]); + (void) usage_aid(shortname,optstring); + params=par_freeparams(params); + break; + } + } +(void) rou_setexecname(shortname); +if ((params!=(ARGTYP *)0)&&(argc>optind)) { + int i; + + params->argc=argc-optind; + params->argv=(char **)calloc(params->argc+1,sizeof(char *)); + for (i=0;iargc;i++) { + params->argv[i]=strdup(argv[optind+i]); + } + } +return params; +} diff --git a/lib/unipar.d b/lib/unipar.d new file mode 100644 index 0000000..6a7f507 --- /dev/null +++ b/lib/unipar.d @@ -0,0 +1,47 @@ +unipar.o unipar.d : unipar.c /usr/include/stdc-predef.h /usr/include/stdio.h \ + /usr/include/bits/libc-header-start.h /usr/include/features.h \ + /usr/include/features-time64.h /usr/include/bits/wordsize.h \ + /usr/include/bits/timesize.h /usr/include/sys/cdefs.h \ + /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/types/__fpos_t.h \ + /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/stdlib.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/sys/types.h /usr/include/bits/types/clock_t.h \ + /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/byteswap.h \ + /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \ + /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/string.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/strings.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h unipar.h diff --git a/lib/unipar.h b/lib/unipar.h new file mode 100644 index 0000000..d4db92b --- /dev/null +++ b/lib/unipar.h @@ -0,0 +1,29 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Low level subroutine declaration */ +/* to handle an argv list and extract */ +/* parameters. */ +/* */ +/********************************************************/ +#ifndef UNIPAR +#define UNIPAR + +#include + +//structure of argument +typedef struct { + int argc; //number of main argument + char **argv; //list of argument + }ARGTYP; + +extern char config[]; //Application config file +extern char srcip[]; //Source IP to be used + +//free allocated memory used by a ARGTYP structure +extern ARGTYP *par_freeparams(ARGTYP *params); + +//allocated memory and parse an argment list +extern ARGTYP *par_getparams(int argc,char * const argv[],const char *optstring); + +#endif diff --git a/lib/unipos.c b/lib/unipos.c new file mode 100644 index 0000000..42b93d6 --- /dev/null +++ b/lib/unipos.c @@ -0,0 +1,575 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Low level subroutine implementation */ +/* to handle POSTGRES SQL request */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "unipos.h" + + + +//checking if MYSQL database need to compiled +#if DATABASE==USE_POSTGRESQL + #define DB_POSTGRESQL +#endif + +#ifdef DB_POSTGRESQL +char *posenv[SQLENV]= { + "POSTGRESQL", + "localhost", + "5432", + "mailleur", + (char *)0 + }; +#else +char *posenv[SQLENV]= { + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0 + }; +#endif + +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to execut a database request by daemon*/ +/* */ +/********************************************************/ +#ifdef DB_POSTGRESQL +static PGresult *request(PGconn *pf,char *directive) + +{ +#define OPEP "unipos.c:request," +#define RELAX 1000000 + +PGresult *statut; +int try; + +statut=(PGresult *)0; +try=0; +while (statut==(PGresult *)0) { + try++; + switch(PQstatus(pf)) { + case CONNECTION_OK : + if ((statut=PQexec(pf,directive))!=(PGresult *)0) + break; + else + (void) rou_alert(0,"%s Command <%s> failed, (error=<%s>), retrying", + OPEP,directive,PQerrorMessage(pf)); + // fall through + // NO Break, want DB reset + default : + (void) rou_alert(0,"%s reseting postgres connection (try='%d')", + OPEP,try); + (void) usleep(RELAX/2); + (void) PQreset(pf); + (void) usleep(RELAX/2); + break; + } + if (try>10) { + (void) rou_alert(0,"%s Unable to carry command <%s> Postgres error!", + OPEP,directive); + break; + } + } +return statut; + +#undef RELAX +#undef OPEP +} +#endif +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to detect and 'clean' any single quote*/ +/* within a string, this is mandatory for string */ +/* variable in the database. */ +/* Single quote "'" are doubled becoming "''" */ +/* */ +/********************************************************/ +PUBLIC char *pos_cleanquote(register char *dstr) + +{ +char *cleanstr; +int taille; + +cleanstr=strdup("E'"); +taille=strlen(cleanstr)+2; +if (dstr!=(char *)0) { + int max; + int i,p; + char *newclean; + + /*to double char ' in the string */ + max=strlen((const char *)dstr); + taille+=max; + if ((newclean=(char *)realloc(cleanstr,taille))!=(char *)0) { + cleanstr=newclean; + p=strlen(cleanstr); + for (i=0;i to time_t (Bug?)",OPEP,date); + } + } + } +#endif + +return datetime; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to lock access to a specific table */ +/* within database. */ +/* */ +/********************************************************/ +PUBLIC _Bool pos_lock(POSPTR *posptr,char *tablename) + +{ +#define OPEP "unipos.c:pos_lock," + +_Bool locked; + +locked=false; +#ifdef DB_POSTGRESQL + { + static const char *cmd="LOCK TABLE %s IN SHARE ROW EXCLUSIVE MODE"; + + char fullcmd[300]; + int phase; + _Bool proceed; + + (void) snprintf(fullcmd,sizeof(fullcmd),cmd,tablename); + phase=0; + proceed=true; + while (proceed==true) { + //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //Starting lock + if (pos_request(posptr,"BEGIN")<0) { + (void) rou_alert(0,"%s Unable to BEGIN to lock table <%s>", + OPEP,tablename); + phase=999; //no need to go further + } + break; + case 1 : //lock table itself + if (pos_request(posptr,fullcmd)<0) { + (void) rou_alert(0,"%s Unable to lock table <%s>", + OPEP,tablename); + phase=999; //no need to go further + } + break; + case 2 : //lock done + locked=true; + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } + } +#endif +return locked; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to unlock access to a previously */ +/* locked table within database. */ +/* */ +/********************************************************/ +PUBLIC _Bool pos_unlock(POSPTR *posptr,_Bool commit) + +{ +#define OPEP "unipos.c:pos_unlock," + +_Bool unlocked; + +unlocked=false; +#ifdef DB_POSTGRESQL + { + char *cmd; + + unlocked=true; + cmd="ROLLBACK"; + if (commit==true) + cmd="COMMIT"; + if (pos_request(posptr,cmd)<0) { + unlocked=false; + (void) rou_alert(0,"%s Unable to unlock table (Bug?) ",OPEP); + } + } +#endif +return unlocked; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to drop/free all result information */ +/* */ +/********************************************************/ +PUBLIC POSRES *pos_dropresult(POSRES *rs) + +{ +#ifdef DB_POSTGRESQL +(void) PQclear(rs); +#endif +return (POSRES *)0; +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to retrieve specific field value in */ +/* tupple, accessed at position */ +/* */ +/********************************************************/ +PUBLIC char *pos_getfield(POSRES *rs,int tuple,int position) + +{ +register char *got; + +got=(char *)0; +#ifdef DB_POSTGRESQL +got=PQgetvalue((PGresult *)rs,tuple,position); +#endif +return got; +} +/* + +*/ +/********************************************************/ +/* */ +/* procedure to retrieve specific field value in */ +/* tupple under fieldname. */ +/* */ +/********************************************************/ +PUBLIC const char *pos_getvalue(POSRES *rs,int tuple,const char *fieldname) + +{ +#define OPEP "unipos.c:pos_getfield," +register char *got; + +got=(char *)0; +#ifdef DB_POSTGRESQL + { + int position; + + if ((position=PQfnumber((PGresult *)rs,fieldname))<0) + (void) rou_alert(0,"%s field '%s' unknown (BUG?)",OPEP,fieldname); + else { + if (PQgetisnull((PGresult *)rs,tuple,position)==false) + got=PQgetvalue((PGresult *)rs,tuple,position); + } + } +#endif +return got; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to extract data from the database. */ +/* Return POSRES status pointer (can be NULL is not*/ +/* successfull. */ +/* */ +/********************************************************/ +PUBLIC POSRES *pos_gettupple(POSPTR *posptr,char *command) + +{ +#define OPEP "basmys.c:mys_tupple," + +register POSRES *posres; + +posres=(POSRES *)0; +#ifdef DB_POSTGRESQL + { + PGresult *pgstatut; + register PGconn *pf; + + pf=(PGconn *)posptr; + if ((pgstatut=request(pf,command))!=(PGresult *)0) { + if (PQresultStatus(pgstatut)!=PGRES_TUPLES_OK) { + (void) rou_alert(0,"%s SQL command <%s> failed",OPEP,command); + (void) PQclear(pgstatut); + pgstatut=(PGresult *)0; + } + } + posres=(POSRES *)pgstatut; + } +#endif +return posres; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to return the number of tupple related*/ +/* related to a previous search. */ +/* */ +/********************************************************/ +PUBLIC int pos_nbrtupple(POSRES *posres) + +{ +register int numrow; + +numrow=0; +#ifdef DB_POSTGRESQL +numrow=PQntuples((PGresult *)posres); +#endif +return numrow; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to request an action (insert,update */ +/* delete) to the database. */ +/* return the number of tupple affected by the */ +/* command. */ +/* */ +/********************************************************/ +PUBLIC int pos_request(POSPTR *posptr,char *command) + +{ +#define OPEP "unipos.c:pos_action," + +int number; + +number=-1; +#ifdef DB_POSTGRESQL + { + register PGconn *pf; + PGresult *pgstat; + + pf=(PGconn *)posptr; + if ((pgstat=request((PGconn *)pf,command))!=(PGresult *)0) { + switch (PQresultStatus(pgstat)) { + case PGRES_COMMAND_OK : + number=atoi(PQcmdTuples(pgstat)); + break; + default : + (void) rou_alert(0,"%s Command <%s> failed, (error=<%s> pgstatut='%d')", + OPEP,command,PQerrorMessage(pf), + PQresultStatus(pgstat)); + break; + } + (void) PQclear(pgstat); + } + } +#endif +return number; + +#undef OPEP +} diff --git a/lib/unipos.d b/lib/unipos.d new file mode 100644 index 0000000..fa7260e --- /dev/null +++ b/lib/unipos.d @@ -0,0 +1,48 @@ +unipos.o unipos.d : unipos.c /usr/include/stdc-predef.h /usr/include/libpq-fe.h \ + /usr/include/stdio.h /usr/include/bits/libc-header-start.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/types/__fpos_t.h \ + /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/postgres_ext.h \ + /usr/include/pg_config_ext.h /usr/include/stdlib.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/sys/types.h /usr/include/bits/types/clock_t.h \ + /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/byteswap.h \ + /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \ + /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/string.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/strings.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/linux/posix_types.h /usr/include/linux/stddef.h \ + /usr/include/asm/posix_types.h /usr/include/asm/posix_types_64.h \ + /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h unipos.h diff --git a/lib/unipos.h b/lib/unipos.h new file mode 100644 index 0000000..5a5ffcd --- /dev/null +++ b/lib/unipos.h @@ -0,0 +1,64 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Base level subroutine declaration */ +/* to handle Postgresql SQL request. */ +/* */ +/********************************************************/ +#ifndef UNIPOS +#define UNIPOS + +//reference to a SQL pointer reference +typedef void POSPTR; + +//reference to a POSTGRESQL result +typedef void POSRES; + +//Database env variable +extern char *posenv[SQLENV]; + +//Procedure to detect and 'clean' any single quote within a string +extern char *pos_cleanquote(char *sequence); + +//procedure to return a dynamicaly allocated string +//to do SQL compute a date with a delta in second +extern char *pos_caldate(char *expression,int second); + +//Opening a postscript database +extern POSPTR *pos_opensql(const char *host,const char *sqlport,const char *dbname); + +//closing a postscript database +extern POSPTR *pos_closesql(POSPTR *posptr); + +//converting a time to a database representation +extern const char *pos_fromunixtime(time_t timestamp); + +//converting a database time representation to unix time +extern time_t pos_tounixtime(const char *date); + +//locking database one table access +extern _Bool pos_lock(POSPTR *posptr,char *tablename); + +//unlocking the current database table lock access +extern _Bool pos_unlock(POSPTR *posptr,_Bool commit); + +//procedure to drop/free all result information +extern POSRES *pos_dropresult(POSRES *rs); + +//procedure to extract specific field within database +extern char *pos_getfield(POSRES *rs,int tuple,int position); + +//procedure to extract specific field value within database +extern const char *pos_getvalue(POSRES *rs,int tuple,const char *fieldname); + +//procedure to extract data from postgresql database +extern POSRES *pos_gettupple(POSPTR *posptr,char *command); + +//procedure to return the number of entry within a result +extern int pos_nbrtupple(POSRES *posres); + +//procedure to submit an action (insert,update,delete) +//to a postgresql database +extern int pos_request(POSPTR *posptr,char *command); + +#endif diff --git a/lib/uniprc.c b/lib/uniprc.c new file mode 100644 index 0000000..e23b51a --- /dev/null +++ b/lib/uniprc.c @@ -0,0 +1,531 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Process management implementation module. */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "uniprc.h" + +//directory to set lock +#define DIRLOCK "/var/run/"APPNAME + +/*Process command override structure (proc) */ +typedef struct { + int max; //title max size + char *title; //title storage area + }TITLTYP; + +static TITLTYP *title=(TITLTYP *)0; //storage area for /proc + //title display +static _Bool modopen; //boolean module open/close + +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to change the current ID to an */ +/* application working ID */ +/* */ +/********************************************************/ +static uid_t getappid(char *appname,_Bool group) + +{ +#define OPEP "uniprc.c:getappid" + +uid_t id; +char *fullname; +struct stat bufstat; + +id=(uid_t)0; +fullname=rou_apppath(appname); +if (stat(fullname,&bufstat)<0) + (void) rou_alert(0,"%s Unable to get <%s> stat (error=<%s> bug?)", + OPEP,fullname,strerror(errno)); +else { + if (group==false) + id=bufstat.st_uid; + else + id=bufstat.st_gid; + } +fullname=rou_freestr(fullname); +return id; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to allow process core DUMP */ +/* to trace origin of problem */ +/* */ +/* NOTE: */ +/* On linux to have a working coredump, you MUST */ +/* add to /etc/sysctl.conf */ +/* fs.suid_dumpable=1 */ +/* kernel.core_uses_pid=1 */ +/* kernel.core_pattern=./core.%e.%p */ +/* */ +/********************************************************/ +PUBLIC void prc_allow_core_dump() + +{ +struct rlimit limites; + +if (getrlimit(RLIMIT_CORE,&limites)<0) { + (void) fprintf(stderr,"getrlimit error='%s'",strerror(errno)); + } +limites.rlim_cur=limites.rlim_max; +if (setrlimit(RLIMIT_CORE,&limites)<0) { + (void) fprintf(stderr,"setrlimit error='%s'",strerror(errno)); + } +(void) prctl(PR_SET_DUMPABLE,1,0,0,0);/*to allow core-dump */ +} +/* +^L +*/ +/********************************************************/ +/* */ +/* */ +/* Procedure to allow exited child process */ +/* to leave the zombie stat. */ +/* */ +/********************************************************/ +PUBLIC void prc_nozombie() + +{ +while (waitpid(-1,(int *)0,WNOHANG)>0); +} +/* +^L +*/ +/********************************************************/ +/* */ +/* procedure to check if a process is */ +/* still up and running. */ +/* */ +/********************************************************/ +PUBLIC _Bool prc_checkprocess(pid_t pidnum) + +{ +#define SIGCHECK 0 //signal to check if process + //is existing. + // +_Bool status; + +status=false; +switch(pidnum) { + case (pid_t)0 : /*0 means no process */ + status=false; + break; + case (pid_t)1 : /*init process always OK*/ + status=true; + break; + default : /*standard process */ + if (kill(pidnum,SIGCHECK)==0) + status=true; + break; + } +return status; +#undef SIGCHECK +} +/* +^L +*/ +/********************************************************/ +/* */ +/* procedure to kill a set of process within a */ +/* list, return return the number of process */ +/* still up; */ +/* */ +/********************************************************/ +PUBLIC _Bool prc_killchilds(pid_t *childs,int num,int maxretry) + +{ +int remain; + +remain=num; +while (maxretry>0) { + remain=0; + for (int i=0;i directory (system?/bug?)", + fullname); + phase=999; //big trouble, No need to go further + } + } + else + (void) closedir(dir); + (void) free(fullname); + break; + case 2 : //setting lock filename + const char *fname; + char *name; + + if ((fname=strrchr(lockname,'/'))==(char *)0) + fname=lockname; + else + fname++; + name=(char *)calloc(sizeof(DIRLOCK)+strlen(fname)+10,sizeof(char)); + (void) sprintf(name,"%s/%s.lock",DIRLOCK,fname); + fullname=rou_apppath(name); + (void) free(name); + break; + case 3 : //checking if link already exist + if (stat(fullname,&bufstat)<0) { + phase++; //no need to check lock contents + } + break; + case 4 : //making lockname + if (S_ISREG(bufstat.st_mode)!=0) { + FILE *fichier; + + if ((fichier=fopen(fullname,"r"))!=(FILE *)0) { + pid_t pid; + char strloc[80]; + + (void) fgets(strloc,sizeof(strloc)-1,fichier); + (void) fclose(fichier); + if (sscanf(strloc,"%lu",(u_long *)(&pid))==1) { + (void) rou_alert(5,"Locking, check %d process active",pid); + if (prc_checkprocess(pid)==false) { + (void) rou_alert(6,"Locking, removing pid=%d unactive lock",pid); + (void) unlink(fullname); + } + else { + if (lock==LCK_LOCK) { + (void) rou_alert(0,"lock check, found %d process still active",pid); + phase=999; //no need to go further + } + } + } + } + } + break; + case 5 : //do we need to unlock ? + if (lock==LCK_UNLOCK) { + (void) rou_alert(6,"%s Request unlocking <%s>",OPEP,fullname); + (void) unlink(fullname); + done=true; + phase=999; //No need to go further + } + break; + case 6 : //making lockname + (void) rou_alert(6,"%s Request locking <%s>",OPEP,fullname); + while (tentative>0) { + int handle; + + tentative--; + if ((handle=open(fullname,O_RDWR|O_EXCL|O_CREAT,0640))>=0) { + char numid[30]; + + (void) snprintf(numid,sizeof(numid),"%d\n",getpid()); + (void) write(handle,numid,strlen(numid)); + (void) close(handle); + done=true; + break; //breaking "tentative" loop + } + else { + (void) rou_alert(3,"Trying one more second to lock <%s> (error=<%s>)", + fullname,strerror(errno)); + (void) sleep(1); + } + } + break; + default : //SAFE Guard + if (done==false) + (void) rou_alert(2,"Unable to set <%s> lock (config?)",lockname); + proceed=false; + break; + } + phase++; + } +fullname=rou_freestr(fullname); +return done; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* */ +/* Procedure to put a process in background */ +/* mode. */ +/* Return the child process id. */ +/* */ +/********************************************************/ +PUBLIC pid_t prc_divedivedive() + +{ +#define OPEP "uniprc:rou_divedivedive," +pid_t childpid; + +childpid=(pid_t)0; +switch (childpid=fork()) { + case -1 : + (void) fprintf(stderr,"%s, Unable to dive! (error=<%s>)", + OPEP,strerror(errno)); + break; + case 0 : + //we are now in background mode + (void) setsid(); + break; + default : + //waiting for ballast to fill up :-}} + (void) sleep(1); + break; + } +return childpid; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to free used by "title" struct memory.*/ +/* */ +/********************************************************/ +PUBLIC void prc_cleantitle() + +{ +if (title!=(TITLTYP *)0) { + if (environ!=(char **)0) { + int i; + + for (i=0;environ[i]!=(char *)0;i++) { + (void) free(environ[i]); + environ[i]=(char *)0; + } + (void) free(environ); + environ=(char **)0; + } + (void) free(title); + title=(TITLTYP *)0; + } +} +/* + +*/ +/********************************************************/ +/* */ +/* */ +/* Procedure to find and limit space to */ +/* be used as status information available */ +/* from proc (ps ax) */ +/* */ +/********************************************************/ +PUBLIC void prc_preptitle(int argc,char *argv[],char *env[]) + +{ +char *lastend; + +lastend=(char *)0; +(void) prc_cleantitle(); +title=(TITLTYP *)calloc(1,sizeof(TITLTYP)); +if (argv!=(char **)0) { + int i; + + title->title=argv[0]; + for (i=1;imax=lastend-title->title; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to update title information. */ +/* Title information is avalable via the */ +/* CLI (commande line interface) "ps" */ +/* */ +/********************************************************/ +PUBLIC void prc_settitle(const char *fmt,...) + +{ +va_list args; + +va_start(args,fmt); +if ((title!=(TITLTYP *)0)&&(title->title!=(char *)0)) { + (void) memset(title->title,'\000',title->max); + (void) vsnprintf(title->title,title->max,fmt,args); + } +va_end(args); +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to change the current ID (must be */ +/* root) to the application/program "owner:group" */ +/* */ +/********************************************************/ +void prc_chgid(char *appnom) + +{ +#define OPEP "uniprc.c:prc_chgid," + +#define MSG \ + "%s Unable to %s to '%d' (error=<%s> (cur u/g id='%d/%d',eid='%d/%d') bug?)" + +struct rlimit limites; + +(void) memset(&limites,'\000',sizeof(struct rlimit)); +if (getuid()==0) { /*is changing ID possible */ + uid_t uid; + uid_t gid; + + gid=getappid(appnom,true); + uid=getappid(appnom,false); + if (setegid(gid)<0) + (void) rou_alert(0,MSG,OPEP,"setegid",gid, + strerror(errno), + getuid(),getgid(), + geteuid(),getegid()); + if (seteuid(uid)<0) + (void) rou_alert(0,MSG,OPEP,"seteuid",uid, + strerror(errno), + getuid(),getgid(), + geteuid(),getegid()); + (void) rou_alert(6,"%s ID now set euid='%d', egid='%d' uid='%d' guid='%d'", + OPEP,geteuid(),getegid(),getuid(),getgid()); + } +if (getrlimit(RLIMIT_CORE,&limites)<0) { + (void) rou_alert(0,"%s getrlimit error='%s'",OPEP,strerror(errno)); + } +limites.rlim_cur=limites.rlim_max; +if (setrlimit(RLIMIT_CORE,&limites)<0) { + (void) rou_alert(0,"%s setrlimit error='%s'",OPEP,strerror(errno)); + } +//to allow application core-dump +(void) prctl(PR_SET_DUMPABLE,1,0,0,0); +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to "open/close" module and do */ +/* homework purpose */ +/* return zero if everything right */ +/* */ +/********************************************************/ +PUBLIC int prc_modeuniprc(_Bool mode) + +{ +#define OPEP "uniprc.c:prc_modeuniprc" + +int status; + +status=0; +if (mode!=modopen) { + (void) rou_modesubrou(mode); + switch ((int)mode) { + case true : + (void) prc_allow_core_dump(); + break; + case false : + break; + default : + (void) fprintf(stderr,"Calling %s with wrong mode='%d' (Bug?!):", + OPEP,(int)mode); + status=-1; + break; + } + modopen=mode; + } +return status; +#undef OPEP +} diff --git a/lib/uniprc.d b/lib/uniprc.d new file mode 100644 index 0000000..c9ec409 --- /dev/null +++ b/lib/uniprc.d @@ -0,0 +1,72 @@ +uniprc.o uniprc.d : uniprc.c /usr/include/stdc-predef.h /usr/include/sys/prctl.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/linux/prctl.h /usr/include/linux/types.h \ + /usr/include/asm/types.h /usr/include/asm-generic/types.h \ + /usr/include/asm-generic/int-ll64.h /usr/include/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h /usr/include/asm/posix_types.h \ + /usr/include/asm/posix_types_64.h /usr/include/asm-generic/posix_types.h \ + /usr/include/sys/resource.h /usr/include/bits/resource.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_rusage.h /usr/include/sys/stat.h \ + /usr/include/bits/types/struct_timespec.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/stat.h /usr/include/bits/struct_stat.h \ + /usr/include/sys/wait.h /usr/include/signal.h \ + /usr/include/bits/signum-generic.h /usr/include/bits/signum-arch.h \ + /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/include/bits/types/stack_t.h /usr/include/sys/ucontext.h \ + /usr/include/bits/sigstack.h /usr/include/bits/sigstksz.h \ + /usr/include/bits/ss_flags.h /usr/include/bits/types/struct_sigstack.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/bits/types/idtype_t.h \ + /usr/include/dirent.h /usr/include/bits/dirent.h \ + /usr/include/bits/posix1_lim.h /usr/include/bits/local_lim.h \ + /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h /usr/include/bits/dirent_ext.h \ + /usr/include/errno.h /usr/include/bits/errno.h \ + /usr/include/linux/errno.h /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/fcntl.h /usr/include/bits/fcntl.h \ + /usr/include/bits/fcntl-linux.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/stdio.h /usr/include/bits/libc-header-start.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/stdlib.h \ + /usr/include/sys/types.h /usr/include/bits/types/clock_t.h \ + /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \ + /usr/include/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/alloca.h /usr/include/bits/stdlib-float.h \ + /usr/include/string.h /usr/include/bits/types/locale_t.h \ + /usr/include/bits/types/__locale_t.h /usr/include/strings.h \ + /usr/include/syslog.h /usr/include/sys/syslog.h \ + /usr/include/bits/syslog-path.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h subrou.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h uniprc.h diff --git a/lib/uniprc.h b/lib/uniprc.h new file mode 100644 index 0000000..ecdf612 --- /dev/null +++ b/lib/uniprc.h @@ -0,0 +1,56 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/************************************************/ +/* */ +/* Unit level process management */ +/* declaration */ +/* */ +/************************************************/ +#ifndef UNIPRC +#define UNIPRC + +#include +#include + +#include "subrou.h" + +extern char **environ; //context enviromenent variable + +#define LCK_UNLOCK 0 /*unlocking request */ +#define LCK_LOCK 1 /*locking requets */ + +//To clean the command line title area +extern void prc_cleantitle(); + +//To duplicate enviromenet library and used as command line data +extern void prc_preptitle(int argc,char *argv[],char *env[]); + +//To insert a string in the command area +extern void prc_settitle(const char *fmt,...); + +//To allow application to core dump is memory is +//big trouble need to be investigated +extern void prc_allow_core_dump(); + +//routine to make sure all child process are out of +//zombie state +extern void prc_nozombie(); + +//routine to check if a proces is still up and running +extern _Bool prc_checkprocess(pid_t pidnumber); + +//Routine to kill a list of subprocess +extern _Bool prc_killchilds(pid_t *childs,int num,int maxretry); + +//lock application (to avoid running multiple daemon) +extern _Bool prc_locking(const char *lockname,int lock,int tentative); + +//procedure to put application in deamon mode +extern pid_t prc_divedivedive(); + +//procedure to change the current id (root) to the application "owner" +extern void prc_chgid(char *appnom); + +//homework to be done before starting/stopping module. +extern int prc_modeuniprc(_Bool mode); + +#endif diff --git a/lib/unisig.c b/lib/unisig.c new file mode 100644 index 0000000..258141d --- /dev/null +++ b/lib/unisig.c @@ -0,0 +1,256 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Module for signal handling level */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include + +#include "unisig.h" + +PUBLIC _Bool hangup; //Hangup signal received +PUBLIC _Bool reload; //reload configuration signal received +PUBLIC _Bool wakeup; //application wakeup under an alarm +PUBLIC _Bool childout; //application child signal + +static _Bool modopen; //boolean module open/close +static int sfd; //Signal detail information +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to catch signal and do what is */ +/* needed. */ +/* */ +/********************************************************/ +static void gotsigsegv(int sig) + +{ +#define OPEP "unisig.c:trapsigsegv," + +switch (sig) { + case SIGSEGV : + (void) rou_core_dump("Genuine memory violation (Bug?)"); + break; + default : + (void) rou_core_dump("%s Unexpected signal <%s> received (BUG!)", + OPEP,strsignal(sig)); + break; + } +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to set a signal handler in case of */ +/* segmentation violation. */ +/* */ +/********************************************************/ +static void trapsigsegv(_Bool onoff,sighandler_t trap) + +{ +static _Bool prvon=false; +static struct sigaction oldsa; + +if (onoff==true) { + struct sigaction newsa; + + if (prvon==true) //in case we set signal twice + (void) sigaction(SIGSEGV,&oldsa,(struct sigaction *)0); + newsa.sa_flags=0; + newsa.sa_handler=trap; + (void) sigemptyset(&newsa.sa_mask); + (void) sigaction(SIGSEGV,&newsa,&oldsa); + } +else { + (void) sigaction(SIGSEGV,&oldsa,(struct sigaction *)0); + } +prvon=onoff; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to trap "critical" signal and set */ +/* flag accordingly; */ +/* */ +/********************************************************/ +PUBLIC void sig_alrm(int sig) + +{ +#define OPEP "unisig.c:sig_alrm," + +(void) rou_alert(11,"%s signal <%s> received",OPEP,strsignal(sig)); +switch (sig) + { + case SIGCHLD : { + childout=true; + while (waitpid(-1,(int *)0,WNOHANG)>0); + } + break; + case SIGQUIT : + case SIGTERM : + hangup=true; + break; + case SIGINT : + case SIGHUP : + reload=true; + break; + case SIGALRM : //got an alarm, just to wakeup + wakeup=true; + break; + case SIGUSR1 : + debug++; + if (debug>10) + debug=10; + (void) rou_alert(0,"%s deamon, new increased debug level now set to '%d'", + APPNAME,debug); + break; + case SIGUSR2 : + debug--; + if (debug<0) + debug=0; + (void) rou_alert(0,"%s deamon, new decreased debug level now set to '%d'", + APPNAME,debug); + break; + case SIGPIPE : + (void) rou_alert(0,"%s JMPDBG got SIGPIPE",APPNAME); + break; + default : + (void) rou_alert(0,"Unexpected Signal [%d]/<%s> received", + sig,strsignal(sig)); + break; + } +//able to receive next signal +(void) signal(sig,sig_alrm); +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to trap all meaningfull signal needed */ +/* bay application */ +/* */ +/********************************************************/ +PUBLIC void sig_trapsignal(_Bool onoff,sighandler_t trap) + +{ +#define OPEP "unisig.c:settrap" +#define NUMINTR 9 + +static struct sigaction *olds[NUMINTR]; +static _Bool alldone=false; + +if (onoff==alldone) { + switch ((int)onoff) { + case true : + (void) rou_crash("%s signal trap already set (Bug?)",OPEP); + break; + case false : + (void) rou_crash("%s signal trap already UNset (Bug?)",OPEP); + break; + default : + (void) rou_crash("%s unproper settrap value (very bad Bug!)",OPEP); + break; + } + } +if (onoff==true) { + sigset_t mask; + struct sigaction *newsa; + int i; + + (void) sigemptyset(&mask); + (void) sigaddset(&mask,SIGCHLD); + newsa=(struct sigaction *)calloc(1,sizeof(struct sigaction)); + newsa->sa_flags=0; + newsa->sa_handler=trap; + for (i=0;i)", + OPEP,strerror(errno)); + } + } +else { + int i; + + (void) sigaction(SIGPIPE,olds[8],(struct sigaction *)0); + (void) sigaction(SIGCHLD,olds[7],(struct sigaction *)0); + (void) sigaction(SIGALRM,olds[6],(struct sigaction *)0); + (void) sigaction(SIGHUP,olds[5],(struct sigaction *)0); + (void) sigaction(SIGQUIT,olds[4],(struct sigaction *)0); + (void) sigaction(SIGTERM,olds[3],(struct sigaction *)0); + (void) sigaction(SIGINT,olds[2],(struct sigaction *)0); + (void) sigaction(SIGUSR1,olds[1],(struct sigaction *)0); + (void) sigaction(SIGUSR2,olds[0],(struct sigaction *)0); + for (i=0;i +#include + +#include "subrou.h" + +typedef void (*sighandler_t)(int); + + +extern _Bool hangup; //Hangup signal received +extern _Bool reload; //reload configuration signal received +extern _Bool wakeup; //just got a signal +extern _Bool childout; //A child process just vanished + +//"standard" signal trap +extern void sig_alrm(int sig); + +//trapping application signal (SIGTERM, SIGHUP, etc... +extern void sig_trapsignal(_Bool onoff,sighandler_t trap); + +//homework to be done before starting/stopping module. +extern int sig_modeunisig(_Bool mode); + +#endif diff --git a/lib/unisql.c b/lib/unisql.c new file mode 100644 index 0000000..1ffdebe --- /dev/null +++ b/lib/unisql.c @@ -0,0 +1,251 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Module for low level SQL subroutine */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "unisql.h" + +#define DLANG "UTF-8" + +/* + +*/ +/************************************************/ +/* */ +/* Procedure to convert a char sequence */ +/* from on char set to another. */ +/* if successful return a new pointer */ +/* */ +/************************************************/ +static char *cnvconvert(char *lfrom,char *lto,char *encoded) + +{ +#define OPEP "unisql.c:cnvconvert," + +char *converted; +char *marker; +iconv_t hconv; +size_t inbuflft; +char *inbuf; +size_t outbuflft; +char *outbuf; +int phase; +int proceed; + +converted=(char *)0; +marker=(char *)0; +hconv=(iconv_t)0; +inbuflft=(size_t)0; +inbuf=(char *)0; +outbuflft=(size_t)0; +outbuf=(char *)0; +phase=0; +proceed=1; +while (proceed==true) { + switch (phase) { + case 0 : /*opening conv channel */ + if ((hconv=iconv_open(lto,lfrom))==(iconv_t)-1) { + (void) rou_alert(0,"%s Unexpected lang conversion request " + "from=<%s> to=<%s> (errno=<%s>)", + OPEP,lfrom,lto,strerror(errno)); + phase=999; /*trouble trouble */ + } + break; + case 1 : /*doing convertion */ + inbuflft=strlen(encoded); + outbuflft=(inbuflft*4)+1; /*spare room */ + inbuf=encoded; + marker=(char *)calloc(outbuflft,sizeof(char)); + outbuf=marker; + while (inbuflft>0) { + if (iconv(hconv,&inbuf,&inbuflft,&outbuf,&outbuflft)==(size_t)(-1)) { + inbuf++; + inbuflft=strlen(inbuf); + //replacing out of lfrom subset char by '_' + (void) strcat(marker,"_"); + outbuf++; + outbuflft--; + } + } + break; + case 2 : /*doing convertion */ + if (iconv_close(hconv)<0) + (void) rou_alert(0,"%s Unexpected close conversion error " + "(errno=<%s>) (bug?)",OPEP,strerror(errno)); + break; + default : /*SAFE Guard */ + converted=marker; + proceed=false; + break; + } + phase++; + } +return converted; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to free memory used by a user */ +/* definition. */ +/* */ +/********************************************************/ +PUBLIC USRTYP *sql_freeusr(USRTYP *usr) + +{ +if (usr!=(USRTYP *)0) { + usr->hash=rou_freestr(usr->hash); + usr->password=rou_freestr(usr->password); + usr->email=rou_freestr(usr->email); + (void) free(usr); + usr=(USRTYP *)0; + } +return usr; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to free memory used by a session */ +/* definition. */ +/* */ +/********************************************************/ +PUBLIC SESTYP *sql_freeses(SESTYP *ses) + +{ +if (ses!=(SESTYP *)0) { + ses->duration=rou_freestr(ses->duration); + ses->hsubject=rou_freestr(ses->hsubject); + ses->hfrom=rou_freestr(ses->hfrom); + ses->sfrom=rou_freestr(ses->sfrom); + ses->sessid=rou_freestr(ses->sessid); + (void) free(ses); + ses=(SESTYP *)0; + } +return ses; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to free memory used by a remote SMTP */ +/* data record definition. */ +/* */ +/********************************************************/ +PUBLIC SRVTYP *sql_freesrv(SRVTYP *smtpdata) + +{ +if (smtpdata!=(SRVTYP *)0) { + smtpdata->reverse=rou_freestr(smtpdata->reverse); + smtpdata->listing=rou_freestr(smtpdata->listing); + smtpdata->rmtip=rou_freestr(smtpdata->rmtip); + (void) free(smtpdata); + smtpdata=(SRVTYP *)0; + } +return smtpdata; +} +/* + +*/ +/************************************************/ +/* */ +/* Routine to check if string is properly */ +/* coded, if it is not the case replace all*/ +/* dubious charactere with plain ASCII */ +/* */ +/************************************************/ +PUBLIC char *sql_checkencoding(char *strencoded) + +{ +#define OPEP "unisql.c:sql_checkencoding," + +char *converted; +char *ptr; +int phase; +int proceed; + +converted=(char *)0; +ptr=(char *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //set the destination convertion + if (((ptr=getenv("DB_LANG"))==(char *)0)||(strlen(ptr)==0)) + ptr=DLANG; + break; + case 1 : + if ((converted=cnvconvert(ptr,ptr,strencoded))!=(char *)0) + phase=999; //everything fine converting to DB_LANG + break; + case 2 : //conversion trouble + (void) rou_alert(0,"%s Wrong encoding for db access key <%s> (Config?)", + OPEP,strencoded); + break; + default : /*SAFE Guard */ + proceed=false; + break; + } + phase++; + } +return converted; + +#undef OPEP +} +/* + +*/ +/************************************************/ +/* */ +/* Routine to check if key is acceptable */ +/* to be used as a search element. */ +/* return true if OK. */ +/* */ +/************************************************/ +PUBLIC _Bool sql_check_key(char *key) + +{ +#define OPEP "unisql.c:sql_check_key," + +_Bool isok; + +isok=true; +if ((key!=(char *)0)&&(strlen(key)>0)) { + for (int i=0,l=strlen(key);i not accepted, '%c' is not " + "an acceptable char",OPEP,key,car); + break; //no need to check further + } + } +return isok; + +#undef OPEP +} diff --git a/lib/unisql.d b/lib/unisql.d new file mode 100644 index 0000000..8e708f0 --- /dev/null +++ b/lib/unisql.d @@ -0,0 +1,41 @@ +unisql.o unisql.d : unisql.c /usr/include/stdc-predef.h /usr/include/ctype.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/types/locale_t.h \ + /usr/include/bits/types/__locale_t.h /usr/include/errno.h \ + /usr/include/bits/errno.h /usr/include/linux/errno.h \ + /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h /usr/include/iconv.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h \ + /usr/include/stdlib.h /usr/include/bits/libc-header-start.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/bits/floatn.h /usr/include/bits/floatn-common.h \ + /usr/include/sys/types.h /usr/include/bits/types/clock_t.h \ + /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/byteswap.h \ + /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \ + /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \ + /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/string.h \ + /usr/include/strings.h subrou.h /usr/include/linux/types.h \ + /usr/include/asm/types.h /usr/include/asm-generic/types.h \ + /usr/include/asm-generic/int-ll64.h /usr/include/asm/bitsperlong.h \ + /usr/include/asm-generic/bitsperlong.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h /usr/include/asm/posix_types.h \ + /usr/include/asm/posix_types_64.h /usr/include/asm-generic/posix_types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/time.h /usr/include/bits/time.h \ + /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_itimerspec.h unisql.h diff --git a/lib/unisql.h b/lib/unisql.h new file mode 100644 index 0000000..95afe3e --- /dev/null +++ b/lib/unisql.h @@ -0,0 +1,90 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/************************************************/ +/* */ +/* Low level SQL subroutine declaration */ +/* */ +/************************************************/ +#ifndef UNISQL +#define UNISQL + +#include + +#define SQLENV 5 //number of ENV parameters for + //SQL definition + +typedef enum { + sql_select, //select a record + sql_insert, //create a record + sql_update, //update a record + sql_delete, //delete a record + sql_uknown //No action + }SQLENUM; + +//defining a database column definition retrieval +typedef struct { + int num; //field number + char *name; //field name; + }FLDTYP; + +//structure about user within the database +typedef struct { + char *email; //user emails + char *password; //user crypted password + char *hash; //'email:realm:password' MD5 + u_int lock; //account is lock + u_long space; //user space used + u_long mxspace; //user maximun space + }USRTYP; + +//structure about an email session +//A session is the exchaneg mail from, rcpts and data +//with a remote server +typedef struct { + char *sessid; //session id + char *sfrom; //the "mail from" coming from SMTP exchange + char *hsubject; //the "Subject:" as within the email header + char *hfrom; //the "From:" as within the email header + char *duration; //Session duration un millisec + u_long taille; //Email size + }SESTYP; + +//Structure about email action status (managing email) +typedef struct { + char *sessid; //session id + char code; //Email status code + char *remoteip; //The remoter server IP number + char *reverse; //The remoter server reverse address + char *sfrom; //the "MAIL FROM:" within the SMTP exchange + char *hfrom; //the "From:" within the email header + char *hsubject; //the "Subject:" within the email header + char *rcptto; //email recipient + char **resp; //Multiline status + }ACTTYP; + +//Structure about remotes SMTP server +typedef struct { + char *rmtip; //Remote IP number + time_t lastscan;//last scan time + time_t update; //last update time + int links; //Number of connection from this remote + int credit; //Remote credit number + char *reverse; //Remote serveur reverss-address + char *listing; //Remote listing explaination + }SRVTYP; + +//procedure to free space used by an USRTYP +extern USRTYP *sql_freeusr(USRTYP *usr); + +//procedure to free memory used by a SESTYP +extern SESTYP *sql_freeses(SESTYP *ses); + +//procedure to free memory used by a remote server data +extern SRVTYP *sql_freesrv(SRVTYP *srvdata); + +//Procedure to check if string is properly coded according DB_LANG +extern char *sql_checkencoding(char *strencoded); + +//Procedure to check if a SQL key is acceptable +extern _Bool sql_check_key(char *key); + +#endif diff --git a/lib/unitls.c b/lib/unitls.c new file mode 100644 index 0000000..22eac5c --- /dev/null +++ b/lib/unitls.c @@ -0,0 +1,1364 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Implement all routine to manage SMTP low level */ +/* exchange. */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "subrou.h" +#include "unitls.h" + +//alternate define SSL_CIPHER_LIST "ALL:!LOW" +#define SSL_CIPHER_LIST "DEFAULT" + +static _Bool modopen; //module open/close status +//Binding information as AFN +static AFNTYP **afns=(AFNTYP **)0; +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to report display ALL ssl error queue */ +/* */ +/********************************************************/ +static void showerrorstack(char *msg) + +{ +int error; + +(void) rou_alert(0,"SSL error queue caused by <%s>",msg); +while ((error=ERR_get_error())!=0) { + (void) rou_alert(0,"\tcode='%d, <%s>",error,ERR_error_string(error,(char *)0)); + } +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to report display all erro queue */ +/* after afyer an ssl action. Return true if no */ +/* fatal error found. */ +/* */ +/********************************************************/ +static _Bool showtlserror(TLSTYP *tls,int sslerror,char *msg,...) + +{ +#define OPEP "unitls.c:showtlserror" +_Bool good; +va_list args; +char info[300]; + +good=true; +va_start(args,msg); +(void) vsnprintf(info,sizeof(info),msg,args); +(void) rou_alert(0,"showtlserror sslerror='%d' code='%d'", + sslerror,SSL_get_error(tls->ssl,sslerror)); +if (sslerror<=0) { + char *detail; + int code; + + good=false; + detail="Unexpected error"; + switch (sslerror) { + case 0 : + (void) showerrorstack(info); + break; + default : + if (tls->ssl==(SSL *)0) //in case of trouble + (void) rou_core_dump("%s Unexpected NULL SSL (Bug?)",OPEP); + code=SSL_get_error(tls->ssl,sslerror); + switch (code) { + case SSL_ERROR_ZERO_RETURN : + detail="zero return"; + break; + case SSL_ERROR_WANT_READ : + detail="want read"; + break; + case SSL_ERROR_WANT_WRITE : + detail="want write"; + break; + case SSL_ERROR_WANT_CONNECT : + detail="want connect"; + break; + case SSL_ERROR_WANT_X509_LOOKUP : + detail="want X509 lookup"; + break; + case SSL_ERROR_SYSCALL : + if (ERR_get_error()==0) + detail="Premature EOF"; + else + detail="syscall error"; + break; + case SSL_ERROR_SSL : + (void) showerrorstack(info); + detail=ERR_error_string(ERR_get_error(),(char *)0); + break; + default : + (void) rou_alert(0,"%s, caused by <%s> Unexpected ssl error='%d'", + OPEP,info,code); + detail=(char *)0; + break; + } + break; + } + if (detail!=(char *)0) + (void) rou_alert(4,"%s, caused by <%s>, error=<%s>",OPEP,info,detail); + } +va_end(args); +return good; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to open an SSL channel */ +/* */ +/********************************************************/ +static TLSTYP *freetls(TLSTYP *tls) + +{ +if (tls!=(TLSTYP *)0) { + tls->peerip=rou_freestr(tls->peerip); + tls->peername=rou_freestr(tls->peername); + tls->locip=rou_freestr(tls->locip); + tls->locport=rou_freestr(tls->locport); + if (tls->ssl!=(SSL *)0) { + (void) SSL_clear(tls->ssl); + (void) SSL_free(tls->ssl); + } + if (tls->ctx!=(SSL_CTX *)0) + (void) SSL_CTX_free(tls->ctx); + (void) free(tls); + tls=(TLSTYP *)0; + } +return tls; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to load the certificat beeing as root */ +/* */ +/********************************************************/ +static _Bool load_certs(TLSTYP *tls,const char *certs[]) + +{ +#define OPEP "unitls.c:load_certs," + +_Bool isok; +uid_t gid; //ccurrent group id +uid_t uid; //ccurrent user id + +gid=getegid(); //let be back to root if needed +uid=geteuid(); //to open certificate file +if (setegid(getgid())<0) + (void) rou_core_dump("%s Unable to set the Egid to '%d' (error=<%s>", + OPEP,getgid(),strerror(errno)); +if (seteuid(getuid())<0) + (void) rou_core_dump("%s Unable to set the Euid to '%d' (error=<%s>", + OPEP,getuid(),strerror(errno)); +isok=true; +for (int i=0;(i<3)&&(isok==true);i++) { + switch (i) { + case 0 : //loading the key file + (void) rou_alert(7,"%s key file=<%s>",OPEP,certs[i]); + isok=(SSL_CTX_use_PrivateKey_file(tls->ctx,certs[i],SSL_FILETYPE_PEM)==1); + break; + case 1 : //loading the chain file + (void) rou_alert(7,"%s chain file=<%s>",OPEP,certs[i]); + isok=(SSL_CTX_use_certificate_chain_file(tls->ctx,certs[i])==1); + break; + case 2 : //loading the root certificate + (void) rou_alert(7,"%s root certificate=<%s>",OPEP,certs[i]); + isok=(SSL_CTX_load_verify_locations(tls->ctx,certs[i],(const char *)0)==1); + break; + default : //SAFE Guard + (void) rou_alert(0,"%s value override (Bug!)",OPEP); + break; + } + if (isok==false) { + char msg[200]; + + (void) snprintf(msg,sizeof(msg),"%s, file[%d] <%s> missing?",OPEP,i,certs[i]); + (void) showtlserror(tls,0,msg); + break; + } + } +(void) setegid(gid); //recover the standard application +(void) seteuid(uid); //uid:gid +return isok; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to set the link certificate */ +/* */ +/********************************************************/ +static int set_crypting(TLSTYP *tls,_Bool server) + +{ +#define OPEP "unitls.c:set_crypting" + +static const char *cenv[]={"CA_KEY","CA_CERT","CA_ROOT","CA_VERIFY"}; +static const char *envsec="SSL_SECURITY"; + +int done; +const char *certs[sizeof(cenv)/sizeof(char *)]; +const SSL_METHOD *(*tls_methode)(); +const char *cipher_list; +int seclevel; +const char *certext; +int mode; +int phase; +_Bool proceed; + +done=false; +tls_methode=TLS_client_method; +if ((cipher_list=getenv("CIPHER_LIST"))==(char *)0) + cipher_list=SSL_CIPHER_LIST; +if (getenv(envsec)!=(char *)0) + seclevel=atoi(getenv(envsec)); +else + seclevel=2; +certext="CLT"; +if (tls->server==true) { + tls_methode=TLS_server_method; + certext="SRV"; + } +mode=SSL_VERIFY_NONE; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase); + switch (phase) { + case 0 : //loading certificate names + for (int i=0;i<(sizeof(cenv)/sizeof(char *));i++) { + char data[100]; + + (void) snprintf(data,sizeof(data),"%s_%s",cenv[i],certext); + certs[i]=getenv(data); + if (certs[i]==(char *)0) { + (void) rou_alert(0,"%s Missing <%s> environment variable (config?)", + OPEP,data); + phase=999; //missing certificate info. + } + } + //Set the verify mode + if (certs[3]!=(char *)0) { //env value can be missing + if (atoi(certs[3])==1) { + mode=SSL_VERIFY_PEER; //to make sure peer certificate is OK + } + } + break; + case 1 : //pre-configure SSL + (void) SSL_library_init(); + (void) SSL_load_error_strings(); + (void) ERR_clear_error(); + if ((tls->ctx=SSL_CTX_new(tls_methode()))==(SSL_CTX *)0) { + (void) showtlserror(tls,0,"Get CTX"); + phase=999; //no need to go furter + } + break; + case 2 : //load certificate information + if (load_certs(tls,certs)==false) { + (void) rou_alert(0,"%s Unable to load certificate information (config?)", + OPEP); + phase=999; //no need to go furter + } + break; + case 3 : //verify management + if (((mode&SSL_VERIFY_PEER)!=0)||(tls->server==false)) + tls->checkpeer=true; + (void) SSL_CTX_set_verify(tls->ctx,mode,(int(*)())0); + (void) SSL_CTX_set_purpose(tls->ctx,X509_PURPOSE_ANY); + (void) SSL_CTX_set_verify_depth(tls->ctx,7); + (void) SSL_CTX_set_options(tls->ctx,SSL_OP_ALL); + //(void) SSL_CTX_set_min_proto_version(tls->ctx,TLS1_3_VERSION); + (void) SSL_CTX_set_security_level(tls->ctx,seclevel); + if (SSL_CTX_set_cipher_list(tls->ctx,cipher_list)==0) { + (void) showtlserror(tls,0,"No cipher list"); + phase=999; + } + break; + case 4 : //allowing partial write + (void) SSL_CTX_set_mode(tls->ctx,SSL_MODE_ENABLE_PARTIAL_WRITE); + break; + case 5 : //everything fine + done=true; + break; + default : //SAFE Guard + if (done==false) { + if (tls->ctx!=(SSL_CTX *)0) { + (void) SSL_CTX_free(tls->ctx); + tls->ctx=(SSL_CTX *)0; + } + } + proceed=false; + break; + } + phase++; + } +return done; + +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to get peerip, local name and port */ +/* */ +/********************************************************/ +static void getnames(TLSTYP *tls) + +{ +#define OPEP "unitls.c:getnames" + +socklen_t taille; +struct sockaddr connip; +char host[NI_MAXHOST]; +char serv[NI_MAXSERV]; +int phase; +_Bool proceed; + +taille=(socklen_t)(sizeof(connip)); +(void) strcpy(host,""); +(void) strcpy(serv,""); +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Checking if everithing is fine + if (tls==(TLSTYP *)0) { + (void) rou_alert(0,"%s, TLS is NULL (bug?)",OPEP); + } + break; + case 1 : //Getting local name and service + (void) strcpy(host,"lochost"); + (void) strcpy(serv,"locserv"); + if (getsockname(tls->handle,&connip,&taille)==0) { + int mode; + int status; + + mode=NI_NAMEREQD|NI_NUMERICSERV; + status=getnameinfo(&connip,taille,host,sizeof(host),serv,sizeof(serv),mode); + if (status!=0) { + (void) strcpy(host,"loc-Unknown"); + (void) strcpy(serv,"loc-Unknown"); + } + } + tls->locip=strdup(host); + tls->locport=strdup(serv); + break; + case 2 : //Getting peer name and service + (void) strcpy(host,"remhost"); + (void) strcpy(serv,"remserv"); + if (getpeername(tls->handle,&connip,&taille)==0) { + int mode; + int status; + + mode=NI_NUMERICHOST|NI_NUMERICSERV; + status=getnameinfo(&connip,taille,host,sizeof(host),serv,sizeof(serv),mode); + if (status!=0) { + (void) strcpy(host,"peer-Unknown"); + (void) strcpy(serv,"peer-Unknown"); + } + tls->peerip=strdup(host); + mode=NI_NAMEREQD|NI_NUMERICSERV; + status=getnameinfo(&connip,taille,host,sizeof(host),serv,sizeof(serv),mode); + if (status!=0) + (void) strcpy(host,"Unknown"); + tls->peername=strdup(host); + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to parse an email protocol */ +/* */ +/********************************************************/ +PUBLIC PROTYP tls_getprotocol(const char *strproto) + +{ +static struct { + PROTYP proto; + const char *voca; + }prolist[]={ + {pro_smtp,""}, + {pro_smtp,"smtp"}, + {pro_smtps,"smtps"}, + {pro_unknwn,(char *)0} + }; +PROTYP proto; + + +proto=pro_unknwn; +for (int i=0;prolist[i].voca!=(char *)0;i++) { + if (strcasecmp(strproto,prolist[i].voca)==0) { + proto=prolist[i].proto; + break; + } + } +return proto; +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to the system interrace and build */ +/* a list of local IPV4 interface available */ +/* and build the LISTYP structure. */ +/* */ +/********************************************************/ +static void buildafns() + +{ +#define OPEP "unitls.c,buildafns," + +char *localip; +struct ifaddrs *ifaddr; +int phase; +_Bool proceed; + +localip=strdup(""); +afns=(AFNTYP **)0; +ifaddr=(struct ifaddrs *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Get the interface list + if (getifaddrs(&ifaddr)<0) { + (void) rou_alert(0,"%s Unable to get local IP (error=<%s> system?)", + OPEP,strerror(errno)); + phase=999; //no need to go further + } + break; + case 1 : //Scan interface lis + for (struct ifaddrs *ifa=ifaddr;ifa!=(struct ifaddrs *)0;ifa=ifa->ifa_next) { + int family; + int taille; + int er; + char *newloc; + char host[NI_MAXHOST]; + + if (ifa->ifa_addr==(struct sockaddr *)0) + continue; + family=ifa->ifa_addr->sa_family; + switch (family) { + case AF_INET : + taille=sizeof(struct sockaddr_in); + break; + case AF_INET6 : + taille=sizeof(struct sockaddr_in6); + continue; //No scanning for IPV6 Number (Jun 2025) + break; + default : + continue; + break; + } + er=getnameinfo(ifa->ifa_addr,taille,host,NI_MAXHOST,NULL,0,NI_NUMERICHOST); + if (er!=0) { + (void) rou_alert(0,"%s etnameinfo() failed: (error=<%s> system?)", + OPEP,strerror(errno)); + continue; + } + newloc=(char *)calloc(strlen(localip)+strlen(host)+3,sizeof(char)); + if (strlen(localip)>0) { + (void) strcpy(newloc,localip); + (void) strcat(newloc,","); + } + (void) strcat(newloc,host); + (void) free(localip); + localip=newloc; + } + break; + case 2 : //converting interface IP list to AFNTYP list + afns=afn_getipnums(localip); + (void) freeifaddrs(ifaddr); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +localip=rou_freestr(localip); +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to build a ID string about the */ +/* encrypted connecion within TLS */ +/* */ +/********************************************************/ +PUBLIC char *tls_getcipherid(TLSTYP *tls) + +{ +#define OPEP "unitls.c:tls_getcipherid," +#define MXID 72 + +char *cipherid; +const SSL_CIPHER *cipher; +const char *version; +const char *name; +const char *verif; +int bits; +int phase; +_Bool proceed; + +cipherid=(char *)0; +cipher=(const SSL_CIPHER *)0; +version=(char *)0; +name=(char *)0; +verif=(char *)0; +bits=0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //do we have a TLS + if ((tls==(TLSTYP *)0)||(tls->ssl==(SSL *)0)) { + (void) rou_alert(0,"%s TLS or SSL NULL (Bug?)",OPEP); + phase=999; + } + break; + case 1 : //do we have a TLS + if ((cipher=SSL_get_current_cipher(tls->ssl))==(const SSL_CIPHER *)0) { + (void) rou_alert(0,"%s Unable to get cypher (BUg?)",OPEP); + phase=999; + } + break; + case 2 : //do we have a TLS + version=SSL_CIPHER_get_version(cipher); + name=SSL_CIPHER_get_name(cipher); + bits=SSL_CIPHER_get_bits(cipher,0); + if (strcmp(version,"SSLv3")==0) + version="TLSv1/SSLv3"; + break; + case 3 : //set verify mode + switch(SSL_get_verify_mode(tls->ssl)) { + case SSL_VERIFY_PEER : + //No break + case SSL_VERIFY_CLIENT_ONCE : + //No break + case (SSL_VERIFY_NONE) : + switch(SSL_get_verify_result(tls->ssl)) { + case (X509_V_OK) : + verif="OK"; + break; + default : + verif="FAIL"; + break; + } + break; + default : + verif="NO"; + break; + } + break; + case 4 : //we have ALL data + cipherid=(char *)calloc(1,MXID); + (void) snprintf(cipherid,MXID,"version=%s cipher=%s bits=%d verify=%s", + version,name,bits,verif); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return cipherid; +#undef MXID +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to verify remote certificate */ +/* */ +/********************************************************/ +PUBLIC _Bool tls_verify(TLSTYP *tls) + +{ +#define OPEP "unitls.c:tls_verify," +X509 *peer; +_Bool ok; +int phase; +_Bool proceed; + +peer=(X509 *)0; +ok=false; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //do we need to check peer + if (tls->checkpeer==false) { + (void) rou_alert(1,"%s Peer [%s]; certificate not verified", + OPEP,tls->peerip); + phase=999; //No need to check certificate + } + break; + case 1 : //get remote certificate + if ((peer=SSL_get_peer_certificate(tls->ssl))==(X509 *)0) { + char msg[200]; + + (void) snprintf(msg,sizeof(msg),"%s, Unable to get certificate " + "from remote [%s]", + OPEP,tls->peerip); + (void) showtlserror(tls,0,msg); + phase=999; //no need to go furter + } + break; + case 2 : { //displaying certificate + char *line; + + line=X509_NAME_oneline(X509_get_subject_name(peer),0,0); + (void) rou_alert(4,"Certificate subject=<%s>",line); + line=rou_freestr(line); + line=X509_NAME_oneline(X509_get_issuer_name(peer),0,0); + (void) rou_alert(4,"Certificate issuer=<%s>",line); + line=rou_freestr(line); + } + break; + case 3 : { //verifying certificate + int verif; + char *line; + char *cn; //Certificate Common Name + + cn="CN=Unknown"; + line=X509_NAME_oneline(X509_get_subject_name(peer),0,0); + if (line!=(char *)0) { + char *ptr; + + if ((ptr=strstr(line,"CN="))!=(char *)0) + cn=ptr; + } + verif=SSL_get_verify_result(tls->ssl); + switch (verif) { + case X509_V_OK : + (void) rou_alert(1,"Peer is [%s]/%s",tls->peerip,tls->peername); + (void) rou_alert(1,"%s; Remote certificate is verified",cn); + break; + default : + (void) rou_alert(0,"%s Remote certificate status='%d'",OPEP,verif); + break; + } + line=rou_freestr(line); + } + break; + case 4 : //everything is fine + (void) X509_free(peer); + ok=true; + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return ok; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return the current sercurity level */ +/* */ +/********************************************************/ +PUBLIC int tls_get_sec_level(TLSTYP *tls) + +{ +int level; + +level=-1; +if (tls!=(TLSTYP *)0) { + level=SSL_get_security_level(tls->ssl); + } +return level; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to open an SSL channel */ +/* */ +/********************************************************/ +PUBLIC TLSTYP *tls_opentls(int handle,_Bool server) + +{ +#define OPEP "unitls.c:tls_opentls" + +TLSTYP *tls; +int phase; +_Bool proceed; + +tls=(TLSTYP *)0; +phase=0; +proceed=true; +while (proceed==true) { + //(void) rou_alert(6,"%s JMPDBG phase='%d', serveur='%d'",OPEP,phase,server); + switch (phase) { + case 0 : //prepare the structure first; + tls=(TLSTYP *)calloc(1,sizeof(TLSTYP)); + tls->handle=handle; + tls->server=server; + (void) getnames(tls); + break; + case 1 : //set certificate according client/server mode + if (set_crypting(tls,server)==false) { + (void) rou_alert(1,"%s Unable to open a TLS channel",OPEP); + tls=freetls(tls); + phase=999; + } + break; + case 2 : //Setting the TLS channel + if ((tls->ssl=tls_setsocket(handle,tls->ctx))==(SSL *)0) + phase=999; //trouble, trouble no need to go furter + break; + case 3 : //Setting the TLS channel actif + switch (server) { + case false : //mode client + if (tls_connect(tls)<0) + phase=999; //trouble trouble + break; + case true : //mode server + if (tls_accept(tls)<0) + phase=999; //trouble trouble + break; + } + break; + case 4 : //Setting the TLS channel actif + proceed=false; + break; + default : //SAFE guard + tls=freetls(tls); + proceed=false; + break; + } + phase++; + } +return tls; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to close an SSL channel */ +/* */ +/********************************************************/ +PUBLIC TLSTYP *tls_closetls(TLSTYP *tls) + +{ +#define OPEP "unitls.c:tls_closetls" + +int status; +int phase; +_Bool proceed; + +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Check if TLS is OK + if (tls==(TLSTYP *)0) { + (void) rou_core_dump("%s Unexpected NULL SSL (Bug?)",OPEP); + } + break; + case 1 : //set certificate + //valgrind is trapping SIGPIPE and stop + struct sigaction oldsa; + + (void) sigaction(SIGPIPE,(struct sigaction *)0,&oldsa); + (void) signal(SIGPIPE, SIG_IGN); + status=SSL_shutdown(tls->ssl); + if (status<0) + (void) rou_alert(0,"%s, Link with [%s], ssl_shutdown status='%d'", + OPEP,tls->peerip,status); + (void) sigaction(SIGPIPE,&oldsa,(struct sigaction *)0); + break; + default : //SAFE guard + tls=freetls(tls); + proceed=false; + break; + } + phase++; + } +return tls; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to write a buffer contents to an SSL */ +/* channel. Retune the number of char written or */ +/* -1 if trouble. */ +/* */ +/********************************************************/ +PUBLIC int tls_write(TLSTYP *tls,char *buffer,int tosend) + +{ +#define OPEP "unitls.c:tls_write" + +int sent; + +sent=0; +if (tls!=(TLSTYP *)0) { + _Bool proceed; + int sofar; + + proceed=true; + while (proceed==true) { + int status; + + status=0; + proceed=false; + sofar=SSL_write(tls->ssl,buffer,tosend); + switch (sofar) { + case -1 : //trouble to write + switch (status=SSL_get_error(tls->ssl,-1)) { + case SSL_ERROR_WANT_READ : // + case SSL_ERROR_WANT_WRITE : //"Wanted" error + (void) usleep(1000); + proceed=true; + break; + default : + (void) showtlserror(tls,sofar,"%s Premature EOF with crypted link", + OPEP); + sent=-1; + break; + } + break; + case 0 : //no char sent + switch (SSL_get_error(tls->ssl,0)) { + case SSL_ERROR_SYSCALL : //EOF received? + tls->goteof=true; + if (ERR_get_error()!=0) + (void) rou_alert(0,"%s wrong EOF",OPEP); + break; + default : + (void) rou_alert(0,"%s Unexpected SSL_write error='%d'", + OPEP,SSL_get_error(tls->ssl,0)); + (void) showtlserror(tls,0,"show SSL error",OPEP); + break; + } + break; + default : //some character sent + sent+=sofar; + if (sentssl,buffer,maxread); + switch (got) { + case -1 : //trouble to write + status=SSL_get_error(tls->ssl,-1); + switch (status) { + case SSL_ERROR_WANT_READ : //"wanted" error + case SSL_ERROR_WANT_WRITE : // + (void) usleep(1000); //to ease up incoming charactere + got=0; + break; + default : + (void) showtlserror(tls,-1,"%s Unexpected SSL_read status='%d')", + OPEP,status); + break; + } + break; + case 0 : //no char received + switch (SSL_get_error(tls->ssl,0)) { + case SSL_ERROR_ZERO_RETURN : //No char available on link + case SSL_ERROR_SYSCALL : //EOF received? + tls->goteof=true; + if (ERR_get_error()!=0) + (void) rou_alert(0,"%s wrong EOF",OPEP); + break; + default : + (void) rou_alert(0,"%s Unexpected SSL_read error='%d'", + OPEP,SSL_get_error(tls->ssl,0)); + (void) showtlserror(tls,0,"show SSL error",OPEP); + got=-1; + break; + } + break; + default : //some character received + break; + } + } +return got; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to wait for characeter to be available*/ +/* on the tls link. */ +/* Wait for at most mili-second time. */ +/* */ +/********************************************************/ +PUBLIC int tls_waitforchar(TLSTYP *tls,u_int millisec) + +{ +#define OPEP "unitls.c:tls_waitforchar," + +int status; +struct pollfd polling[1]; +_Bool proceed; +int phase; + +status=-1; +polling[0].events=POLLIN|POLLPRI; +polling[0].revents=(short)0; +proceed=true; +phase=0; +while (proceed==true) { + switch (phase) { + case 0 : //check TLS + if ((tls==(TLSTYP *)0)||(tls->handle<0)) { + (void) rou_alert(0,"%s TLS is not available (Bug?)",OPEP); + phase=999; //trouble trouble (Bug?) + } + break; + case 1 : //lets assume we are cleartext mode + polling[0].fd=tls->handle; + if (tls->tls==true) { //we are crypted mode + if (tls->ssl==(SSL *)0) { //Is ssl definined + (void) rou_alert(0,"%s Crypted mode but no SSL (Bug?)",OPEP); + phase=999; //trouble trouble (Bug?) + } + else + polling[0].fd=SSL_get_fd(tls->ssl); + } + break; + case 2 : //lets wait for char + status=poll(polling,1,millisec); + switch (status) { + case -1 : //Polling error + (void) rou_alert(0,"%s Polling error (error=<%s>)",OPEP,strerror(errno)); + break; + case 0 : //polling timeout + switch (errno) { + default : //lets say nothind to do + (void) rou_alert(0,"%s Polling timeout (error='%d'-<%s>)", + OPEP,errno,strerror(errno)); + break; + } + break; + case 1 : //char is available. + //nothing to do + break; + } + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +return status; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to accept a TLS connection from a */ +/* remote client. */ +/* */ +/********************************************************/ +PUBLIC int tls_accept(TLSTYP *tls) + +{ +#define OPEP "unitls.c:tls_accept," + +int statut; +X509 *peer; +int tic; +int done; + +statut=-1; +peer=(X509 *)0; +tic=30; //30 second MAX to extablish SSL connexio +done=false; +if ((tls->bio=BIO_new_fd(tls->handle,BIO_NOCLOSE))==(BIO *)0) { + (void) rou_core_dump("%s Unable to get the BIO (error=<%s>)", + OPEP,strerror(errno)); + } +(void) SSL_set_bio(tls->ssl,tls->bio,tls->bio); +while (done==false) { + int sslerr; + + statut=SSL_accept(tls->ssl); + switch (sslerr=SSL_get_error(tls->ssl,statut)) { + case SSL_ERROR_NONE : + statut=0; + if ((peer=SSL_get_peer_certificate(tls->ssl))!=(X509 *)0) { + if (SSL_get_verify_result(tls->ssl)!=X509_V_OK) + statut=-1; + (void) X509_free(peer); + } + done=true; + break; + case SSL_ERROR_WANT_READ : + switch(tls_waitforchar(tls,(u_int)1000)) { + case -1 : + switch(errno) { /*received a signal, lets see...*/ + case EINTR : /*could be a TERM signal */ + break; + default : /*hummm real code fault report */ + (void) rou_core_dump("%s poll error '%s'",OPEP,strerror(errno)); + done=true; + statut=-1; + break; + } + break; + case 0 : /*standard time out */ + tic--; + if (tic<=0) { + done=true; + (void) rou_alert(0,"%s, SSL_accept too long to establish",OPEP); + statut=-1; + } + break; + default : + break; + } + break; +#ifdef SSL_ERROR_WANT_ACCEPT + case SSL_ERROR_WANT_ACCEPT : +#endif + case SSL_ERROR_WANT_WRITE : + break; + case SSL_ERROR_SYSCALL: /*EOF received */ + if (ERR_get_error()==0) + tls->goteof=true; + else + (void) showtlserror(tls,statut,"%s SSL_SYSCALL pbs",OPEP); + statut=-1; + done=true; + break; + default : + (void) showtlserror(tls,statut,"%s SSL_accept fatal error " + "(sslerr='%d')",OPEP,sslerr); + statut=-1; + done=true; + break; + } + } +return statut; +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Procedur to initiate a TLS connection from the */ +/* client side. */ +/* Return -1 if trouble, 0 otherwise */ +/* */ +/********************************************************/ +PUBLIC int tls_connect(TLSTYP *tls) + +{ +#define OPEP "unitls.c:tls_connect," + +int done; +int statut; +int tic; + +done=false; +statut=-1; +tic=30; //trying for 30 second +if ((tls->bio=BIO_new_fd(tls->handle,BIO_NOCLOSE))==(BIO *)0) { + (void) rou_core_dump("%s Unable to get the BIO (error=<%s>)", + OPEP,strerror(errno)); + } +(void) SSL_set_bio(tls->ssl,tls->bio,tls->bio); +while (done==false) { + statut=SSL_connect(tls->ssl); + switch (SSL_get_error(tls->ssl,statut)) { + case SSL_ERROR_NONE : + done=true; + statut=0; + break; + case SSL_ERROR_WANT_READ : + switch (tls_waitforchar(tls,(u_int)1000)) { + case -1 : + switch(errno) { /*received a signal, lets see...*/ + case EINTR : /*could be a TERM signal */ + break; + default : /*hummm real code fault report */ + (void) rou_core_dump("%s poll error '%s'",OPEP,strerror(errno)); + done=true; + statut=-1; + break; + } + break; + case 0 : /*standard time out */ + tic--; + if (tic<=0) { + done=true; + (void) rou_alert(0,"%s, SSL_connect too long to establish",OPEP); + statut=-1; + } + break; + default : + break; + } + break; + case SSL_ERROR_WANT_WRITE : + case SSL_ERROR_WANT_CONNECT : + break; + default : + (void) showtlserror(tls,statut,"%s SSL_connect fatal error",OPEP); + statut=-1; + done=true; + break; + } + } +return statut; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to check if remote certificat is a */ +/* valide one. */ +/* return -1if trouble, 0 otherwise */ +/* */ +/********************************************************/ +PUBLIC int tls_check_peer(TLSTYP *tls) + +{ +#define OPEP "unitls.c:tls_check_peer" + +int status; +X509 *peer; +int phase; +int proceed; + +status=-1; +peer=(X509 *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //check SSL + if ((tls==(TLSTYP *)0)||(tls->ssl=(SSL *)0)) { + phase=999; //trouble trouble (Bug?) + } + break; + case 1 : //get peer + if ((peer=SSL_get_peer_certificate(tls->ssl))==(X509 *)0) { + (void) showtlserror(tls,0,"Get peer Certificate"); + phase=999; //trouble trouble + } + break; + case 2 : //is peer valid? + if (SSL_get_verify_result(tls->ssl)!=X509_V_OK) { + (void) showtlserror(tls,0,"Get Verify peer Certificate"); + phase=999; //trouble trouble + } + (void) X509_free(peer); + break; + case 3 : //everything is right + status=0; + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return status; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to link a socket reference to an */ +/* crypted (SSL) channel. */ +/* return an SSL pointer or a NULL pointer */ +/* */ +/********************************************************/ +PUBLIC SSL *tls_setsocket(int handle,SSL_CTX *ctx) + +{ +#define OPEP "unitls.c:tls_setsocket" + +SSL *ssl; +int phase; +_Bool proceed; + +ssl=(SSL *)0; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //Setting inital context + if ((ssl=SSL_new(ctx))==(SSL *)0) { + char reason[200]; + + (void) ERR_error_string(ERR_get_error(),reason); + (void) rou_alert(0,"%S Unable to get a new SSL channel (error=<%s>)", + OPEP,reason); + phase=999; //trouble trouble + } + break; + case 1 : //assign SSL to socket reference + if (SSL_set_fd(ssl,handle)==0) { + char reason[200]; + + (void) ERR_error_string(ERR_get_error(),reason); + (void) rou_alert(0,"%S Unable to set new SSL to socket (error=<%s>)", + OPEP,reason); + (void) free(ssl); + ssl=(SSL *)0; + phase=999; + } + break; + default : //SAFE guard + proceed=false; + break; + } + phase++; + } +return ssl; +#undef OPEP +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to return the AFN list of binding data*/ +/* */ +/********************************************************/ +PUBLIC AFNTYP **tls_get_bind_afn() + +{ +return afns; +} +/* +^L +*/ +/********************************************************/ +/* */ +/* Procedure to "open/close" module and do */ +/* homework purpose */ +/* return zero if everything right */ +/* */ +/********************************************************/ +int tls_modeunitls(_Bool mode) + +{ +#define OPEP "unitls.c:soc_modeunitls," + +int status; + +status=0; +if (mode!=modopen) { + (void) rou_modesubrou(mode); + switch ((int)mode) { + case true : + (void) SSL_library_init(); + (void) ERR_clear_error(); + (void) buildafns(); + break; + case false : + afns=(AFNTYP **)rou_freelist((void **)afns,(genfree_t)afn_freeipnum); + break; + default : + (void) fprintf(stderr,"Calling %s with wrong mode='%d' (Bug?!):", + OPEP,(int)mode); + status=-1; + break; + } + modopen=mode; + } +return status; +#undef OPEP +} diff --git a/lib/unitls.d b/lib/unitls.d new file mode 100644 index 0000000..950f43a --- /dev/null +++ b/lib/unitls.d @@ -0,0 +1,118 @@ +unitls.o unitls.d : unitls.c /usr/include/stdc-predef.h /usr/include/openssl/asn1.h \ + /usr/include/openssl/macros.h /usr/include/openssl/opensslconf.h \ + /usr/include/openssl/configuration.h /usr/include/openssl/opensslv.h \ + /usr/include/stdio.h /usr/include/bits/libc-header-start.h \ + /usr/include/features.h /usr/include/features-time64.h \ + /usr/include/bits/wordsize.h /usr/include/bits/timesize.h \ + /usr/include/sys/cdefs.h /usr/include/bits/long-double.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stddef.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdarg.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/time64.h /usr/include/bits/types/__fpos_t.h \ + /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/types/cookie_io_functions_t.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/floatn.h \ + /usr/include/bits/floatn-common.h /usr/include/time.h \ + /usr/include/bits/time.h /usr/include/bits/types/clock_t.h \ + /usr/include/bits/types/time_t.h /usr/include/bits/types/struct_tm.h \ + /usr/include/bits/types/struct_timespec.h /usr/include/bits/endian.h \ + /usr/include/bits/endianness.h /usr/include/bits/types/clockid_t.h \ + /usr/include/bits/types/timer_t.h \ + /usr/include/bits/types/struct_itimerspec.h \ + /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \ + /usr/include/openssl/e_os2.h /usr/include/sys/types.h \ + /usr/include/bits/stdint-intn.h /usr/include/endian.h \ + /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h \ + /usr/include/bits/atomic_wide_counter.h /usr/include/bits/struct_mutex.h \ + /usr/include/bits/struct_rwlock.h /usr/include/inttypes.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdint.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h \ + /usr/include/bits/stdint-uintn.h /usr/include/bits/stdint-least.h \ + /usr/include/openssl/bio.h /usr/include/openssl/crypto.h \ + /usr/include/stdlib.h /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h /usr/include/alloca.h \ + /usr/include/bits/stdlib-float.h /usr/include/openssl/safestack.h \ + /usr/include/openssl/stack.h /usr/include/openssl/types.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/limits.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/syslimits.h \ + /usr/include/limits.h /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ + /usr/include/bits/pthread_stack_min-dynamic.h \ + /usr/include/bits/pthread_stack_min.h /usr/include/bits/posix2_lim.h \ + /usr/include/openssl/cryptoerr.h /usr/include/openssl/symhacks.h \ + /usr/include/openssl/cryptoerr_legacy.h /usr/include/openssl/core.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include-fixed/pthread.h \ + /usr/include/sched.h /usr/include/bits/sched.h \ + /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \ + /usr/include/bits/setjmp.h \ + /usr/include/bits/types/struct___jmp_buf_tag.h \ + /usr/include/openssl/bioerr.h /usr/include/openssl/asn1err.h \ + /usr/include/openssl/bn.h /usr/include/openssl/bnerr.h \ + /usr/include/openssl/err.h /usr/include/openssl/lhash.h \ + /usr/include/errno.h /usr/include/bits/errno.h \ + /usr/include/linux/errno.h /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ + /usr/include/openssl/x509.h /usr/include/openssl/buffer.h \ + /usr/include/openssl/buffererr.h /usr/include/openssl/evp.h \ + /usr/include/openssl/core_dispatch.h /usr/include/openssl/indicator.h \ + /usr/include/openssl/params.h /usr/include/openssl/evperr.h \ + /usr/include/openssl/objects.h /usr/include/openssl/obj_mac.h \ + /usr/include/openssl/objectserr.h /usr/include/openssl/ec.h \ + /usr/include/string.h /usr/include/strings.h \ + /usr/include/openssl/ecerr.h /usr/include/openssl/rsa.h \ + /usr/include/openssl/rsaerr.h /usr/include/openssl/dsa.h \ + /usr/include/openssl/dh.h /usr/include/openssl/dherr.h \ + /usr/include/openssl/dsaerr.h /usr/include/openssl/sha.h \ + /usr/include/openssl/x509err.h /usr/include/openssl/x509_vfy.h \ + /usr/include/openssl/pkcs7.h /usr/include/openssl/pkcs7err.h \ + /usr/include/openssl/http.h /usr/include/openssl/conf.h \ + /usr/include/openssl/conferr.h /usr/include/openssl/conftypes.h \ + /usr/include/openssl/x509v3.h /usr/include/openssl/x509v3err.h \ + /usr/include/sys/socket.h /usr/include/bits/types/struct_iovec.h \ + /usr/include/bits/socket.h /usr/include/bits/socket_type.h \ + /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ + /usr/include/asm-generic/socket.h /usr/include/linux/posix_types.h \ + /usr/include/linux/stddef.h /usr/include/asm/posix_types.h \ + /usr/include/asm/posix_types_64.h /usr/include/asm-generic/posix_types.h \ + /usr/include/asm/bitsperlong.h /usr/include/asm-generic/bitsperlong.h \ + /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ + /usr/include/bits/types/struct_osockaddr.h /usr/include/ifaddrs.h \ + /usr/include/netdb.h /usr/include/netinet/in.h /usr/include/bits/in.h \ + /usr/include/rpc/netdb.h /usr/include/bits/netdb.h /usr/include/poll.h \ + /usr/include/sys/poll.h /usr/include/bits/poll.h /usr/include/signal.h \ + /usr/include/bits/signum-generic.h /usr/include/bits/signum-arch.h \ + /usr/include/bits/types/sig_atomic_t.h \ + /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \ + /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \ + /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \ + /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h /usr/include/bits/types/stack_t.h \ + /usr/include/sys/ucontext.h /usr/include/bits/sigstack.h \ + /usr/include/bits/sigstksz.h /usr/include/bits/ss_flags.h \ + /usr/include/bits/types/struct_sigstack.h /usr/include/bits/sigthread.h \ + /usr/include/bits/signal_ext.h /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ + /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \ + /usr/include/bits/getopt_core.h /usr/include/bits/unistd_ext.h subrou.h \ + /usr/include/linux/types.h /usr/include/asm/types.h \ + /usr/include/asm-generic/types.h /usr/include/asm-generic/int-ll64.h \ + /usr/lib/gcc/x86_64-ok-linux-gnu/13.4.0/include/stdbool.h unitls.h \ + /usr/include/openssl/ssl.h /usr/include/openssl/e_ostime.h \ + /usr/include/sys/time.h /usr/include/openssl/comp.h \ + /usr/include/openssl/comperr.h /usr/include/openssl/pem.h \ + /usr/include/openssl/pemerr.h /usr/include/openssl/hmac.h \ + /usr/include/openssl/async.h /usr/include/openssl/asyncerr.h \ + /usr/include/openssl/ct.h /usr/include/openssl/cterr.h \ + /usr/include/openssl/sslerr.h /usr/include/openssl/sslerr_legacy.h \ + /usr/include/openssl/prov_ssl.h /usr/include/openssl/ssl2.h \ + /usr/include/openssl/ssl3.h /usr/include/openssl/tls1.h \ + /usr/include/openssl/dtls1.h /usr/include/openssl/srtp.h \ + /usr/include/openssl/quic.h subafn.h diff --git a/lib/unitls.h b/lib/unitls.h new file mode 100644 index 0000000..83a0460 --- /dev/null +++ b/lib/unitls.h @@ -0,0 +1,89 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Define all routine to manage transport secure */ +/* layer. */ +/* */ +/********************************************************/ +#ifndef UNIUTL +#define UNIUTL + +#include +#include + +#include "subafn.h" + +//defining email protocol value. +typedef enum { + pro_smtp, //text SMTP protocol, in clear mode + pro_starttls, //Text SMTP protocol, encrypted upon request + pro_smtps, //Text SMTP protocol, text encrypted from start + pro_unknwn //Protcole undefined + }PROTYP; + +typedef struct { //structure about listening port + PROTYP proto; //Protocol to be used + char *port; //binding port number + int iteration; //Number of binding iteration + AFNTYP *afn; //Information about the IP + }LISTYP; + +typedef struct { + _Bool server; //SSL server/client mode + _Bool checkpeer;//Check peer certificate + _Bool goteof; //SSL End Of File + _Bool tls; //link in TLS (crypted) mode + BIO *bio; //SSL Basic IO + int handle; //device handle + char *peerip; //Remote IP number + char *peername; //Remote reverse address + char *locip; //Local IP number + char *locport; //local Port number + SSL_CTX *ctx; //SSL context + SSL *ssl; //SSL link + }TLSTYP; + +//procedure to report ll information about +//the TLS channel +extern char *tls_getcipherid(TLSTYP *tls); + +//procedure to verify certificate linked to TLS channel +extern _Bool tls_verify(TLSTYP *tls); + +//procedure to get the security level +extern int tls_get_sec_level(TLSTYP *tls); + +//procedure to open an tls channel +extern TLSTYP *tls_opentls(int handle,_Bool server); + +//procedure to close an tls channel +extern TLSTYP *tls_closetls(TLSTYP *tls); + +//write on the SSL channel +extern int tls_write(TLSTYP *tls,char *buffer,int tosend); + +//read from the SSL channel +extern int tls_read(TLSTYP *tls,char *buffer,int maxread); + +//wait for a char alvalable on channel +extern int tls_waitforchar(TLSTYP *tls,u_int millisec); + +//accept from a TLS client connection +extern int tls_accept(TLSTYP *tls); + +//connect to a TLS serveur connection +extern int tls_connect(TLSTYP *tls); + +//check peer certificat +extern int tls_check_peer(TLSTYP *tls); + +//set socket as an tls socket +extern SSL *tls_setsocket(int handle,SSL_CTX *ctx); + +//getting binding information as AFN structure +extern AFNTYP **tls_get_bind_afn(); + +//homework to be done before starting/stopping module. +extern int tls_modeunitls(_Bool mode); + +#endif diff --git a/linux/osukiss/mailleur b/linux/osukiss/mailleur new file mode 100644 index 0000000..d9e78bf --- /dev/null +++ b/linux/osukiss/mailleur @@ -0,0 +1,63 @@ +#! /usr/bin/bash +#================================================================= +# Begin receiver +# +# Description : Start mailleur receiver daemon +# chkconfig: 2345 94 12 +# +#================================================================= + +### BEGIN INIT INFO +# Provides: $mailler +# Required-Start: $network $dovecot $database +# Should-Start: +# Required-Stop: sendsignals +# Should-Stop: +# Default-Start: 3 4 5 +# Default-Stop: 0 1 2 6 +# Short-Description: Starts mailleur reciever and sorter daemon. +# Description: Starts mailleur needed daemon. +# X-LFS-Provided-By: LFS +### END INIT INFO + +. /lib/lsb/init-functions + +APPNAME=mailleur +DAEMON=receiver + +#checking profile +if [ -f /etc/profile ] ; then + . /etc/profile + fi + +#-------------------------------------------------------------- +#to start all mailleur daemon +#-------------------------------------------------------------- +case "$1" in + start ) + for serv in receiver sorter scanner sender + do + /usr/share/$APPNAME/linux/osukiss/$serv $1 + done + ;; + condrestart | \ + reload | \ + stop ) + for serv in scanner sorter sender receiver + do + /usr/share/$APPNAME/linux/osukiss/$serv $1 + done + ;; + restart ) + $0 stop + sleep 1 + $0 start + ;; + *) + echo "Usage: $0 {start|stop|reload|condrestart|restart}" + exit 1 + ;; +esac + + + diff --git a/linux/osukiss/receiver b/linux/osukiss/receiver new file mode 100644 index 0000000..b908605 --- /dev/null +++ b/linux/osukiss/receiver @@ -0,0 +1,106 @@ +#!/bin/sh +#================================================================= +# Begin receiver +# +# Description : Start mailleur receiver daemon +# chkconfig: 2345 94 12 +# +#================================================================= + +### BEGIN INIT INFO +# Provides: $receiver +# Required-Start: $sorter +# Should-Start: +# Required-Stop: sendsignals +# Should-Stop: +# Default-Start: 3 4 5 +# Default-Stop: 0 1 2 6 +# Short-Description: Starts reciever daemon. +# Description: Starts reciever daemon. +# X-LFS-Provided-By: LFS +### END INIT INFO + +. /lib/lsb/init-functions + +APPNAME=mailleur +DAEMON=receiver +DAEMON_PID=/run/${APPNAME}/${DAEMON}.lock + +# Some functions to make the below more readable + +#loading load configuration file +if [ -f /etc/sysconfig/$APPNAME ] ; then + . /etc/sysconfig/$APPNAME +fi + +#-------------------------------------------------------------- +#to start receiver daemon +#-------------------------------------------------------------- +mng_daemon () + +{ +case "$1" in + start) + mkdir -p /run/$APPNAME/ + chown $APPNAME:mail /run/$APPNAME/ + /usr/lib/$APPNAME/support/starting.sh osukiss + if [ $? != 0 ] ; then + exit 1; + fi + log_info_msg "Starting ${DAEMON} Server..." + start_daemon -f /usr/libexec/$APPNAME/bin/${DAEMON} $OPTIONS + evaluate_retval + ;; + + stop) + log_info_msg "Stopping ${DAEMON} Server..." + killproc -p ${DAEMON_PID} /usr/libexec/$APPNAME/bin/${DAEMON} + evaluate_retval + rm -fr ${DAEMON_PID} + ;; + + esac +} + +case "$1" in + start \ + | stop \ + ) + mng_daemon $1 + ;; + + reload) + log_info_msg "Reloading ${DAEMON} Server..." + pid=`cat ${DAEMON_PID} 2>/dev/null` + + if [ -n "${pid}" ]; then + kill -HUP "${pid}" + else + (exit 1) + fi + + evaluate_retval + ;; + + restart) + $0 stop + sleep 1 + $0 start + ;; + + condrestart) + pid=`cat ${DAEMON_PID} 2>/dev/null` + if [ -n "${pid}" -a -d /proc/$pid ]; then + $0 restart + fi + ;; + + + *) + echo "Usage: $0 {start|stop|reload|restart}" + exit 1 + ;; +esac + + + diff --git a/linux/osukiss/scanner b/linux/osukiss/scanner new file mode 100644 index 0000000..d24d907 --- /dev/null +++ b/linux/osukiss/scanner @@ -0,0 +1,106 @@ +#!/bin/sh +#================================================================= +# Begin sorter +# +# Description : Start mailleur sorter daemon +# chkconfig: 2345 91 17 +# +#================================================================= + +### BEGIN INIT INFO +# Provides: $scanner +# Required-Start: $ +# Should-Start: +# Required-Stop: sendsignals +# Should-Stop: +# Default-Start: 3 4 5 +# Default-Stop: 0 1 2 6 +# Short-Description: Starts sorter daemon. +# Description: Starts sorter daemon. +# X-LFS-Provided-By: LFS +### END INIT INFO + +. /lib/lsb/init-functions + +APPNAME=mailleur +DAEMON=scanner +DAEMON_PID=/run/${APPNAME}/${DAEMON}.lock + +# Some functions to make the below more readable + +#loading load configuration file +if [ -f /etc/sysconfig/$APPNAME ] ; then + . /etc/sysconfig/$APPNAME +fi + +#-------------------------------------------------------------- +#to start sorter daemon +#-------------------------------------------------------------- +mng_daemon () + +{ +case "$1" in + start) + mkdir -p /run/$APPNAME/ + chown $APPNAME:mail /run/$APPNAME/ + /usr/lib/$APPNAME/support/starting.sh osukiss + if [ $? != 0 ] ; then + exit 1; + fi + log_info_msg "Starting ${DAEMON} Server..." + start_daemon -f /usr/libexec/$APPNAME/bin/${DAEMON} $OPTIONS + evaluate_retval + ;; + + stop) + log_info_msg "Stopping ${DAEMON} Server..." + killproc -p ${DAEMON_PID} /usr/libexec/$APPNAME/bin/${DAEMON} + evaluate_retval + rm -fr ${DAEMON_PID} + ;; + + esac +} + +case "$1" in + start \ + | stop \ + ) + mng_daemon $1 + ;; + + reload) + log_info_msg "Reloading ${DAEMON} Server..." + pid=`cat ${DAEMON_PID} 2>/dev/null` + + if [ -n "${pid}" ]; then + kill -HUP "${pid}" + else + (exit 1) + fi + + evaluate_retval + ;; + + restart) + $0 stop + sleep 1 + $0 start + ;; + + condrestart) + pid=`cat ${DAEMON_PID} 2>/dev/null` + if [ -n "${pid}" -a -d /proc/$pid ]; then + $0 restart + fi + ;; + + + *) + echo "Usage: $0 {start|stop|reload|restart|status}" + exit 1 + ;; +esac + + + diff --git a/linux/osukiss/sender b/linux/osukiss/sender new file mode 100644 index 0000000..28b6401 --- /dev/null +++ b/linux/osukiss/sender @@ -0,0 +1,105 @@ +#!/bin/sh +#================================================================= +# Begin receiver +# +# Description : Start mailleur sender daemon +# chkconfig: 2345 94 12 +# +#================================================================= + +### BEGIN INIT INFO +# Provides: $sender +# Should-Start: +# Required-Stop: sendsignals +# Should-Stop: +# Default-Start: 3 4 5 +# Default-Stop: 0 1 2 6 +# Short-Description: Starts sender daemon. +# Description: Starts sender daemon. +# X-LFS-Provided-By: LFS +### END INIT INFO + +. /lib/lsb/init-functions + +APPNAME=mailleur +DAEMON=sender +DAEMON_PID=/run/${APPNAME}/${DAEMON}.lock + +# Some functions to make the below more readable + +#loading load configuration file +if [ -f /etc/sysconfig/$APPNAME ] ; then + . /etc/sysconfig/$APPNAME +fi + +#-------------------------------------------------------------- +#to start receiver daemon +#-------------------------------------------------------------- +mng_daemon () + +{ +case "$1" in + start) + mkdir -p /run/$APPNAME/ + chown $APPNAME:mail /run/$APPNAME/ + /usr/lib/$APPNAME/support/starting.sh osukiss + if [ $? != 0 ] ; then + exit 1; + fi + log_info_msg "Starting ${DAEMON} Server..." + start_daemon -f /usr/libexec/$APPNAME/bin/${DAEMON} $OPTIONS + evaluate_retval + ;; + + stop) + log_info_msg "Stopping ${DAEMON} Server..." + killproc -p ${DAEMON_PID} /usr/libexec/$APPNAME/bin/${DAEMON} + evaluate_retval + rm -fr ${DAEMON_PID} + ;; + + esac +} + +case "$1" in + start \ + | stop \ + ) + mng_daemon $1 + ;; + + reload) + log_info_msg "Reloading ${DAEMON} Server..." + pid=`cat ${DAEMON_PID} 2>/dev/null` + + if [ -n "${pid}" ]; then + kill -HUP "${pid}" + else + (exit 1) + fi + + evaluate_retval + ;; + + restart) + $0 stop + sleep 1 + $0 start + ;; + + condrestart) + pid=`cat ${DAEMON_PID} 2>/dev/null` + if [ -n "${pid}" -a -d /proc/$pid ]; then + $0 restart + fi + ;; + + + *) + echo "Usage: $0 {start|stop|reload|restart}" + exit 1 + ;; +esac + + + diff --git a/linux/osukiss/sorter b/linux/osukiss/sorter new file mode 100644 index 0000000..30ceca9 --- /dev/null +++ b/linux/osukiss/sorter @@ -0,0 +1,106 @@ +#!/bin/sh +#================================================================= +# Begin sorter +# +# Description : Start mailleur sorter daemon +# chkconfig: 2345 91 17 +# +#================================================================= + +### BEGIN INIT INFO +# Provides: $sorter +# Required-Start: $ +# Should-Start: +# Required-Stop: sendsignals +# Should-Stop: +# Default-Start: 3 4 5 +# Default-Stop: 0 1 2 6 +# Short-Description: Starts sorter daemon. +# Description: Starts sorter daemon. +# X-LFS-Provided-By: LFS +### END INIT INFO + +. /lib/lsb/init-functions + +APPNAME=mailleur +DAEMON=sorter +DAEMON_PID=/run/${APPNAME}/${DAEMON}.lock + +# Some functions to make the below more readable + +#loading load configuration file +if [ -f /etc/sysconfig/$APPNAME ] ; then + . /etc/sysconfig/$APPNAME +fi + +#-------------------------------------------------------------- +#to start sorter daemon +#-------------------------------------------------------------- +mng_daemon () + +{ +case "$1" in + start) + mkdir -p /run/$APPNAME/ + chown $APPNAME:mail /run/$APPNAME/ + /usr/lib/$APPNAME/support/starting.sh osukiss + if [ $? != 0 ] ; then + exit 1; + fi + log_info_msg "Starting ${DAEMON} Server..." + start_daemon -f /usr/libexec/$APPNAME/bin/${DAEMON} $OPTIONS + evaluate_retval + ;; + + stop) + log_info_msg "Stopping ${DAEMON} Server..." + killproc -p ${DAEMON_PID} /usr/libexec/$APPNAME/bin/${DAEMON} + evaluate_retval + rm -fr ${DAEMON_PID} + ;; + + esac +} + +case "$1" in + start \ + | stop \ + ) + mng_daemon $1 + ;; + + reload) + log_info_msg "Reloading ${DAEMON} Server..." + pid=`cat ${DAEMON_PID} 2>/dev/null` + + if [ -n "${pid}" ]; then + kill -HUP "${pid}" + else + (exit 1) + fi + + evaluate_retval + ;; + + restart) + $0 stop + sleep 1 + $0 start + ;; + + condrestart) + pid=`cat ${DAEMON_PID} 2>/dev/null` + if [ -n "${pid}" -a -d /proc/$pid ]; then + $0 restart + fi + ;; + + + *) + echo "Usage: $0 {start|stop|reload|restart|status}" + exit 1 + ;; +esac + + + diff --git a/mailleur.spec.in b/mailleur.spec.in new file mode 100644 index 0000000..6007825 --- /dev/null +++ b/mailleur.spec.in @@ -0,0 +1,406 @@ +#----------------------------------------------------------------------------- +%{?!dist: %define dist @@DIST@@} +%define spooldir %{_localstatedir}/spool/ +%define wwwdir %{_localstatedir}/www/ +%define dovedir %{_sysconfdir}/dovecot/conf.d +#----------------------------------------------------------------------------- +Name : @@APPN@@ +Version : @@VERSION@@ +Release : @@RELEASE@@%{?dist} +Summary : Application to filter and manage E-mail traffic +Group : System Environment/Libraries + +Vendor : SAFE Inc. +License : GPLv2 +URL : http://mailleur.safe.ca/ + +Source0 : %{name}-@@VERSION@@.tar.gz +#----------------------------------------------------------------------------- +BuildRequires : libxcrypt-devel +BuildRequires : mariadb +BuildRequires : postgresql +BuildRequires : postgresql-server-devel + +Requires : bash +Requires : bind-utils +Requires : cpp +Requires : dovecot > 2.4.0 +Requires : httpd +Requires : openssl +Requires : php-apache +Requires : php-cli +Requires : php-dbg +Requires : python3-certbot_apache +Requires : sed + +#----------------------------------------------------------------------------- +%description +'%{name}' is an email firewall. Its purpose is to filter all email, +rejecting viruses and unwelcome messages at the SMTP protocol level +(and avoids bouncing to forged originators). +It also provide extended audit logs, allowing effective mean to +search about email exchange within time and transaction context. + +#----------------------------------------------------------------------------- +%files +%defattr(-,root,root,-) +%attr(0754,root,root) %{_datadir}/%{name}/linux/osukiss/%{name} +%attr(0754,root,root) %{_datadir}/%{name}/linux/osukiss/receiver +%attr(0754,root,root) %{_datadir}/%{name}/linux/osukiss/scanner +%attr(0754,root,root) %{_datadir}/%{name}/linux/osukiss/sender +%attr(0754,root,root) %{_datadir}/%{name}/linux/osukiss/sorter +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/cron.d/%{name}.cron +%attr(0644,%{name},mail) %config(noreplace) %{_sysconfdir}/pki/%{name}/* +%attr(0644,%{name},mail) %config(noreplace) %{_sysconfdir}/sysconfig/%{name} +#configuration directory +%attr(0644,%{name},mail) %config(noreplace) %{_sysconfdir}/%{name}/%{name}.conf +%attr(0644,%{name},mail) %config(noreplace) %{_sysconfdir}/%{name}/blacklister.conf +%attr(0644,%{name},mail) %config(noreplace) %{_sysconfdir}/%{name}/relayed.conf +#dovecot SQL database access +%attr(0644,%{name},mail) %config(noreplace) %{dovedir}/80-%{name}-usesql.conf +# +%{_bindir}/chkspf +%{_libexecdir}/%{name}/bin-utils/chkspf +%{_libexecdir}/%{name}/bin-utils/feeder +%{_libdir}/%{name}/rpm_build_date +%attr(0754,root,root) %{_libdir}/%{name}/shell/*.sh +%attr(0754,root,root) %{_libdir}/%{name}/support/addconfig.sh +%attr(0754,root,root) %{_libdir}/%{name}/support/do_database.sh +%attr(0754,root,root) %{_libdir}/%{name}/support/do_httpd.sh +%attr(0754,root,root) %{_libdir}/%{name}/support/dummy-cert.sh +%attr(0754,root,root) %{_libdir}/%{name}/support/starting.sh +%attr(0754,root,root) %config(noreplace) %{_libdir}/%{name}/support/do_dns_tlsa.sh +%attr(0750,%{name},mail) %{_libdir}/%{name}/support/mailleur-reset-db.sh +%attr(0750,%{name},mail) %{_libdir}/%{name}/support/mailleur-settest-db.sh +%attr(0755,%{name},mail) %dir %{spooldir}/%{name}/ +%attr(0755,%{name},mail) %dir %{spooldir}/%{name}/queue +%attr(0750,%{name},mail) %dir %{spooldir}/%{name}/mails +%attr(0750,%{name},apache) %dir %{wwwdir}/%{name}/ +%{wwwdir}/%{name}/index.php +%attr(0750,%{name},apache) %{wwwdir}/%{name}/devsql.php +%attr(0750,%{name},apache) %{wwwdir}/%{name}/gesdis.php +%attr(0750,%{name},apache) %{wwwdir}/%{name}/gessql.php +%attr(0750,%{name},apache) %{wwwdir}/%{name}/lvllog.php +%attr(0750,%{name},apache) %{wwwdir}/%{name}/lvlmai.php +%attr(0750,%{name},apache) %{wwwdir}/%{name}/lvlrmt.php +%attr(0750,%{name},apache) %{wwwdir}/%{name}/lvlusr.php +%attr(0750,%{name},apache) %{wwwdir}/%{name}/release.php +%attr(0750,%{name},apache) %{wwwdir}/%{name}/subrou.php +%attr(0750,%{name},apache) %{wwwdir}/%{name}/unienv.php +%attr(0750,%{name},apache) %{wwwdir}/%{name}/unilng.php +%attr(0640,%{name},apache) %{wwwdir}/%{name}/reg-icons/*.gif +%attr(0640,%{name},apache) %{wwwdir}/%{name}/reg-icons/*.png +%attr(0644,root,root) %{_datadir}/%{name}/sql/%{name}.sql +%attr(0644,root,root) %{_datadir}/%{name}/sql/preset.sql +%exclude %{_datadir}/%{name}/sql/%{name}.mysql +%exclude %{_datadir}/%{name}/sql/%{name}.postg +#----------------------------------------------------------------------------- + +%preun +OS=`%{_libdir}/%{name}/shell/getsysos.sh` +if [ "$1" = 0 ]; then + case "$OS" in + "sysv" | \ + "osukiss" ) + for action in %{name} receiver scanner sender sorter + do + %{_initrddir}/${action} stop > /dev/null 2>&1 || : + %{_sbindir}/chkconfig --del ${action} + #removing remaining init synlink + %{__rm} %{_initrddir}/${action} + done + ;; + * ) + echo "Unable to find distribution" + exit -1 + ;; + esac + %{_sbindir}/userdel %{name} + ( + /bin/echo -n "%{name}-%{version} has been fully removed on "; date + /bin/echo "remaining file in this directory are data-base and logs" + /bin/echo "created while %{name} was in production." + /bin/echo "these files _may_ be removed too, but that they could" + /bin/echo "contain valuable data and admin should be careful" + /bin/echo "when removing them." + ) > %{_var}/log/README-%{name}-removed + fi + +%pre +if [ ! "$(getent passwd %{name})" ]; then + %{_sbindir}/useradd \ + -r \ + -c "%{name} daemon" \ + -K SYS_UID_MIN=50 \ + -K SYS_UID_MAX=99 \ + -g mail \ + -s /usr/bin/bash \ + -d %{_var}/spool/%{name} \ + %{name} + fi + +%post +OS=`%{_libdir}/%{name}/shell/getsysos.sh` +ln -nsf \ + ./lvllog.php \ + %{_var}/www/%{name}/index.php \ + +if [ "$1" = 1 ]; then + ( + echo "#------------------------------------------" + echo "#Architecture type was set by rpm first install procedure" + echo "#"`date` + echo "AP_ARCH=%{_arch}" + echo "#------------------------------------------" + ) >> %{_sysconfdir}/%{name}/install + #installing init file according OS + case "$OS" in + "sysv" | \ + "osukiss" ) + for action in %{name} receiver scanner sender sorter + do + %{__ln_s} \ + %{_datadir}/%{name}/linux/$OS/${action} \ + %{_initrddir}/${action} + done + %{_sbindir}/chkconfig --add %{name} + %{_sysconfdir}/rc.d/init.d/%{name} condrestart > /dev/null 2>&1 || : + ;; + * ) + echo "Unable to find distribution" + exit -1 + ;; + esac + fi + +%posttrans +OS=`%{_libdir}/%{name}/shell/getsysos.sh` +case "$OS" in + "sysv" | \ + "osukiss" ) + %{_sysconfdir}/rc.d/init.d/dovecot restart > /dev/null 2>&1 || : + ;; + * ) + ;; + esac + +#============================================================================= +%package devel +Summary : tools and components to test '%{name}' + +#----------------------------------------------------------------------------- + +Requires : %{name} = %{version}-%{release} +Requires : gdb + +#----------------------------------------------------------------------------- +%description devel +'%{name}' tools and data set to improve/debug '%{name}' + +#----------------------------------------------------------------------------- +%files devel +%defattr(-,root,root,-) +%attr(0750,root,root) %{_libdir}/%{name}/tools/genpsdusr.sh +%attr(0640,root,root) %{_datadir}/%{name}/sql/datatest.sql +%attr(0640,root,root) %{_datadir}/%{name}/sql/Makefile +%attr(0644,root,root) %{_datadir}/%{name}/sql/datatest.def + +#============================================================================= +%package pgsql +Summary : mailleur using postgresql as Data-base + +#----------------------------------------------------------------------------- + +Requires : %{name} = %{version}-%{release} +Requires : php-pgsql +Requires : postgresql-server +Requires : postgresql-contrib +Requires : dovecot-postgresql + +Obsoletes : %{name}-mysql <= %{version}-%{release} +#----------------------------------------------------------------------------- +%description pgsql +'%{name}' is configured to work with POSTGRESQL type database + +#----------------------------------------------------------------------------- +%files pgsql +%defattr(-,root,root,-) +#dovecot SQL database access +%attr(0644,%{name},mail) %config(noreplace) %{dovedir}/70-%{name}-pgsql.conf +#library to access postgres +%attr(0755,%{name},mail) %{_libexecdir}/%{name}/bin-posql/* + +#----------------------------------------------------------------------------- +%post pgsql +OS=`%{_libdir}/%{name}/shell/getsysos.sh` +if [ "$1" = 1 ]; then + sed -i \ + -e "s/^DB_TYPE=.*$/DB_TYPE=POSTGRESQL/" \ + -e "s/^DB_PORT=.*$/DB_PORT=5432/" \ + %{_sysconfdir}/%{name}/%{name}.conf + fi + +#generating postgresql receiver and sender +#generating exec to be path of the /usr/sbin path +for exe in \ + receiver \ + scanner \ + sender \ + sorter + do + %{__ln_s} -nsf \ + %{_libexecdir}/%{name}/bin-posql/$exe \ + %{_sbindir} + done + +case "$OS" in + "sysv" | \ + "osukiss" ) + for action in %{name} + do + %{_sbindir}/chkconfig --add ${action} + %{_sysconfdir}/rc.d/init.d/${action} condrestart > /dev/null 2>&1 || : + done + ;; + * ) + echo "Unable to find distribution" + exit -1 + ;; + esac + +#adjusting libexec bin directory +%{__ln_s} -nsf ./bin-posql %{_libexecdir}/%{name}/bin + +%postun pgsql +if [ "$1" = 0 ]; then + rm -f %{_libexecdir}/%{name}/bin + rm -f %{_sbindir}/receiver + rm -f %{_sbindir}/scanner + rm -f %{_sbindir}/sender + rm -f %{_sbindir}/sorter + fi + +%posttrans pgsql +if [ "$1" = 1 ]; then + OS=`%{_libdir}/%{name}/shell/getsysos.sh` + case "$OS" in + "sysv" | \ + "osukiss" ) + %{_sysconfdir}/rc.d/init.d/postgresql restart > /dev/null 2>&1 || : + ;; + * ) + ;; + esac + fi + +#============================================================================= +%package mysql +Summary : mailleur using mysql/mariadb as Data-base + +#----------------------------------------------------------------------------- + +Requires : %{name} = %{version}-%{release} +Requires : mariadb +Requires : php-mysqlnd +Requires : dovecot-mysql + +Obsoletes : %{name}-postgresql <= %{version}-%{release} +#----------------------------------------------------------------------------- +%description mysql +'%{name}' is configured to work with MYSQL/MARIADB type database + +#----------------------------------------------------------------------------- +%files mysql +%defattr(-,root,root,-) +#dovecot SQL database access +%attr(0644,%{name},mail) %config(noreplace) %{dovedir}/70-%{name}-mysql.conf +#library to access mariadb +%attr(0755,%{name},mail) %{_libexecdir}/%{name}/bin-mysql/* + +#----------------------------------------------------------------------------- + +%post mysql +OS=`%{_libdir}/%{name}/shell/getsysos.sh` +if [ "$1" = 1 ]; then + sed -i \ + -e "s/^DB_TYPE=.*$/DB_TYPE=MYSQL/" \ + -e "s/^DB_PORT=.*$/DB_PORT=3306/" \ + %{_sysconfdir}/%{name}/%{name}.conf + fi +#generating exec to be path of the /usr/sbin path +for exe in \ + receiver \ + scanner \ + sender \ + sorter + do + %{__ln_s} -nsf \ + %{_libexecdir}/%{name}/bin-mysql/$exe \ + %{_sbindir}/ + done + +case "$OS" in + "sysv" | \ + "osukiss" ) + for action in %{name} + do + %{_sbindir}/chkconfig --add ${action} + %{_sysconfdir}/rc.d/init.d/${action} condrestart > /dev/null 2>&1 || : + done + ;; + * ) + echo "Unable to find distribution" + exit -1 + ;; + esac + +#adjusting libexec bin directory +%{__ln_s} -nsf ./bin-mysql %{_libexecdir}/%{name}/bin + +%postun mysql +if [ "$1" = 0 ]; then + rm -f %{_libexecdir}/%{name}/bin + rm -f %{_sbindir}/receiver + rm -f %{_sbindir}/scanner + rm -f %{_sbindir}/sender + rm -f %{_sbindir}/sorter + fi + +%posttrans mysql +if [ "$1" = 1 ]; then + OS=`%{_libdir}/%{name}/shell/getsysos.sh` + case "$OS" in + "sysv" | \ + "osukiss" ) + %{_sysconfdir}/rc.d/init.d/mysqld restart > /dev/null 2>&1 || : + ;; + * ) + ;; + esac + fi + +#============================================================================= +%prep +%setup -q +#----------------------------------------------------------------------------- +#building application +%build + +%{__make} + +#----------------------------------------------------------------------------- +%clean +%{__rm} -rf %{buildroot} + +#----------------------------------------------------------------------------- +#installing program +%install + +%{__make} \ + DESTDIR="%{buildroot}" \ + install + +date > %{buildroot}%{_libdir}/%{name}/rpm_build_date + +#============================================================================= +%changelog diff --git a/shell/getsysos.sh b/shell/getsysos.sh new file mode 100644 index 0000000..17c9f2a --- /dev/null +++ b/shell/getsysos.sh @@ -0,0 +1,25 @@ +#! /usr/bin/bash +#--------------------------------------------------- +#shell script to get the OS used to run clement + +DIST=` \ + cat /etc/os-release | \ + grep "^ID=" | \ + sed -e 's:"::g' | \ + cut -d '=' -f2 | \ + tr '[:upper:]' '[:lower:]' \ + ` + +case "$DIST" in + "osukiss" ) #Osukiss distribution + OS="osukiss" + ;; + "rocky" | \ + "fedora" ) + OS="systemd" #systemd distribution + ;; + * ) #all other are system V + OS="sysv" + ;; + esac +echo $OS diff --git a/shell/test-spf.sh b/shell/test-spf.sh new file mode 100755 index 0000000..bda07d6 --- /dev/null +++ b/shell/test-spf.sh @@ -0,0 +1,35 @@ +#! /usr/bin/bash +#--------------------------------------------------------------------- +#shell script to test SPF directive +#--------------------------------------------------------------------- +numfile=0; +numerr=0; +while [ $# -gt 0 ] + do + filename=$1 + numfile=$((numfile+1)) + numline=0 + echo "scanning \"$1\" test file" + while read line + do + numline=$((numline+1)) + data=`echo $line | grep -o '^[^#]*'` + if [ -z "$data" ] ; then + continue; + fi + expect=`echo $data | cut -d ' ' -f1` + domain=`echo $data | cut -d ' ' -f2` + ipnum=`echo $data | cut -d ' ' -f3` + result=`bin-utils/chkspf $domain $ipnum` + echo -n "done bin-utils/chkspf $domain $ipnum " + if [ "$result" != "$expect" ] ; then + echo "Fail!" + numerr=$((numerr+1)) + echo -e "\tError=$numerr\tline $numline, Expected:=$expect Result:=$result" + else + echo "Success" + fi + done < $1 + shift + done +echo "number of test file scanned: $numfile, total error reported: $numerr"; diff --git a/sql/.gitignore b/sql/.gitignore new file mode 100644 index 0000000..79d5f73 --- /dev/null +++ b/sql/.gitignore @@ -0,0 +1 @@ +popul.sql diff --git a/sql/Makefile b/sql/Makefile new file mode 100644 index 0000000..86d3b8f --- /dev/null +++ b/sql/Makefile @@ -0,0 +1,100 @@ +#-------------------------------------------------------------------- +#Generate database for postgresql and mysql +#-------------------------------------------------------------------- +prod \ +debug \ + : mailleur.postg mailleur.mysql + +allclean \ +clean : + @ rm -fr mailleur.mysql mailleur.postg + +#-------------------------------------------------------------------- + +prepdb : newpop debug deltest newtest + +mailleur.postg \ + : mailleur.sql + @ cpp -P -DPOSTGRESQL \ + mailleur.sql > mailleur.postg + +mailleur.mysql \ + : mailleur.sql + @ cpp -P -DMYSQL \ + mailleur.sql > mailleur.mysql + +dbmysql : mailleur.mysql + @ - ( \ + echo "CREATE USER `id -un`@localhost;"; \ + echo "CREATE USER apache@localhost;"; \ + echo "CREATE USER dovecot@localhost;"; \ + echo "GRANT ALL ON mailleur.* \ + TO `id -un`@localhost \ + WITH GRANT OPTION;"; \ + echo "FLUSH PRIVILEGES;"; \ + echo "CREATE DATABASE mailleur;"; \ + echo "ALTER DATABASE mailleur \ + CHARACTER SET utf8;"; \ + ) | sudo mariadb -q + @ cat mailleur.mysql | mariadb -q mailleur; + @ cpp -P -DMYSQL \ + datatest.sql | mariadb -q mailleur; + cpp -P -traditional -DMYSQL \ + popul.sql | mariadb -q mailleur; + @ echo "MYSQL database ready" + + +ndbmysql: + @-( \ + echo "DROP DATABASE mailleur;"; \ + echo "DROP USER dovecot@localhost;"; \ + echo "DROP USER apache@localhost;"; \ + echo "DROP USER `id -un`@localhost;"; \ + ) | sudo mariadb + +dbpostg : mailleur.postg + @ -( \ + echo "CREATE ROLE apache WITH LOGIN;"; \ + echo "CREATE ROLE dovecot WITH LOGIN;"; \ + echo "CREATE EXTENSION pgcrypto;"; \ + echo "CREATE DATABASE mailleur "; \ + echo " ENCODING='UTF8';"; \ + ) | psql -q -U postgres template1 + @ cat mailleur.postg | psql -q mailleur; + @ cpp -DPOSTGRESQL \ + -P \ + -traditional \ + datatest.sql | \ + sed -e"/^\/\//d" | \ + psql -q mailleur; + @ cpp -DPOSTGRESQL \ + -P \ + -traditional \ + popul.sql | \ + sed -e"/^\/\//d" | \ + psql -q mailleur; + @ echo "POSGRESQL database ready" + +ndbpostg: + @-( \ + echo "drop database mailleur;"; \ + echo "DROP ROLE apache;"; \ + echo "DROP ROLE dovecot;"; \ + echo "DROP EXTENSION pgcrypto;"; \ + ) | psql -q -U postgres template1 + +#-------------------------------------------------------------------- +#procedure to delete or create a postgresql and mysql test database + +newtest : dbpostg dbmysql + +deltest : ndbpostg ndbmysql + +newpop : + @ ../tools/genpsdusr.sh 2000 > popul.sql + @ echo "New 'popul' database created" + +#-------------------------------------------------------------------- +#-------------------------------------------------------------------- +.PHONY: deltest +#-------------------------------------------------------------------- diff --git a/sql/datatest.def b/sql/datatest.def new file mode 100644 index 0000000..c09079f --- /dev/null +++ b/sql/datatest.def @@ -0,0 +1,16 @@ + +//X------------------------------------------------------------------ +//include file to ajuste result according database +//Y------------------------------------------------------------------ +#ifdef POSTGRESQL +#define ADDTIME(adding) 'adding' +#define CONCAT(A,B) A||B +#define INET_ATON(A) A +#define ENCRYPT(A,B) encrypt(A,B,'aes') +#endif +#ifdef MYSQL +#define ADDTIME(adding) INTERVAL adding +#define CONCAT(A,B) concat(A,B) +#define INET_ATON(A) inet_aton(A) +#define ENCRYPT(A,B) encrypt(A,B) +#endif diff --git a/sql/datatest.sql b/sql/datatest.sql new file mode 100644 index 0000000..1f72759 --- /dev/null +++ b/sql/datatest.sql @@ -0,0 +1,81 @@ + +#include "datatest.def" + +//First remove ALL Email data +DELETE FROM emails; +//password is generated via command line: +//openssl password +//present password is crypted as a hash and in password too +//adding a list of local email + +//============================================================== +//set for local test +INSERT INTO emails (email,password,lang) \ + values ('jmp@example.com','4cabri','FRA'); +INSERT INTO emails (email,password) \ + values ('root@example.com','4cabri'); +INSERT INTO emails (email,password) \ + values ('postmaster@example.com','postmaster'); +INSERT INTO emails (email,password) \ + values ('webmaster@example.com','webmaster'); +INSERT INTO emails (email,password) \ + values ('utf8-áö_üñ@example.com','utf8-áö_üñ'); +INSERT INTO emails (email,password) \ + values ('user1@mailleur.example.com','user1'); + +//Set for system with Postgresql database +INSERT INTO emails (email,password) \ + values ('user1@posdb.example.com','user1'); +INSERT INTO emails (email,password) \ + values ('user2@posdb.example.com','user2'); + +//Set for system with MySQL database +INSERT INTO emails (email,password) \ + values ('user1@mardb.example.com','user1'); +INSERT INTO emails (email,password) \ + values ('user2@mardb.example.com','user2'); + +//============================================================== +//List of remote IP status +//good credit IP +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('127.127.0.25',10,now()); +//--------------------------------------------------------------- +//low credit IP +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('27.151.45.98',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('45.197.14.139',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('213.209.157.107',-5,now()+ADDTIME(200 day)); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('213.209.157.108',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('122.175.193.134',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('176.53.146.143',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('209.85.218.68',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('216.246.113.145',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('193.111.208.122',-5,now()); + +//============================================================== +//selected IP from from 'clean' server +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('192.219.254.189',100,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('216.252.69.41',100,now()); + +//selected IP with with very low credit +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('127.127.127.127',-50,now()); + +//============================================================== +//defining admin user +INSERT INTO admins (email) \ + values ('root@example.com'); +INSERT INTO admins (email) \ + values ('jmp@example.com'); +//============================================================== diff --git a/sql/mailleur.sql b/sql/mailleur.sql new file mode 100644 index 0000000..bd7faed --- /dev/null +++ b/sql/mailleur.sql @@ -0,0 +1,232 @@ +/********************************************************/ +/* */ +/* This file define the mailleur data base */ +/* structure */ +/* */ +/********************************************************/ +/*Specific PostgreSQL data base definitions */ +#ifdef POSTGRESQL +#define AUTOSERIAL SERIAL UNIQUE +#define DURATION TIMESPAN +#define DBTIMESTAMP TIMESTAMP(0) WITH TIME ZONE +#define DBNAN 'NaN' +#define DFLT DEFAULT +#define SHORTTEXT TEXT +#define TEXTUNIQUE TEXT UNIQUE NOT NULL +#define INS(name) name /*index size */ +#define ESCLIT E +#define mailapache apache +#define maildove dovecot +#define CASESENSITIVE +#define ADDTIME(adding) 'adding' +#define INET inet +#define CRYPTED bytea +#endif + +/*Specific MySQL type data base definitions */ +#if defined(MYSQL) || defined(MYSQLI) +#define AUTOSERIAL INTEGER AUTO_INCREMENT UNIQUE PRIMARY KEY +#define DURATION INT8 +#define DBTIMESTAMP TIMESTAMP NULL +#define DBNAN NULL +#define DFLT DEFAULT +#define SHORTTEXT VARCHAR(30) +#define TEXTUNIQUE VARCHAR(100) UNIQUE NOT NULL +#define INS(name) name(80) /*index size */ +#define ESCLIT +#define mailapache 'apache'@'localhost' +#define maildove 'dovecot'@'localhost' +#define CASESENSITIVE CHARACTER SET latin1 COLLATE latin1_bin +#define ADDTIME(adding) INTERVAL adding +#define INET VARBINARY(16) +#define CRYPTED MEDIUMBLOB +#endif + +/********************************************************/ +/********************************************************/ +/* */ +/* User available email definition table */ +/* */ +/********************************************************/ +//table to define LOCAL USER +CREATE TABLE emails ( + email TEXTUNIQUE, //User email + creation DBTIMESTAMP //record creation + DFLT NOW(), + lastemail DBTIMESTAMP //last email received + DFLT NOW(), + lastscan DBTIMESTAMP //last scaning date + DFLT NOW(), + password TEXT //user (encrypted) password + DFLT '!', + hash TEXT, //'email:realm:password' MD5 + lang TEXT //user prefered language + DFLT 'ENG', //English by default + space INTEGER //space used by user email + DFLT 0, + mxspace INTEGER //Maximun space available + DFLT 20000, //to user (20 Gig). + locked INTEGER //The account is locked out + DFLT 0 + ); +GRANT SELECT,INSERT,UPDATE,DELETE ON emails TO mailapache; +GRANT SELECT ON emails TO maildove; + + +//table about session +CREATE TABLE sessions ( + creation DBTIMESTAMP //record creation + DFLT NOW(), + sessid TEXTUNIQUE, //Session id + sesstitle TEXT, //The session email title + sessfrom TEXT, //The session from + emailfrom TEXT, //The from within the email itself + taille INTEGER //The email size + DFLT 0, + duration TEXT //email transfer duration + DFLT NULL + ); +GRANT SELECT ON sessions TO mailapache; + +//table about recipient email information +//summerize all emails received actions status according sessions and recipient +CREATE TABLE actions ( + creation DBTIMESTAMP //record creation + DFLT NOW(), + code SHORTTEXT, //action status (one char) + sessid TEXT, //Session id + remoteip TEXT //Remote serveur IP number + DFLT NULL, + reverse TEXT //remote server reverse address name + DFLT 'Unknown IP', + smtpfrom TEXT, //SMTP Connection "MAIL FROM:" + rcptto TEXT, //SMTP Connection "RCPT TO:" + emailfrom TEXT, //email contents "From:" + subject TEXT, //email contents "Subject:" + status INTEGER, //info status + numline INTEGER, //status line + info TEXT //line info + ); +GRANT SELECT ON sessions TO mailapache; + +//defining table about remote server +CREATE TABLE remotes ( + remoteip TEXTUNIQUE, //remote IP number + lastscan DBTIMESTAMP //record last update + DFLT '1970-01-01', + lastupdate DBTIMESTAMP //record creation + DFLT NOW(), + credit INTEGER //Remote IP current credit (-100..+100) + DFLT 5, + reverse TEXT //Remote official revers address + DFLT NULL, + listing TEXT //explaination about black listing + DFLT NULL, + links INTEGER + DFLT 1 //how many time the remote connected + ); +CREATE INDEX remotes_ndx ON remotes(lastscan,lastupdate); +//set a local IP +INSERT INTO remotes (remoteip,reverse,credit,lastscan) \ + values ('127.0.0.1','localhost.localldomain',99,now()); + +//defining table about eventlog reference +CREATE TABLE events ( + creation DBTIMESTAMP //record creation + DFLT NOW(), + serial AUTOSERIAL, //record unique number + sessid TEXTUNIQUE, //Session id + start INTEGER, //Event log starting point + stop INTEGER //Event log ending point + ); +CREATE INDEX event_id_ndx ON events(sessid); +CREATE INDEX event_date_ndx ON events(creation); + + +//defining table about email aliases +//list of aliases related to ONE email +CREATE TABLE aliases ( + email TEXT, //Email address + alias TEXT //One aliases + ); +CREATE INDEX aliases_id_ndx ON aliases(email); + +//List all currently opened cookies +CREATE TABLE cookies ( + cookuuid TEXTUNIQUE, //cookies unique id + email TEXT, //user email address + expire DBTIMESTAMP //cookies date limit + ); + +//List emails address with admin capablities +CREATE TABLE admins ( + email TEXT //user email address + ); + +//-------------------------------------------------------------- +//Defining TRIGGER fonctions according database type +//-------------------------------------------------------------- +//Caution this REALM value MUST be the same as defined +//in mailleur.conf +#define REALM 'mailleur-email' +#define HASHING concat(NEW.email,':',REALM,':',NEW.password) + + +#ifdef POSTGRESQL +CREATE FUNCTION updpass() + RETURNS trigger AS $$ + BEGIN + IF NEW.password IS NULL OR + length(trim(NEW.password)) = 0 OR + substring(NEW.password,1,1) = '$' THEN + NEW.hash=NULL; + NEW.password=NEW.password; + ELSE + NEW.hash = md5(HASHING); + NEW.password = crypt (NEW.password,gen_salt('md5')); + END IF; + RETURN NEW; + END; + $$ LANGUAGE 'plpgsql'; + +CREATE TRIGGER keephash + BEFORE INSERT OR UPDATE on emails + FOR EACH ROW EXECUTE PROCEDURE updpass(); +#endif + +#if defined(MYSQL) || defined(MYSQLI) + +DELIMITER $$ + +CREATE TRIGGER sethash + BEFORE UPDATE ON emails FOR EACH ROW + BEGIN + IF NEW.password IS NULL OR + LENGTH(TRIM(NEW.password))=0 OR + LEFT(NEW.password,1) = '$' THEN + set NEW.hash=NULL; + set NEW.password=NEW.password; + else + set NEW.hash=MD5(HASHING); + set NEW.password=encrypt(NEW.password,concat('$1$',md5(rand()))); + END IF; + END$$ + + +CREATE TRIGGER updhash + BEFORE INSERT ON emails FOR EACH ROW + BEGIN + IF NEW.password IS NULL OR + LENGTH(TRIM(NEW.password))=0 OR + LEFT(NEW.password,1) = '$' THEN + set NEW.hash=NULL; + set NEW.password=NEW.password; + else + set NEW.hash=MD5(HASHING); + set NEW.password=encrypt(NEW.password,concat('$1$',md5(rand()))); + END IF; + END$$ + +DELIMITER ; + +#endif diff --git a/sql/preset.sql b/sql/preset.sql new file mode 100644 index 0000000..7088111 --- /dev/null +++ b/sql/preset.sql @@ -0,0 +1,27 @@ + +/********************************************************/ +/* */ +/* This file define the mailleur data base */ +/* local preset value */ +/* */ +/********************************************************/ + +/********************************************************/ +/* */ +/* Creating the bare minimun user configuration */ +/* */ +/********************************************************/ +//root is the default preset admin +INSERT INTO admins (email) + VALUES (ROOTDOMAINNAME); + +//inserting the mail account +INSERT INTO emails (email,password) + VALUES (ROOTDOMAINNAME,RPASS); + +/********************************************************/ +/* */ +/* Preset value completed */ +/* */ +/********************************************************/ + diff --git a/support/addconfig.sh b/support/addconfig.sh new file mode 100755 index 0000000..7f5f076 --- /dev/null +++ b/support/addconfig.sh @@ -0,0 +1,19 @@ +#! /usr/bin/bash +#----------------------------------------------------------------- +#Shell script to add local information to configuration file +#----------------------------------------------------------------- +export APPNAME=mailleur +export SPOOLDIR=/var/spool/$APPNAME/mails +#loading all applications variables +[ -f /etc/$APPNAME/$APPNAME.conf ] && . /etc/$APPNAME/$APPNAME.conf +#overiding some variable by local setting +[ -f /etc/sysconfig/$APPNAME ] && . /etc/sysconfig/$APPNAME +#----------------------------------------------------------------- +#loading the variable value +LOCDOM=`dnsdomainname` + +sed -i \ + -e "s/^DFLTDOM.*$/DFLTDOMAIN=\"$LOCDOM\"/" \ + /etc/$APPNAME/$APPNAME.conf + + diff --git a/support/do_database.sh b/support/do_database.sh new file mode 100755 index 0000000..ccf4a9e --- /dev/null +++ b/support/do_database.sh @@ -0,0 +1,124 @@ +#! /usr/bin/bash +#------------------------------------------------------------- +#$1 working directory +#procedure to create the clement data-base the first +#time the application is installed. +#------------------------------------------------------------- +#loading the variable value +. /etc/mailleur/mailleur.conf +#------------------------------------------------------------- + +#setting the Variable +#first the Data-base type +if [ -z "$DB_TYPE" ] ; then + DB_TYPE=POSTGRESQL; + fi + +#Then the data-base name +if [ -z "$DB_NAME" ] ; then + DB_NAME=$APPNAME; + fi +#------------------------------------------------------------- +#moving to the right directory +cd $1 +LOG=/etc/$APPNAME/dbinst.log +SQLLOG=/etc/$APPNAME/dbinfo.log +USER=`id -nu` +#building data_base +( +echo "#==========================================" +date +echo "#------------------------------------------" +/bin/echo "creating $DB_TYPE:$DB_NAME data-base" >> $LOG +/bin/echo "LANG=<"$LANG"> DB_LANG=<"$DB_LANG">" +) >> $LOG + +case "$DB_TYPE" in + "TO_BE_DEFINED" ) + echo "Data base type is NOT set within mailleur.conf" + exit 1 + ;; + "MYSQL" ) + SQL="/usr/bin/mariadb" + MSQL="/usr/bin/mariadb $APPNAME -q" + /etc/rc.d/init.d/mysqld status + if [ $? != 0 ] ; then + echo "MySQL serveur NOT found up and running (exiting!)" + exit 1 + fi + if [ "$USER" = "root" ] ; then + chown $APPNAME $LOG + ( + echo "CREATE USER apache@localhost;" + echo "GRANT USAGE ON $APPNAME.* TO apache@localhost;" + echo "CREATE USER dovecot@localhost;" + echo "GRANT USAGE ON $APPNAME.* TO dovecot@localhost;" + echo "GRANT SELECT ON $APPNAME.* TO dovecot@localhost;" + echo "CREATE USER $APPNAME@localhost;" + echo "GRANT ALL PRIVILEGES ON $APPNAME.* TO $APPNAME@localhost;" + echo "FLUSH PRIVILEGES;" + echo "CREATE DATABASE $APPNAME;" + echo "ALTER DATABASE $APPNAME CHARACTER SET utf8;" + ) | $SQL >> $LOG 2>&1 + /bin/echo "data-base is now created" >> $LOG + fi + ;; + "*" ) + #undefined database type at that stage? + ;; + "POSTGRESQL" ) + SQL="/usr/bin/psql -q" + MSQL="/usr/bin/psql -U $APPNAME -q $APPNAME" + /etc/rc.d/init.d/postgresql status + if [ $? != 0 ] ; then + echo "Postgresql serveur NOT found up and running (exiting!)" + exit 1 + fi + if [ ! -z "$DB_PORT" ] ; then + SQLPORT="-p $DB_PORT" + fi + if [ ! -z "$DB_HOST" ] ; then + SQLHOST="-h $DB_HOST" + fi + if [ "$USER" = "root" ] ; then + chown $APPNAME $LOG + ( + echo "CREATE ROLE $APPNAME WITH LOGIN CREATEDB SUPERUSER;" + echo "CREATE ROLE apache WITH LOGIN;" + echo "CREATE ROLE dovecot WITH LOGIN;" + echo "CREATE EXTENSION IF NOT EXISTS pgcrypto;" + echo "CREATE DATABASE $APPNAME ENCODING='UTF8';" + ) | /usr/bin/su - -m postgres -c "$SQL $SQLHOST $SQLPORT template1" >> $LOG 2>&1 + echo "data-base is now created" >> $LOG + fi + ;; + "*" ) + #undefined database type at that stage? + ;; + esac +#loading database definition +if [ -n "$MSQL" ] ; then + echo "#--------------- Create Database ----------------" >> $SQLLOG + cpp -P -D$DB_TYPE /usr/share/$APPNAME/sql/$APPNAME.sql | \ + tee -a $SQLLOG | \ + $MSQL >> $SQLLOG 2>&1 + echo "#--------------- Set Preset value ---------------" >> $SQLLOG + cpp -P -D$DB_TYPE \ + -DDOMAINNAME=\'$DOMAINNAME\' \ + -DROOTDOMAINNAME=\'root@$DOMAINNAME\' \ + -DRPASS=\'$RPASS\' \ + /usr/share/$APPNAME/sql/preset.sql | \ + tee -a $SQLLOG | \ + $MSQL >> $SQLLOG 2>&1 + if [ -f /usr/share/$APPNAME/sql/dataset.sql ] ; then + echo "#--------------- Set dataset value ---------------" >> $SQLLOG + cpp -P -D$DB_TYPE \ + -DDOMAINNAME=\'$DOMAINNAME\' \ + -DROOTDOMAINNAME=\'root@$DOMAINNAME\' \ + -DRPASS=\'$RPASS\' \ + /usr/share/$APPNAME/sql/dataset.sql | \ + tee -a $SQLLOG | \ + $MSQL >> $SQLLOG 2>&1 + fi + echo "#--------------- Init Process Completed ---------" >> $SQLLOG + fi diff --git a/support/do_dns_tlsa.sh b/support/do_dns_tlsa.sh new file mode 100755 index 0000000..0d04cf2 --- /dev/null +++ b/support/do_dns_tlsa.sh @@ -0,0 +1,119 @@ +#! /usr/bin/bash +#------------------------------------------------------------------- +#procedure to generate a lets encrypt certificate with a contanst +#public/private key +#------------------------------------------------------------------- +#comment in if working in production +DRYRUN="--dry-run" +STAGING="--staging" +MRKR=`date +"%F"` +APPNAME=mailleur +#------------------------------------------------------------------- +WRKDIR=/etc/certbot/$APPNAME + +gen_cnf() + +{ +if [ ! -f ./cnffile ] ; then + #generate a config file + cat > ./cnffile << EOT +[req] +distinguished_name=req_dn +[req_dn] +commonName=`uname -n` +[SAN] +subjectAltName=DNS:`uname -n` +EOT + fi +} + +gen_key() + +{ +#Generate an Elliptic Curve Digital Signature Algorithm +if [ ! -f ./ec_key.pem ] ; then + openssl ecparam \ + -out ./ec_key.pem \ + -genkey \ + -name prime256v1 + fi +} + + +gen_req() + +{ +#Generate the CSR request +openssl req \ + -config ./cnffile \ + -outform PEM \ + -new \ + -nodes \ + -subj '/' \ + -reqexts SAN \ + -out ./request.csr \ + -keyout ./$APPNAME-key.pem \ + -key ./ec_key.pem +} + + +gen_cert() + +{ +#Request certificate (with a steady key) via cerbot +#Note" this is done in dry-run mode (remove it to +#pass in production mode) + +#removing previous +rm -f ./$MRKR-* +certbot certonly \ + --apache \ + --force-renewal \ + --csr ./request.csr \ + --fullchain-path ./$MRKR-fullchain.pem \ + --chain-path ./$MRKR-chain.pem \ + --cert-path ./$MRKR-cert.pem \ + --work-dir . \ + --logs-dir ./logs \ + $STAGING \ + $DRYRUN \ + +ln -nsf \ + ./$MRKR-fullchain.pem \ + ./$APPNAME-fullchain.pem + +ln -nsf \ + ./$MRKR-chain.pem \ + ./$APPNAME-chain.pem + +ln -nsf \ + ./$MRKR-cert.pem \ + ./$APPNAME-cert.pem + +} + +gen_dane () + +{ +SUM=`openssl ec -in ./ec_key.pem -pubout -outform DER 2>/dev/null | sha256sum` + +( +echo ";--------------------------------------------" +echo ";TLSA record to be inserted in domain DNS" +echo -e "_25._tcp.`hostname -s`\tTLSA\t3 1 1\t$SUM" +echo -e "_465._tcp.`hostname -s`\tTLSA\t3 1 1\t$SUM" +echo -e "_587._tcp.`hostname -s`\tTLSA\t3 1 1\t$SUM" +echo ";--------------------------------------------" +) > ./dns_tlsa +} + +#Set working directory +mkdir -p $WRKDIR +cd $WRKDIR + +gen_cnf +gen_key +gen_req +gen_cert +gen_dane + diff --git a/support/do_httpd.sh b/support/do_httpd.sh new file mode 100755 index 0000000..2f1a532 --- /dev/null +++ b/support/do_httpd.sh @@ -0,0 +1,105 @@ +#! /usr/bin/bash +#----------------------------------------------------------------- +#Shell script to add local information to configuration file +#----------------------------------------------------------------- +#loading the variable value +. /etc/mailleur/mailleur.conf +#----------------------------------------------------- +#Updating clement httpd configuration file +export hostipv4=`dig \`uname -n\` A +noall +short`; +export hostipv6=`dig \`uname -n\` AAAA +noall +short`; +if [ -z "$domain" ] ; then + export domain=`dnsdomainname` + fi + +#to make sure we have at least an hostipv4 reference +if [ -z "$hostipv4" -a -z "$hostipv6" ] ; then + export hostipv4=`grep \`uname -n\` /etc/hosts | cut -f1` + fi +#----------------------------------------------------------------- +add_web() + +{ +#updating httpd.con +sed -i \ + -e "s:#LoadModule ssl_:LoadModule ssl_:" \ + -e "s:#LoadModule rewrite:LoadModule rewrite:" \ + -e "s:#LoadModule socache_shmcb_module:LoadModule socache_shmcb_module:" \ + /etc/httpd/httpd.conf + +#converting '.' to '\.' +reldom=`echo $domain | sed -e "s/\\./\\\\\\./g"` + +cat >> /etc/httpd/conf.d/$APPNAME.conf < + ServerName `hostname` + ServerAlias $APPNAME.$domain + ServerAlias localhost.localdomain + ServerAdmin root@$domain + RewriteEngine on + #comment in if you want to debug redirect + #LogLevel alert rewrite:trace3 + RewriteCond %{HTTP_HOST} ^$APPNAME\.$reldom [OR] + RewriteCond %{HTTP_HOST} ^`hostname -s`\.$reldom + RewriteRule ^(.*)$ https://`hostname -s`.$domain [R=301] + ErrorLog logs/mailerr.log + TransferLog logs/maillog.log + + +#----------------------------------------------------------------- +#Listening on TLS port +Listen 443 + +SSLSessionCache "shmcb:logs/ssl_scache(512000)" +SSLSessionCacheTimeout 300 + +#----------------------------------------------------------------- + + ServerName `hostname` + ServerAlias $APPNAME.$domain + ServerAlias localhost.localdomain + ServerAdmin root@$domain + DocumentRoot /var/www/$APPNAME + Alias reg-icons /var/www/$APPNAME/reg-icons + + Options MultiViews FollowSymlinks ExecCGI + AllowOverride AuthConfig FileInfo Indexes Limit Options + Require all granted + + #---------------------------------------------- + #SSL + SSLEngine On + SSLCertificateKeyFile /etc/pki/$APPNAME/$APPNAME-key.pem + SSLCertificateFile /etc/pki/$APPNAME/$APPNAME-cert.pem + SSLProtocol +TLSv1.3 +TLSv1.2 + SSLCompression OFF + SSLHonorCipherOrder ON + #---------------------------------------------- + ErrorLog logs/mailerr-ssl.log + TransferLog logs/maillog-ssl.log + + +#$APPNAME STOP +!EOT +} + +#----------------------------------------------------------------- +#setting name virtual + +#to setup the IPV4 WEB interface +if [ -n "$hostipv4" ] ; then + add_web $hostipv4 + fi + +#----------------------------------------------------------------- +#to setup the IPV6 WEB interface +if [ -n "$hostipv6" ] ; then + add_web $hostipv6 + fi + +#restarting httpd server +service httpd restart + diff --git a/support/dummy-cert.sh b/support/dummy-cert.sh new file mode 100755 index 0000000..1655ad3 --- /dev/null +++ b/support/dummy-cert.sh @@ -0,0 +1,43 @@ +#! /usr/bin/bash +#--------------------------------------------------- +#shell script to create a dummy Certificat. +#--------------------------------------------------- +umask 077 + +answers() { + echo UN + echo "One State in the world" + echo "One City Somewhere" + echo "An Organization" + echo "$APPNAME E-mail filtering" + echo `hostname` + echo "$APPNAME@"`hostname` +} + +if [ $# -eq 0 ] ; then + echo $"Usage: `basename $0` filename [...]" + exit 0 +fi + +for target in $@ + do + PEM1=`mktemp /tmp/openssl.XXXXXX` + PEM2=`mktemp /tmp/openssl.XXXXXX` + trap "rm -f $PEM1 $PEM2" SIGINT + /usr/bin/openssl ecparam \ + -genkey \ + -name secp384r1 \ + -out $PEM1 + answers | \ + /usr/bin/openssl req \ + -key $PEM1 \ + -nodes \ + -x509 \ + -text \ + -sha384 \ + -days 3650 \ + -out $PEM2 2> /dev/null + cp $PEM1 ${target}-key.pem + cp $PEM2 ${target}-cert.pem + rm -f $PEM1 $PEM2 + done diff --git a/support/mailleur-reset-db.sh b/support/mailleur-reset-db.sh new file mode 100755 index 0000000..a1e5925 --- /dev/null +++ b/support/mailleur-reset-db.sh @@ -0,0 +1,73 @@ +#! /usr/bin/bash +#--------------------------------------------------------------- +#program to reset the database contents +#parameters ["doit"] "confdirectory +#--------------------------------------------------------------- +#start delay +APPLICATION=mailleur +DELAY=10 +DOIT=doit +#--------------------------------------------------------------- +OWNER=`stat -c '%U' $0` +USER=`id -nu` +if [ "$USER" != "$OWNER" ] ; then + echo "" + echo "-----------" + echo "ATTENTION! $0 MUST BE executed by $0 file owner, exiting" + echo "-----------" + exit 1 + fi +#--------------------------------------------------------------- +if [ $# -eq 0 -o $# -ge 1 -a "$1" != "$DOIT" ] ; then + echo "" + echo "-----------" + echo "ATTENTION!:" + echo "- You are requesting a FULL database RESET." + echo "- You are requesting spool directory contents erasing." + echo "" + echo "all data, (DB contents, email, logs) will be GONE forever." + echo "Are you sure!" + echo "You have $DELAY seconds to cancel (CTRL-C)" + echo "-----------" + sleep $DELAY + fi +if [ -n "$1" -a "$1" == "$DOIT" ] ; then + shift; + fi +CONF=/etc/$APPLICATION/$APPLICATION.conf +if [ $# -gt 0 ] ; then + CONF=$1 + fi +if [ ! -f $CONF ] ; then + echo "configuration file $CONF is missing, exiting!" + exit 1 + fi +. $CONF +#--------------------------------------------------------------- +#destroying the database +case "$DB_TYPE" in + "POSTGRESQL" ) + DB=$(psql -U postgres -tAc "SELECT 1 FROM pg_database WHERE datname='${APPNAME}'") + if [ "$DB" = "1" ] ; then + echo "drop database $APPNAME;" | psql -q -U postgres template1 + fi + echo "create database $APPNAME;" | psql -q -U postgres template1 + SQL="psql -q $APPNAME" + ;; + "MYSQL" ) + DB=$(mariadb-show | grep $APPNAME ) + if [ ! -z "$DB" ] ; then + echo "DROP DATABASE mailleur;" | mariadb + fi + echo "create database $APPNAME;" | mariadb + SQL="mariadb -q $APPNAME" + ;; + * ) + echo $DB_TYPE is not expected!, check configuration file! + exit 1 + ;; + esac + +#loading database +cpp -P -D$DB_TYPE $ROOTBASE/usr/share/$APPNAME/sql/$APPNAME.sql | $SQL +#cpp -P -D$DB_TYPE $ROOTBASE/usr/share/$APPNAME/sql/datatest.sql | $SQL diff --git a/support/mailleur-settest-db.sh b/support/mailleur-settest-db.sh new file mode 100755 index 0000000..5169cb3 --- /dev/null +++ b/support/mailleur-settest-db.sh @@ -0,0 +1,61 @@ +#! /usr/bin/bash +#--------------------------------------------------------------- +#program to reset the database contents +#parameters ["doit"] "confdirectory +#--------------------------------------------------------------- +#start delay +APPLICATION=mailleur +DELAY=10 +DOIT=doit +#--------------------------------------------------------------- +OWNER=`stat -c '%U' $0` +USER=`id -nu` +if [ "$USER" != "$OWNER" ] ; then + echo "" + echo "-----------" + echo "ATTENTION! $0 MUST BE executed by $0 file owner, exiting" + echo "-----------" + exit 1 + fi +#--------------------------------------------------------------- +if [ $# -eq 0 -o $# -ge 1 -a "$1" != "$DOIT" ] ; then + echo "" + echo "-----------" + echo "ATTENTION!:" + echo "- You are requesting a FULL database PRERESET." + echo "" + echo "SOME database data will be GONE forever and replace by test value." + echo "Are you sure!" + echo "You have $DELAY seconds to cancel (CTRL-C)" + echo "-----------" + sleep $DELAY + fi +if [ -n "$1" -a "$1" == "$DOIT" ] ; then + shift; + fi +CONF=/etc/$APPLICATION/$APPLICATION.conf +if [ $# -gt 0 ] ; then + CONF=$1 + fi +if [ ! -f $CONF ] ; then + echo "configuration file $CONF is missing, exiting!" + exit 1 + fi +. $CONF +#--------------------------------------------------------------- +#destroying the database +case "$DB_TYPE" in + "POSTGRESQL" ) + SQL="psql -q $APPNAME" + ;; + "MYSQL" ) + SQL="mariadb -q $APPNAME" + ;; + * ) + echo $DB_TYPE is not expected!, check configuration file! + exit 1 + ;; + esac + +#RE loading database +cpp -P -D$DB_TYPE $ROOTBASE/usr/share/$APPNAME/sql/datatest.sql | $SQL diff --git a/support/starting.sh b/support/starting.sh new file mode 100755 index 0000000..4161303 --- /dev/null +++ b/support/starting.sh @@ -0,0 +1,243 @@ +#! /usr/bin/bash +#--------------------------------------------------------------- +#program to check everything is ready to start clement +#$1 is either "sysvinit", "systemd" or "osukiss +#=============================================================== +OS=$1 #set the OS Type +#Hard coded variables +export APPNAME=mailleur +#---------------------------------------------------------------------- +#display code +CURS_ZERO="\\033[0G" + +NORMAL="\\033[0;39m" # Standard console grey +SUCCESS="\\033[1;32m" # Success is green +WARNING="\\033[1;33m" # Warnings are yellow +FAILURE="\\033[1;31m" # Failures are red +INFO="\\033[1;36m" # Information is light cyan +BRACKET="\\033[1;34m" # Brackets are blue + +# Use a colored prefix +BMPREFIX="\t " +SUCCESS_PREFIX="${SUCCESS} * ${NORMAL}" +FAILURE_PREFIX="${FAILURE}*****${NORMAL}" +WARNING_PREFIX="${WARNING} *** ${NORMAL}" +SKIP_PREFIX="${INFO} S ${NORMAL}" + +SUCCESS_SUFFIX="${BRACKET}[${SUCCESS} OK ${BRACKET}]${NORMAL}" +FAILURE_SUFFIX="${BRACKET}[${FAILURE} FAIL ${BRACKET}]${NORMAL}" +WARNING_SUFFIX="${BRACKET}[${WARNING} WARN ${BRACKET}]${NORMAL}" +SKIP_SUFFIX="${BRACKET}[${INFO} SKIP ${BRACKET}]${NORMAL}" + +#=============================================================== +#restarting a daemon +#---------------------------------------------------------------------- +#$1 daemon application name +sh_restart() + +{ +case "$OS" in + "osukiss" ) + service $1 restart + ;; + "sysvinit" ) + service $1 restart + ;; + "systemd" ) + systemctl restart $1 + ;; + * ) + echo "sh_restart: Unexpected OS=$OS, exiting!" + exit 1 + ;; + esac +} +#---------------------------------------------------------------------- +#reporting a big trouble +#---------------------------------------------------------------------- +sh_failure() + +{ +case "$OS" in + "osukiss" ) + /usr/bin/echo -n -e "${BMPREFIX}${@}" + /usr/bin/echo -e "${CURS_ZERO}${FAILURE_SUFFIX}" + ;; + "sysvinit" ) + /usr/bin/echo -n -e "${BMPREFIX}${@}" + /usr/bin/echo -e "${CURS_ZERO}${FAILURE_SUFFIX}" + ;; + "systemd" ) + echo -n $1 ; failure; + ;; + * ) + echo "sh_failure: Unexpected OS=$OS, exiting!" + exit 1 + ;; + esac +} +#---------------------------------------------------------------------- +#reporting a small problem +sh_warning() + +{ +case "$OS" in + "osukiss" ) + /usr/bin/echo -n -e "${BMPREFIX}${@}" + /usr/bin/echo -e "${CURS_ZERO}${WARNING_SUFFIX}" + ;; + "sysvinit" ) + /usr/bin/echo -n -e "${BMPREFIX}${@}" + /usr/bin/echo -e "${CURS_ZERO}${WARNING_SUFFIX}" + ;; + "systemd" ) + echo -n $2 ; warning; + ;; + * ) + echo "sh_warning: Unexpected OS=$OS, exiting!" + exit 1 + ;; + esac +} +#---------------------------------------------------------------------- +#reporting a success +sh_success() + +{ +case "$OS" in + "osukiss" ) + /usr/bin/echo -n -e "${BMPREFIX}${@}" + /usr/bin/echo -e "${CURS_ZERO}${SUCCESS_SUFFIX}" + ;; + "sysvinit" ) + /usr/bin/echo -n -e "${BMPREFIX}${@}" + /usr/bin/echo -e "${CURS_ZERO}${SUCCESS_SUFFIX}" + ;; + "systemd" ) + echo -n $1 ; success; + ;; + * ) + echo "sh_warning: Unexpected OS=$OS, exiting!" + exit 1 + ;; + esac +} +#---------------------------------------------------------------------- +#adding dovecot configuration +#---------------------------------------------------------------------- +do_doveconf() + +{ +service dovecot restart +} + +#---------------------------------------------------------------------- +#adding httpd configuration +#---------------------------------------------------------------------- +do_webconf() + +{ +/usr/lib/$APPNAME/support/do_httpd.sh +if [ $? = 0 ] ; then + sh_success $"Preparing $APPNAME httpd configuration" +else + sh_failure $"Preparing $APPNAME httpd configuration" +fi +} +#---------------------------------------------------------------------- +#procedure to check if the config is properly done +#---------------------------------------------------------------------- +chk_config() + +{ +if [ -z "$DB_TYPE" -o "$DB_TYPE" = "DB_TO_BE_DEFINED" ] ; then + echo -n "Checking file /etc/$APPNAME/$APPNAME.conf" + sh_failure $1 $" ->> not configured" + echo -e "\tPlease set DB_TYPE within /etc/$APPNAME/$APPNAME.conf" + echo -e "\tAborting start, Exiting at once" + exit -1; + fi +} +#---------------------------------------------------------------------- +#building application data-base +#---------------------------------------------------------------------- +do_mkdb() + +{ +case "$DB_TYPE" in + "MYSQL" | \ + "POSTGRESQL" ) + /usr/lib/$APPNAME/support/do_database.sh "/tmp" + if [ $? != 0 ] ; then + exit -1 + fi + ;; + "TO_BE_DEFINED" ) + echo "You must install $APPNAME with a DB flavor (ex: $APPNAME-postgresql" + echo "Exiting now" + exit -2; + ;; + "*" ) + echo "Unexpectd DB_TYPE variable within /etc/sysconfig/$APPNAME, please check" + echo "Exiting now" + exit -3; + ;; + esac +#extracting local configuration value +} +#---------------------------------------------------------------------- +#creating mailleur local certificat +#---------------------------------------------------------------------- +do_mkcert() + +{ +mkdir -p /etc/pki/$APPNAME +if [ ! -f /etc/pki/$APPNAME/$APPNAME-cert.pem ] ; then + /usr/lib/$APPNAME/support/dummy-cert.sh /etc/pki/$APPNAME/$APPNAME + chown $APPNAME:mail \ + /etc/pki/$APPNAME/$APPNAME-cert.pem \ + /etc/pki/$APPNAME/$APPNAME-key.pem + sh_success $"Preparing $APPNAME server self-signed certificate" + fi +} +#---------------------------------------------------------------------- +#setting local mailleur configuration +#---------------------------------------------------------------------- +do_mkconf() + +{ +if [ ! -f /etc/$APPNAME/config.done ] ; then + do_mkcert; + /usr/lib/$APPNAME/support/addconfig.sh + do_mkdb ; + do_doveconf ; + do_webconf ; + case "$OS" in + osukiss ) + ;; + sysvinit ) + ;; + systemd ) + ;; + * ) + echo "sh_mkconf: Unexpected OS=$OS, exiting!" + exit -1 + ;; + esac + date > /etc/$APPNAME/config.done +fi +} +#=============================================================== +#main script +#---------------------------------------------------------------------- +#loading all applications variables +[ -f /etc/$APPNAME/$APPNAME.conf ] && . /etc/$APPNAME/$APPNAME.conf +#overiding some variable by local setting +[ -f /etc/sysconfig/$APPNAME ] && . /etc/sysconfig/$APPNAME + +export DOMAINNAME=`dnsdomainname`; +export RPASS=`grep root /etc/shadow | cut -d':' -f2 |sed -e 's:\\\\$:\\\\\\\\$:g'`; +chk_config $1; +do_mkconf $1; +exit 0; +#--------------------------------------------------------------- diff --git a/sysconfig/mailleur b/sysconfig/mailleur new file mode 100644 index 0000000..fc85325 --- /dev/null +++ b/sysconfig/mailleur @@ -0,0 +1,8 @@ +#------------------------------------------- +#options available to debug mailleur +#OPTIONS="-d9" +#this is to debug a specific function within a specific procedure name +#Avaliable procedure name are defined within mailleur sources (#define OPEP) +#OPTIONS="-d9 -Dlvleml.c:checkto,modrec.c:docontact" +#------------------------------------------- + diff --git a/test_area/etc/mailleur/blacklister.conf b/test_area/etc/mailleur/blacklister.conf new file mode 100644 index 0000000..ff146c4 --- /dev/null +++ b/test_area/etc/mailleur/blacklister.conf @@ -0,0 +1,26 @@ +#dnsbl.sorbs.net +#t1.dnsbl.net.au +#checked 2025-07-12 by preference order +#The SpamCop Blocking List (SCBL) lists IP addresses which +#have transmitted reported email to SpamCop users. SpamCop +-1 bl.spamcop.net 127.0.0.2 +#Spamhaus Block List (SBL) is a realtime database of IP addresses +#of spam sources, including known spammers, spam gangs, +#spam operations and spam support services. +-1 sbl.spamhaus.org 127.0.0.2,127.0.0.3,127.0.0.9 +#b.barracudacentral.org will return the standard +#127.0.0.2 IP address when queried if the SMTP server is listed. +-6 b.barracudacentral.org 127.0.0.2 +#www.blocklist.de is a free and voluntary service provided +#by a Fraud/Abuse-specialist, +-1 bl.blocklist.de 127.0.0.9,127.0.0.13 +# ips.backscatterer.org for scoring or rejecting misdirected +#bounces and misdirected autoresponders +-1 ips.backscatterer.org 127.0.0.2 +#DroneBL is a realtime monitor of abusable IPs +#-1 dnsbl.dronebl.org +#The s5h blacklist is a real-time IP-based blacklist that is +#maintained by the System 5 Hosting (S5H) organization. +#-1 all.s5h.net 127.0.0.2 +#Junk Email Filter is a front end email spam filtering +-1 hostkarma.junkemailfilter.co 127.0.0.2 diff --git a/test_area/etc/mailleur/mailleur.conf b/test_area/etc/mailleur/mailleur.conf new file mode 100644 index 0000000..3fb243b --- /dev/null +++ b/test_area/etc/mailleur/mailleur.conf @@ -0,0 +1,80 @@ +#file used to set environment configuration +#------------------------------------------------ +#Defining application name +APPNAME=mailleur +#root working directoy definition for the whole application +ROOTBASE="/" +#defining local default domain +DFLTDOMAIN="localdomain" +#defining the local REALM +#Caution! the realm is hardcoded within data-base +#and USED too to hash the user passwd +#Changing this value coule be a trouble make +#(entering again ALL user password) +REALM="mailleur-email" +#------------------------------------------------ +#list of listening port to do SMTP protocole +#format +#protocol|ipnum|port|iteration[,protocol|ipnum|port|iteration]++ +#example +#stmtps|ipnum|465|5 -> protocol smtps|IP number|port 465|5 iterations +#|ipnum||| -> smtp|ipnum|25|2 +#||,smtps||465|2 -> smtp|0.0.0.0|25|2 + smtps||465|2 +#|| -> smtp|0.0.0.0|25|2 +#Examples for test purpose +#SMTPPORTS="|127.127.10.25|1025|,smtps|127.127.10.25|1465|1" +#SMTPPORTS="|127.127.10.25|1025|" +#SMTPPORTS="smtps|127.127.10.25|1465|1" +#Defaults (production) +SMTPPORTS="|||5,smtps||465|3,smtp||587|2" +#------------------------------------------------ +#SSL Security level default value +#CIPHER_LIST="DEFAULT" +#SSL_SECURITY=2 +#------------------------------------------------ +#Defining SERVER mode Certificate data +CA_ROOT_SRV="/etc/pki/tls/make-ca/ca-bundle.crt" +CA_VERIFY_SRV=0 #to check PEER/client remote certificate +#If certificate set via do_dns_tlsa.sh (letsencrypt) +#CA_CERT_SRV="/etc/certbot/mailleur/mailleur-fullchain.pem" +#CA_KEY_SRV="/etc/certbot/mailleur/mailleur-key.pem" +#If certificate are self signed (default installation) +#CA_CERT_SRV="/etc/pki/mailleur/mailleur-cert.pem" +#CA_KEY_SRV="/etc/pki/mailleur/mailleur-key.pem" +#Symbolic link set at installation +CA_CERT_SRV="/etc/pki/mailleur/mailleur-cert.pem" +CA_KEY_SRV="/etc/pki/mailleur/mailleur-key.pem" +#------------------------------------------------ +#Defining CLIENT mode Certificate data +CA_ROOT_CLT="/etc/pki/tls/make-ca/ca-bundle.crt" +CA_VERIFY_CLT=0 #to check PEER/server remote certificate +#If certificate set via do_dns_tlsa.sh (letsencrypt) +#CA_CERT_CLT="/etc/certbot/mailleur/mailleur-fullchain.pem" +#CA_KEY_CLT="/etc/certbot/mailleur/mailleur-key.pem" +#If certificate are self signed (default installation) +#CA_CERT_CLT="/etc/pki/mailleur/mailleur-cert.pem" +#CA_KEY_CLT="/etc/pki/mailleur/mailleur-key.pem" +#Symbolic link set at installation +CA_CERT_CLT="/etc/mailleur/pki/mailleur-cert.pem" +CA_KEY_CLT="/etc/mailleur/pki/mailleur-key.pem" +#------------------------------------------------ +#Configured for Postgresql database +#DB_TYPE can be either POSTGRESQL,MYSQL, default POSTGRESQL +DB_TYPE=TO_BE_DEFINED +DB_NAME=mailleur +DB_HOST=localhost +DB_PORT=TO_BE_DEFINED +DB_LANG="UTF-8" +#------------------------------------------------ +#Dovecot storage directory +DOV_MAILDIR="/var/spool/mailleur/mails" +#------------------------------------------------ +#The list of public blacklist serveur +BLACKLISTER=/etc/mailleur/blacklister.conf +#the list of IP from which we accept to relay email +RELAYABLE=/etc/mailleur/relayed.conf +#------------------------------------------------ +#Minimal credit level to which remote is rejected at once +#if credit is equal or below that level +RJCTCRED=-50 +#------------------------------------------------ diff --git a/test_area/etc/mailleur/mailleur.conf.dvl b/test_area/etc/mailleur/mailleur.conf.dvl new file mode 100644 index 0000000..0389242 --- /dev/null +++ b/test_area/etc/mailleur/mailleur.conf.dvl @@ -0,0 +1,66 @@ +#file used to set environment configuration +#Used for developpement purpose ONLY +#------------------------------------------------ +#Defining application name +APPNAME=mailleur +#root working directoy definition for the whole application +ROOTBASE="/home/jmp/safe-mailleur/mailleur/test_area/" +#defining local default domain +DFLTDOMAIN="example.com" +#defining the local REALM +#Caution! the realm is hardcoded within data-base +#and USED too to hash the user passwd +#Changing this value coule be a trouble make +#(entering again ALL user password) +REALM="mailleur-email" +#------------------------------------------------ +#list of listening port to do SMTP protocole +#format +#protocol|ipnum|port|iteration[,protocol|ipnum|port|iteration]++ +#example +#stmtps|ipnum|465|5 -> protocol smtps|IP number|port 465|5 iterations +#|ipnum||| -> smtp|ipnum|25|2 +#||,smtps||465|2 -> smtp|0.0.0.0|25|2 + smtps||465|2 +#|| -> smtp|0.0.0.0|25|2 +#SMTPPORTS="||1025" +#SMTPPORTS="|127.127.10.25|1025|,smtps|127.127.10.25|1026|1" +#SMTPPORTS="|127.127.10.25|1025|" +#SMTPPORTS="smtps|127.127.10.25|1065|1" +#------------------------------------------------ +#SSL Security level +#CIPHER_LIST="ECDHE-ECDSA-AES256-GCM-SHA384" +#SSL_SECURITY=3 +#------------------------------------------------ +#Defining SERVER mode Certificate data +CA_ROOT_SRV="/etc/pki/tls/make-ca/ca-bundle.crt" +CA_CERT_SRV="./certs/mailleur_server-chain-cert_x509.pem" +CA_KEY_SRV="./certs/mailleur_server-key.pem" +CA_VERIFY_SRV=0 #to check PEER/client remote certificate +#------------------------------------------------ +#Defining CLIENT mode Certificate data +CA_ROOT_CLT="/etc/pki/tls/make-ca/ca-bundle.crt" +CA_CERT_CLT="./certs/localhost-chain-cert.pem" +CA_KEY_CLT="./certs/localhost-key.pem" +CA_VERIFY_CLT=0 #to check PEER/server remote certificate +#------------------------------------------------ +#Configured for Postgresql database +#DB_TYPE can be either POSTGRESQL,MYSQL, default POSTGRESQL +#DB_NAME=mailleur +#DB_HOST=localhost +#DB_LANG="UTF-8" +#DB_TYPE=POSTGRESQL +#DB_PORT=5432 +#DB_TYPE=MYSQL +#DB_PORT=3306 + +#------------------------------------------------ +#Dovecot storage directory +DOV_MAILDIR="/var/spool/mailleur/mails" +#------------------------------------------------ +SMTPPORTS="|127.127.10.25|1025|5,smtps|127.127.10.26|1465|3,smtp|127.127.10.26|1587|2" +#------------------------------------------------ +#The list of public blacklist serveur +BLACKLISTER=/etc/mailleur/blacklister.conf +#the list of IP from which we accept to relay email +RELAYABLE=/etc/mailleur/relayed.conf.dvl +#------------------------------------------------ diff --git a/test_area/etc/mailleur/relayed.conf b/test_area/etc/mailleur/relayed.conf new file mode 100644 index 0000000..114af58 --- /dev/null +++ b/test_area/etc/mailleur/relayed.conf @@ -0,0 +1,5 @@ +#-------------------------------------------------------- +##Private address block which email can be relayed from +127.0.0.0/8 #local loop number +#-------------------------------------------------------- +#Setup you own list diff --git a/test_area/etc/mailleur/relayed.conf.dvl b/test_area/etc/mailleur/relayed.conf.dvl new file mode 100644 index 0000000..5c217dc --- /dev/null +++ b/test_area/etc/mailleur/relayed.conf.dvl @@ -0,0 +1,6 @@ +#-------------------------------------------------------- +##Private address block which email can be relayed from +127.0.0.0/8 #local loop number +192.168.254.0/24 #local network +#-------------------------------------------------------- +#Setup you own list diff --git a/test_area/usr/share/mailleur/sql/.gitignore b/test_area/usr/share/mailleur/sql/.gitignore new file mode 100644 index 0000000..79d5f73 --- /dev/null +++ b/test_area/usr/share/mailleur/sql/.gitignore @@ -0,0 +1 @@ +popul.sql diff --git a/test_area/usr/share/mailleur/sql/Makefile b/test_area/usr/share/mailleur/sql/Makefile new file mode 100644 index 0000000..86d3b8f --- /dev/null +++ b/test_area/usr/share/mailleur/sql/Makefile @@ -0,0 +1,100 @@ +#-------------------------------------------------------------------- +#Generate database for postgresql and mysql +#-------------------------------------------------------------------- +prod \ +debug \ + : mailleur.postg mailleur.mysql + +allclean \ +clean : + @ rm -fr mailleur.mysql mailleur.postg + +#-------------------------------------------------------------------- + +prepdb : newpop debug deltest newtest + +mailleur.postg \ + : mailleur.sql + @ cpp -P -DPOSTGRESQL \ + mailleur.sql > mailleur.postg + +mailleur.mysql \ + : mailleur.sql + @ cpp -P -DMYSQL \ + mailleur.sql > mailleur.mysql + +dbmysql : mailleur.mysql + @ - ( \ + echo "CREATE USER `id -un`@localhost;"; \ + echo "CREATE USER apache@localhost;"; \ + echo "CREATE USER dovecot@localhost;"; \ + echo "GRANT ALL ON mailleur.* \ + TO `id -un`@localhost \ + WITH GRANT OPTION;"; \ + echo "FLUSH PRIVILEGES;"; \ + echo "CREATE DATABASE mailleur;"; \ + echo "ALTER DATABASE mailleur \ + CHARACTER SET utf8;"; \ + ) | sudo mariadb -q + @ cat mailleur.mysql | mariadb -q mailleur; + @ cpp -P -DMYSQL \ + datatest.sql | mariadb -q mailleur; + cpp -P -traditional -DMYSQL \ + popul.sql | mariadb -q mailleur; + @ echo "MYSQL database ready" + + +ndbmysql: + @-( \ + echo "DROP DATABASE mailleur;"; \ + echo "DROP USER dovecot@localhost;"; \ + echo "DROP USER apache@localhost;"; \ + echo "DROP USER `id -un`@localhost;"; \ + ) | sudo mariadb + +dbpostg : mailleur.postg + @ -( \ + echo "CREATE ROLE apache WITH LOGIN;"; \ + echo "CREATE ROLE dovecot WITH LOGIN;"; \ + echo "CREATE EXTENSION pgcrypto;"; \ + echo "CREATE DATABASE mailleur "; \ + echo " ENCODING='UTF8';"; \ + ) | psql -q -U postgres template1 + @ cat mailleur.postg | psql -q mailleur; + @ cpp -DPOSTGRESQL \ + -P \ + -traditional \ + datatest.sql | \ + sed -e"/^\/\//d" | \ + psql -q mailleur; + @ cpp -DPOSTGRESQL \ + -P \ + -traditional \ + popul.sql | \ + sed -e"/^\/\//d" | \ + psql -q mailleur; + @ echo "POSGRESQL database ready" + +ndbpostg: + @-( \ + echo "drop database mailleur;"; \ + echo "DROP ROLE apache;"; \ + echo "DROP ROLE dovecot;"; \ + echo "DROP EXTENSION pgcrypto;"; \ + ) | psql -q -U postgres template1 + +#-------------------------------------------------------------------- +#procedure to delete or create a postgresql and mysql test database + +newtest : dbpostg dbmysql + +deltest : ndbpostg ndbmysql + +newpop : + @ ../tools/genpsdusr.sh 2000 > popul.sql + @ echo "New 'popul' database created" + +#-------------------------------------------------------------------- +#-------------------------------------------------------------------- +.PHONY: deltest +#-------------------------------------------------------------------- diff --git a/test_area/usr/share/mailleur/sql/datatest.def b/test_area/usr/share/mailleur/sql/datatest.def new file mode 100644 index 0000000..c09079f --- /dev/null +++ b/test_area/usr/share/mailleur/sql/datatest.def @@ -0,0 +1,16 @@ + +//X------------------------------------------------------------------ +//include file to ajuste result according database +//Y------------------------------------------------------------------ +#ifdef POSTGRESQL +#define ADDTIME(adding) 'adding' +#define CONCAT(A,B) A||B +#define INET_ATON(A) A +#define ENCRYPT(A,B) encrypt(A,B,'aes') +#endif +#ifdef MYSQL +#define ADDTIME(adding) INTERVAL adding +#define CONCAT(A,B) concat(A,B) +#define INET_ATON(A) inet_aton(A) +#define ENCRYPT(A,B) encrypt(A,B) +#endif diff --git a/test_area/usr/share/mailleur/sql/datatest.sql b/test_area/usr/share/mailleur/sql/datatest.sql new file mode 100644 index 0000000..1f72759 --- /dev/null +++ b/test_area/usr/share/mailleur/sql/datatest.sql @@ -0,0 +1,81 @@ + +#include "datatest.def" + +//First remove ALL Email data +DELETE FROM emails; +//password is generated via command line: +//openssl password +//present password is crypted as a hash and in password too +//adding a list of local email + +//============================================================== +//set for local test +INSERT INTO emails (email,password,lang) \ + values ('jmp@example.com','4cabri','FRA'); +INSERT INTO emails (email,password) \ + values ('root@example.com','4cabri'); +INSERT INTO emails (email,password) \ + values ('postmaster@example.com','postmaster'); +INSERT INTO emails (email,password) \ + values ('webmaster@example.com','webmaster'); +INSERT INTO emails (email,password) \ + values ('utf8-áö_üñ@example.com','utf8-áö_üñ'); +INSERT INTO emails (email,password) \ + values ('user1@mailleur.example.com','user1'); + +//Set for system with Postgresql database +INSERT INTO emails (email,password) \ + values ('user1@posdb.example.com','user1'); +INSERT INTO emails (email,password) \ + values ('user2@posdb.example.com','user2'); + +//Set for system with MySQL database +INSERT INTO emails (email,password) \ + values ('user1@mardb.example.com','user1'); +INSERT INTO emails (email,password) \ + values ('user2@mardb.example.com','user2'); + +//============================================================== +//List of remote IP status +//good credit IP +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('127.127.0.25',10,now()); +//--------------------------------------------------------------- +//low credit IP +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('27.151.45.98',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('45.197.14.139',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('213.209.157.107',-5,now()+ADDTIME(200 day)); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('213.209.157.108',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('122.175.193.134',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('176.53.146.143',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('209.85.218.68',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('216.246.113.145',-5,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('193.111.208.122',-5,now()); + +//============================================================== +//selected IP from from 'clean' server +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('192.219.254.189',100,now()); +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('216.252.69.41',100,now()); + +//selected IP with with very low credit +INSERT INTO remotes (remoteip,credit,lastscan) \ + values ('127.127.127.127',-50,now()); + +//============================================================== +//defining admin user +INSERT INTO admins (email) \ + values ('root@example.com'); +INSERT INTO admins (email) \ + values ('jmp@example.com'); +//============================================================== diff --git a/test_area/usr/share/mailleur/sql/mailleur.mysql b/test_area/usr/share/mailleur/sql/mailleur.mysql new file mode 100644 index 0000000..4fca369 --- /dev/null +++ b/test_area/usr/share/mailleur/sql/mailleur.mysql @@ -0,0 +1,121 @@ +CREATE TABLE emails ( + email VARCHAR(100) UNIQUE NOT NULL, + creation TIMESTAMP NULL + DEFAULT NOW(), + lastemail TIMESTAMP NULL + DEFAULT NOW(), + lastscan TIMESTAMP NULL + DEFAULT NOW(), + password TEXT + DEFAULT '!', + hash TEXT, + lang TEXT + DEFAULT 'ENG', + space INTEGER + DEFAULT 0, + mxspace INTEGER + DEFAULT 20000, + locked INTEGER + DEFAULT 0 + ); +GRANT SELECT,INSERT,UPDATE,DELETE ON emails TO 'apache'@'localhost'; +GRANT SELECT ON emails TO 'dovecot'@'localhost'; +CREATE TABLE sessions ( + creation TIMESTAMP NULL + DEFAULT NOW(), + sessid VARCHAR(100) UNIQUE NOT NULL, + sesstitle TEXT, + sessfrom TEXT, + emailfrom TEXT, + taille INTEGER + DEFAULT 0, + duration TEXT + DEFAULT NULL + ); +GRANT SELECT ON sessions TO 'apache'@'localhost'; +CREATE TABLE actions ( + creation TIMESTAMP NULL + DEFAULT NOW(), + code VARCHAR(30), + sessid TEXT, + remoteip TEXT + DEFAULT NULL, + reverse TEXT + DEFAULT 'Unknown IP', + smtpfrom TEXT, + rcptto TEXT, + emailfrom TEXT, + subject TEXT, + status INTEGER, + numline INTEGER, + info TEXT + ); +GRANT SELECT ON sessions TO 'apache'@'localhost'; +CREATE TABLE remotes ( + remoteip VARCHAR(100) UNIQUE NOT NULL, + lastscan TIMESTAMP NULL + DEFAULT '1970-01-01', + lastupdate TIMESTAMP NULL + DEFAULT NOW(), + credit INTEGER + DEFAULT 5, + reverse TEXT + DEFAULT NULL, + listing TEXT + DEFAULT NULL, + links INTEGER + DEFAULT 1 + ); +CREATE INDEX remotes_ndx ON remotes(lastscan,lastupdate); +INSERT INTO remotes (remoteip,reverse,credit,lastscan) values ('127.0.0.1','localhost.localldomain',99,now()); +CREATE TABLE events ( + creation TIMESTAMP NULL + DEFAULT NOW(), + serial INTEGER AUTO_INCREMENT UNIQUE PRIMARY KEY, + sessid VARCHAR(100) UNIQUE NOT NULL, + start INTEGER, + stop INTEGER + ); +CREATE INDEX event_id_ndx ON events(sessid); +CREATE INDEX event_date_ndx ON events(creation); +CREATE TABLE aliases ( + email TEXT, + alias TEXT + ); +CREATE INDEX aliases_id_ndx ON aliases(email); +CREATE TABLE cookies ( + cookuuid VARCHAR(100) UNIQUE NOT NULL, + email TEXT, + expire TIMESTAMP NULL + ); +CREATE TABLE admins ( + email TEXT + ); +DELIMITER $$ +CREATE TRIGGER sethash + BEFORE UPDATE ON emails FOR EACH ROW + BEGIN + IF NEW.password IS NULL OR + LENGTH(TRIM(NEW.password))=0 OR + LEFT(NEW.password,1) = '$' THEN + set NEW.hash=NULL; + set NEW.password=NEW.password; + else + set NEW.hash=MD5(concat(NEW.email,':','mailleur-email',':',NEW.password)); + set NEW.password=encrypt(NEW.password,concat('$1$',md5(rand()))); + END IF; + END$$ +CREATE TRIGGER updhash + BEFORE INSERT ON emails FOR EACH ROW + BEGIN + IF NEW.password IS NULL OR + LENGTH(TRIM(NEW.password))=0 OR + LEFT(NEW.password,1) = '$' THEN + set NEW.hash=NULL; + set NEW.password=NEW.password; + else + set NEW.hash=MD5(concat(NEW.email,':','mailleur-email',':',NEW.password)); + set NEW.password=encrypt(NEW.password,concat('$1$',md5(rand()))); + END IF; + END$$ +DELIMITER ; diff --git a/test_area/usr/share/mailleur/sql/mailleur.postg b/test_area/usr/share/mailleur/sql/mailleur.postg new file mode 100644 index 0000000..922e501 --- /dev/null +++ b/test_area/usr/share/mailleur/sql/mailleur.postg @@ -0,0 +1,111 @@ +CREATE TABLE emails ( + email TEXT UNIQUE NOT NULL, + creation TIMESTAMP(0) WITH TIME ZONE + DEFAULT NOW(), + lastemail TIMESTAMP(0) WITH TIME ZONE + DEFAULT NOW(), + lastscan TIMESTAMP(0) WITH TIME ZONE + DEFAULT NOW(), + password TEXT + DEFAULT '!', + hash TEXT, + lang TEXT + DEFAULT 'ENG', + space INTEGER + DEFAULT 0, + mxspace INTEGER + DEFAULT 20000, + locked INTEGER + DEFAULT 0 + ); +GRANT SELECT,INSERT,UPDATE,DELETE ON emails TO apache; +GRANT SELECT ON emails TO dovecot; +CREATE TABLE sessions ( + creation TIMESTAMP(0) WITH TIME ZONE + DEFAULT NOW(), + sessid TEXT UNIQUE NOT NULL, + sesstitle TEXT, + sessfrom TEXT, + emailfrom TEXT, + taille INTEGER + DEFAULT 0, + duration TEXT + DEFAULT NULL + ); +GRANT SELECT ON sessions TO apache; +CREATE TABLE actions ( + creation TIMESTAMP(0) WITH TIME ZONE + DEFAULT NOW(), + code TEXT, + sessid TEXT, + remoteip TEXT + DEFAULT NULL, + reverse TEXT + DEFAULT 'Unknown IP', + smtpfrom TEXT, + rcptto TEXT, + emailfrom TEXT, + subject TEXT, + status INTEGER, + numline INTEGER, + info TEXT + ); +GRANT SELECT ON sessions TO apache; +CREATE TABLE remotes ( + remoteip TEXT UNIQUE NOT NULL, + lastscan TIMESTAMP(0) WITH TIME ZONE + DEFAULT '1970-01-01', + lastupdate TIMESTAMP(0) WITH TIME ZONE + DEFAULT NOW(), + credit INTEGER + DEFAULT 5, + reverse TEXT + DEFAULT NULL, + listing TEXT + DEFAULT NULL, + links INTEGER + DEFAULT 1 + ); +CREATE INDEX remotes_ndx ON remotes(lastscan,lastupdate); +INSERT INTO remotes (remoteip,reverse,credit,lastscan) values ('127.0.0.1','localhost.localldomain',99,now()); +CREATE TABLE events ( + creation TIMESTAMP(0) WITH TIME ZONE + DEFAULT NOW(), + serial SERIAL UNIQUE, + sessid TEXT UNIQUE NOT NULL, + start INTEGER, + stop INTEGER + ); +CREATE INDEX event_id_ndx ON events(sessid); +CREATE INDEX event_date_ndx ON events(creation); +CREATE TABLE aliases ( + email TEXT, + alias TEXT + ); +CREATE INDEX aliases_id_ndx ON aliases(email); +CREATE TABLE cookies ( + cookuuid TEXT UNIQUE NOT NULL, + email TEXT, + expire TIMESTAMP(0) WITH TIME ZONE + ); +CREATE TABLE admins ( + email TEXT + ); +CREATE FUNCTION updpass() + RETURNS trigger AS $$ + BEGIN + IF NEW.password IS NULL OR + length(trim(NEW.password)) = 0 OR + substring(NEW.password,1,1) = '$' THEN + NEW.hash=NULL; + NEW.password=NEW.password; + ELSE + NEW.hash = md5(concat(NEW.email,':','mailleur-email',':',NEW.password)); + NEW.password = crypt (NEW.password,gen_salt('md5')); + END IF; + RETURN NEW; + END; + $$ LANGUAGE 'plpgsql'; +CREATE TRIGGER keephash + BEFORE INSERT OR UPDATE on emails + FOR EACH ROW EXECUTE PROCEDURE updpass(); diff --git a/test_area/usr/share/mailleur/sql/mailleur.sql b/test_area/usr/share/mailleur/sql/mailleur.sql new file mode 100644 index 0000000..bd7faed --- /dev/null +++ b/test_area/usr/share/mailleur/sql/mailleur.sql @@ -0,0 +1,232 @@ +/********************************************************/ +/* */ +/* This file define the mailleur data base */ +/* structure */ +/* */ +/********************************************************/ +/*Specific PostgreSQL data base definitions */ +#ifdef POSTGRESQL +#define AUTOSERIAL SERIAL UNIQUE +#define DURATION TIMESPAN +#define DBTIMESTAMP TIMESTAMP(0) WITH TIME ZONE +#define DBNAN 'NaN' +#define DFLT DEFAULT +#define SHORTTEXT TEXT +#define TEXTUNIQUE TEXT UNIQUE NOT NULL +#define INS(name) name /*index size */ +#define ESCLIT E +#define mailapache apache +#define maildove dovecot +#define CASESENSITIVE +#define ADDTIME(adding) 'adding' +#define INET inet +#define CRYPTED bytea +#endif + +/*Specific MySQL type data base definitions */ +#if defined(MYSQL) || defined(MYSQLI) +#define AUTOSERIAL INTEGER AUTO_INCREMENT UNIQUE PRIMARY KEY +#define DURATION INT8 +#define DBTIMESTAMP TIMESTAMP NULL +#define DBNAN NULL +#define DFLT DEFAULT +#define SHORTTEXT VARCHAR(30) +#define TEXTUNIQUE VARCHAR(100) UNIQUE NOT NULL +#define INS(name) name(80) /*index size */ +#define ESCLIT +#define mailapache 'apache'@'localhost' +#define maildove 'dovecot'@'localhost' +#define CASESENSITIVE CHARACTER SET latin1 COLLATE latin1_bin +#define ADDTIME(adding) INTERVAL adding +#define INET VARBINARY(16) +#define CRYPTED MEDIUMBLOB +#endif + +/********************************************************/ +/********************************************************/ +/* */ +/* User available email definition table */ +/* */ +/********************************************************/ +//table to define LOCAL USER +CREATE TABLE emails ( + email TEXTUNIQUE, //User email + creation DBTIMESTAMP //record creation + DFLT NOW(), + lastemail DBTIMESTAMP //last email received + DFLT NOW(), + lastscan DBTIMESTAMP //last scaning date + DFLT NOW(), + password TEXT //user (encrypted) password + DFLT '!', + hash TEXT, //'email:realm:password' MD5 + lang TEXT //user prefered language + DFLT 'ENG', //English by default + space INTEGER //space used by user email + DFLT 0, + mxspace INTEGER //Maximun space available + DFLT 20000, //to user (20 Gig). + locked INTEGER //The account is locked out + DFLT 0 + ); +GRANT SELECT,INSERT,UPDATE,DELETE ON emails TO mailapache; +GRANT SELECT ON emails TO maildove; + + +//table about session +CREATE TABLE sessions ( + creation DBTIMESTAMP //record creation + DFLT NOW(), + sessid TEXTUNIQUE, //Session id + sesstitle TEXT, //The session email title + sessfrom TEXT, //The session from + emailfrom TEXT, //The from within the email itself + taille INTEGER //The email size + DFLT 0, + duration TEXT //email transfer duration + DFLT NULL + ); +GRANT SELECT ON sessions TO mailapache; + +//table about recipient email information +//summerize all emails received actions status according sessions and recipient +CREATE TABLE actions ( + creation DBTIMESTAMP //record creation + DFLT NOW(), + code SHORTTEXT, //action status (one char) + sessid TEXT, //Session id + remoteip TEXT //Remote serveur IP number + DFLT NULL, + reverse TEXT //remote server reverse address name + DFLT 'Unknown IP', + smtpfrom TEXT, //SMTP Connection "MAIL FROM:" + rcptto TEXT, //SMTP Connection "RCPT TO:" + emailfrom TEXT, //email contents "From:" + subject TEXT, //email contents "Subject:" + status INTEGER, //info status + numline INTEGER, //status line + info TEXT //line info + ); +GRANT SELECT ON sessions TO mailapache; + +//defining table about remote server +CREATE TABLE remotes ( + remoteip TEXTUNIQUE, //remote IP number + lastscan DBTIMESTAMP //record last update + DFLT '1970-01-01', + lastupdate DBTIMESTAMP //record creation + DFLT NOW(), + credit INTEGER //Remote IP current credit (-100..+100) + DFLT 5, + reverse TEXT //Remote official revers address + DFLT NULL, + listing TEXT //explaination about black listing + DFLT NULL, + links INTEGER + DFLT 1 //how many time the remote connected + ); +CREATE INDEX remotes_ndx ON remotes(lastscan,lastupdate); +//set a local IP +INSERT INTO remotes (remoteip,reverse,credit,lastscan) \ + values ('127.0.0.1','localhost.localldomain',99,now()); + +//defining table about eventlog reference +CREATE TABLE events ( + creation DBTIMESTAMP //record creation + DFLT NOW(), + serial AUTOSERIAL, //record unique number + sessid TEXTUNIQUE, //Session id + start INTEGER, //Event log starting point + stop INTEGER //Event log ending point + ); +CREATE INDEX event_id_ndx ON events(sessid); +CREATE INDEX event_date_ndx ON events(creation); + + +//defining table about email aliases +//list of aliases related to ONE email +CREATE TABLE aliases ( + email TEXT, //Email address + alias TEXT //One aliases + ); +CREATE INDEX aliases_id_ndx ON aliases(email); + +//List all currently opened cookies +CREATE TABLE cookies ( + cookuuid TEXTUNIQUE, //cookies unique id + email TEXT, //user email address + expire DBTIMESTAMP //cookies date limit + ); + +//List emails address with admin capablities +CREATE TABLE admins ( + email TEXT //user email address + ); + +//-------------------------------------------------------------- +//Defining TRIGGER fonctions according database type +//-------------------------------------------------------------- +//Caution this REALM value MUST be the same as defined +//in mailleur.conf +#define REALM 'mailleur-email' +#define HASHING concat(NEW.email,':',REALM,':',NEW.password) + + +#ifdef POSTGRESQL +CREATE FUNCTION updpass() + RETURNS trigger AS $$ + BEGIN + IF NEW.password IS NULL OR + length(trim(NEW.password)) = 0 OR + substring(NEW.password,1,1) = '$' THEN + NEW.hash=NULL; + NEW.password=NEW.password; + ELSE + NEW.hash = md5(HASHING); + NEW.password = crypt (NEW.password,gen_salt('md5')); + END IF; + RETURN NEW; + END; + $$ LANGUAGE 'plpgsql'; + +CREATE TRIGGER keephash + BEFORE INSERT OR UPDATE on emails + FOR EACH ROW EXECUTE PROCEDURE updpass(); +#endif + +#if defined(MYSQL) || defined(MYSQLI) + +DELIMITER $$ + +CREATE TRIGGER sethash + BEFORE UPDATE ON emails FOR EACH ROW + BEGIN + IF NEW.password IS NULL OR + LENGTH(TRIM(NEW.password))=0 OR + LEFT(NEW.password,1) = '$' THEN + set NEW.hash=NULL; + set NEW.password=NEW.password; + else + set NEW.hash=MD5(HASHING); + set NEW.password=encrypt(NEW.password,concat('$1$',md5(rand()))); + END IF; + END$$ + + +CREATE TRIGGER updhash + BEFORE INSERT ON emails FOR EACH ROW + BEGIN + IF NEW.password IS NULL OR + LENGTH(TRIM(NEW.password))=0 OR + LEFT(NEW.password,1) = '$' THEN + set NEW.hash=NULL; + set NEW.password=NEW.password; + else + set NEW.hash=MD5(HASHING); + set NEW.password=encrypt(NEW.password,concat('$1$',md5(rand()))); + END IF; + END$$ + +DELIMITER ; + +#endif diff --git a/test_area/usr/share/mailleur/sql/preset.sql b/test_area/usr/share/mailleur/sql/preset.sql new file mode 100644 index 0000000..7088111 --- /dev/null +++ b/test_area/usr/share/mailleur/sql/preset.sql @@ -0,0 +1,27 @@ + +/********************************************************/ +/* */ +/* This file define the mailleur data base */ +/* local preset value */ +/* */ +/********************************************************/ + +/********************************************************/ +/* */ +/* Creating the bare minimun user configuration */ +/* */ +/********************************************************/ +//root is the default preset admin +INSERT INTO admins (email) + VALUES (ROOTDOMAINNAME); + +//inserting the mail account +INSERT INTO emails (email,password) + VALUES (ROOTDOMAINNAME,RPASS); + +/********************************************************/ +/* */ +/* Preset value completed */ +/* */ +/********************************************************/ + diff --git a/test_area/var/run/mailleur/receiver.lock b/test_area/var/run/mailleur/receiver.lock new file mode 100644 index 0000000..50c88fb --- /dev/null +++ b/test_area/var/run/mailleur/receiver.lock @@ -0,0 +1 @@ +23289 diff --git a/test_area/var/run/mailleur/scanner.lock b/test_area/var/run/mailleur/scanner.lock new file mode 100644 index 0000000..8bba3a5 --- /dev/null +++ b/test_area/var/run/mailleur/scanner.lock @@ -0,0 +1 @@ +23299 diff --git a/test_area/var/run/mailleur/sender.lock b/test_area/var/run/mailleur/sender.lock new file mode 100644 index 0000000..a468ec4 --- /dev/null +++ b/test_area/var/run/mailleur/sender.lock @@ -0,0 +1 @@ +23303 diff --git a/test_area/var/run/mailleur/sorter.lock b/test_area/var/run/mailleur/sorter.lock new file mode 100644 index 0000000..a6d3a20 --- /dev/null +++ b/test_area/var/run/mailleur/sorter.lock @@ -0,0 +1 @@ +23285 diff --git a/test_area/var/spool/mailleur/mails/example.com/postmaster/dovecot/new/23292-20251210053923-0979-0000 b/test_area/var/spool/mailleur/mails/example.com/postmaster/dovecot/new/23292-20251210053923-0979-0000 new file mode 100644 index 0000000..a14f0b7 --- /dev/null +++ b/test_area/var/spool/mailleur/mails/example.com/postmaster/dovecot/new/23292-20251210053923-0979-0000 @@ -0,0 +1,20 @@ +Received: from localhost.localdomain (IP=[127.0.0.1], originator=) + by mailleur.example.com ([127.127.10.25:1025]/receiver-0.18.30-dvl) with ESMTP + id <23292-20251210053923-0979-0000@mailleur.example.com>; + Wed, 10 Dec 2025 05:39:24 -0500 +Subject: (feed000) Very Simple email contents +Date: Wed, 10 Dec 2025 05:39:24 -0500 +From: Maitre Post +To: Maitre WEB + +this email is for local test purpose only +with 2 known recipients beeing as: +postmaster and webmaster. + +Checking line with one '.' transmissioon +. +Previous line is one single dot + +you should have character '|' as last characeter +of this email (after End Of Text). +End Of Text| diff --git "a/test_area/var/spool/mailleur/mails/example.com/utf8-\303\241\303\266_\303\274\303\261/dovecot/new/23387-20251210053926-0983-0000" "b/test_area/var/spool/mailleur/mails/example.com/utf8-\303\241\303\266_\303\274\303\261/dovecot/new/23387-20251210053926-0983-0000" new file mode 100644 index 0000000..cfebc3b --- /dev/null +++ "b/test_area/var/spool/mailleur/mails/example.com/utf8-\303\241\303\266_\303\274\303\261/dovecot/new/23387-20251210053926-0983-0000" @@ -0,0 +1,15 @@ +Received: from localhost.localdomain (IP=[127.0.0.1], originator=) + by mailleur.example.com ([127.127.10.25:1025]/receiver-0.18.30-dvl) with ESMTP + id <23387-20251210053926-0983-0000@mailleur.example.com>; + Wed, 10 Dec 2025 05:39:27 -0500 +Subject: (feed004) Email using UTF-8 characters +Date: Wed, 10 Dec 2025 05:39:27 -0500 +From: Maitre Post +To: Maitre WEB + +this email is for local test purpose only +with 2 known recipients beeing as: +postmaster and webmaster. + +This line include accentued latin char +via the reciption email address <áöüñ@example.com> diff --git a/test_area/var/spool/mailleur/mails/example.com/webmaster/dovecot/new/23292-20251210053923-0979-0000 b/test_area/var/spool/mailleur/mails/example.com/webmaster/dovecot/new/23292-20251210053923-0979-0000 new file mode 100644 index 0000000..a14f0b7 --- /dev/null +++ b/test_area/var/spool/mailleur/mails/example.com/webmaster/dovecot/new/23292-20251210053923-0979-0000 @@ -0,0 +1,20 @@ +Received: from localhost.localdomain (IP=[127.0.0.1], originator=) + by mailleur.example.com ([127.127.10.25:1025]/receiver-0.18.30-dvl) with ESMTP + id <23292-20251210053923-0979-0000@mailleur.example.com>; + Wed, 10 Dec 2025 05:39:24 -0500 +Subject: (feed000) Very Simple email contents +Date: Wed, 10 Dec 2025 05:39:24 -0500 +From: Maitre Post +To: Maitre WEB + +this email is for local test purpose only +with 2 known recipients beeing as: +postmaster and webmaster. + +Checking line with one '.' transmissioon +. +Previous line is one single dot + +you should have character '|' as last characeter +of this email (after End Of Text). +End Of Text| diff --git a/test_area/var/spool/mailleur/mails/example.com/webmaster/dovecot/new/23383-20251210053924-0903-0000 b/test_area/var/spool/mailleur/mails/example.com/webmaster/dovecot/new/23383-20251210053924-0903-0000 new file mode 100644 index 0000000..bb6ce5e --- /dev/null +++ b/test_area/var/spool/mailleur/mails/example.com/webmaster/dovecot/new/23383-20251210053924-0903-0000 @@ -0,0 +1,12 @@ +Received: from localhost.localdomain (IP=[127.0.0.1], originator=) + by mailleur.example.com ([127.127.10.25:1025]/receiver-0.18.30-dvl) with ESMTP + id <23383-20251210053924-0903-0000@mailleur.example.com>; + Wed, 10 Dec 2025 05:39:25 -0500 +Subject: (feed002) Very Simple email contents 2 domains +From: Maitre Post +To: Maitre WEB + +.single dot, next is an empty line starting with a '.' +. +This email is sent to 3 domain X 1 users + diff --git a/test_area/var/spool/mailleur/mails/example.com/webmaster/dovecot/new/23396-20251210053928-0663-0000 b/test_area/var/spool/mailleur/mails/example.com/webmaster/dovecot/new/23396-20251210053928-0663-0000 new file mode 100644 index 0000000..5c42ea2 --- /dev/null +++ b/test_area/var/spool/mailleur/mails/example.com/webmaster/dovecot/new/23396-20251210053928-0663-0000 @@ -0,0 +1,12 @@ +Received: from keeper-us-east-1d.mxtoolbox.com (IP=[18.209.86.113], originator=) + by mailleur.example.com ([127.127.10.25:1025]/receiver-0.18.30-dvl) with ESMTP + id <23396-20251210053928-0663-0000@mailleur.example.com>; + Wed, 10 Dec 2025 05:39:32 -0500 +Subject: (feed008) sending email to local only +From: Maitre Post +To: Maitre WEB + +.single dot, next is an empty line starting with a '.' +. +This email is sent to 3 domain X 1 users + diff --git a/test_area/var/spool/mailleur/mails/mailleur.example.com/user1/dovecot/new/23398-20251210053932-0389-0000 b/test_area/var/spool/mailleur/mails/mailleur.example.com/user1/dovecot/new/23398-20251210053932-0389-0000 new file mode 100644 index 0000000..e889dab --- /dev/null +++ b/test_area/var/spool/mailleur/mails/mailleur.example.com/user1/dovecot/new/23398-20251210053932-0389-0000 @@ -0,0 +1,11 @@ +Received: from mail-ua1-f45.google.com (IP=[209.85.222.45], originator=) + by mailleur.example.com ([127.127.10.25:1025]/receiver-0.18.30-dvl) with ESMTP + id <23398-20251210053932-0389-0000@mailleur.example.com>; + Wed, 10 Dec 2025 05:39:32 -0500 +Subject: (feed008) sending email to local only +From: A Nobody +To: A simple very local user + +this ia an email "from" gmail. +test text text + diff --git a/test_area/var/spool/mailleur/receiver-logs/event-20251210.jrl b/test_area/var/spool/mailleur/receiver-logs/event-20251210.jrl new file mode 100644 index 0000000..f0b6633 --- /dev/null +++ b/test_area/var/spool/mailleur/receiver-logs/event-20251210.jrl @@ -0,0 +1,342 @@ + +#----------------------------- +#Wed Dec 10 05:39:23 2025 +05:39:23.981 Start CNT=23292-20251210053923-0979 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:23 -0500 + HELO example.com + +00.089 250 mailleur.example.com, link (cleartext) ready, your IP/FQDN=[127.0.0.1/localhost.localdomain] + MAIL FROM: + +00.132 250 2.1.3 postmaster@example.com sender ok + RCPT TO: + +00.176 250 5.6.7 Address will be processed + RCPT TO: + +00.219 250 5.6.7 Address will be processed + DATA + +00.260 354 3.5.0 End data with . + +00.301 250-3.5.3 Session ID=<23292-20251210053923-0979-0000> + +00.301 250-3.5.3 data stream received: 1 Kbytes within 0.041 seconds) + +00.301 250 3.5.3 Message accepted for delivery + QUIT + +00.342 221 2.0.0 Bye, closing connection CNT=23292-20251210053923-0979 + +00.342 (Contact terminated, condition=) + +00.344 (127.0.0.1 RVS='localhost.localdomain' delta=' 2' -> new credit='101') + +#----------------------------- +#Wed Dec 10 05:39:24 2025 +05:39:24.333 Start CNT=23294-20251210053924-0332 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:24 -0500 + EHLO example.com + +00.088 250-mailleur.example.com, link (cleartext) ready, your IP/FQDN=[127.0.0.1/localhost.localdomain] + +00.088 250-STARTTLS + +00.088 250-AUTH DIGEST-MD5 + +00.088 250-SIZE 52428800 + +00.088 250-8BITMIME + +00.088 250 ENHANCEDSTATUSCODES + starttls + +00.230 220 2.0.0 Ready to start TLS + (crypted link is now set in 'server' mode, security level='2') + EHLO example.com + +00.297 250-mailleur.example.com, link (crypted) ready, your IP/FQDN=[127.0.0.1/localhost.localdomain] + +00.297 250-AUTH PLAIN LOGIN DIGEST-MD5 + +00.297 250-SIZE 52428800 + +00.297 250-8BITMIME + +00.297 250 ENHANCEDSTATUSCODES + MAIL FROM: SIZE=1024 + +00.346 250 2.1.3 postmaster@example.com sender ok + RCPT TO: + +00.389 250 5.6.7 Address will be processed + RCPT TO: + +00.433 250 5.6.7 Address will be processed + DATA + +00.474 354 3.5.0 End data with . + +00.515 250-3.5.3 Session ID=<23294-20251210053924-0332-0000> + +00.515 250-3.5.3 data stream received: 1 Kbytes within 0.041 seconds) + +00.515 250 3.5.3 Message accepted for delivery + QUIT + +00.558 221 2.0.0 Bye, closing connection CNT=23294-20251210053924-0332 + +00.558 (Contact terminated, condition=) + +00.560 (127.0.0.1 RVS='localhost.localdomain' delta=' 2' -> new credit='103') + +#----------------------------- +#Wed Dec 10 05:39:24 2025 +05:39:24.905 Start CNT=23383-20251210053924-0903 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:24 -0500 + HELO example.com + +00.088 250 mailleur.example.com, link (cleartext) ready, your IP/FQDN=[127.0.0.1/localhost.localdomain] + MAIL FROM: + +00.130 250 2.1.3 trouble@mailref1.example.com sender ok + RCPT TO: + +00.172 250 5.6.7 Address will be processed + RCPT TO: + +00.215 250 5.6.7 Address will be processed + RCPT TO: + +00.258 250 5.6.7 Address will be processed + RCPT TO: + +00.301 250 5.6.7 Address will be processed + DATA + +00.342 354 3.5.0 End data with . + +00.383 250-3.5.3 Session ID=<23383-20251210053924-0903-0000> + +00.383 250-3.5.3 data stream received: 1 Kbytes within 0.041 seconds) + +00.383 250 3.5.3 Message accepted for delivery + QUIT + +00.424 221 2.0.0 Bye, closing connection CNT=23383-20251210053924-0903 + +00.424 (Contact terminated, condition=) + +00.425 (127.0.0.1 RVS='localhost.localdomain' delta=' 2' -> new credit='105') + +#----------------------------- +#Wed Dec 10 05:39:25 2025 +05:39:25.339 Start CNT=23385-20251210053925-0338 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:25 -0500 + HELO example.com + +00.088 250 mailleur.example.com, link (cleartext) ready, your IP/FQDN=[127.0.0.1/localhost.localdomain] + MAIL FROM: + +00.129 250 2.1.3 trouble@mailref1.example.com sender ok + RCPT TO: + +00.173 250 5.6.7 Address will be processed + RCPT TO: + +00.216 250 5.6.7 Address will be processed + RCPT TO: + +00.259 551 5.6.0 unknown user + DATA + +01.259 354 3.5.0 End data with . + +01.259 250-3.5.3 Session ID=<23385-20251210053925-0338-0000> + +01.259 250-3.5.3 data stream received: 1 Kbytes within 0.000 seconds) + +01.259 250 3.5.3 Message accepted for delivery + RSET + +01.300 250-2.1.0 flushed session 23385-20251210053925-0338-0000 + +01.301 250 2.1.0 opening new session 23385-20251210053925-0338-0001 + HELO example.com + +01.382 250 mailleur.example.com, link (cleartext) ready, your IP/FQDN=[127.0.0.1/localhost.localdomain] + MAIL FROM: + +01.423 250 2.1.3 postmaster@mailref1.example.com sender ok + RCPT TO: + +01.467 250 5.6.7 Address will be processed + RCPT TO: + +01.510 250 5.6.7 Address will be processed + DATA + +01.551 354 3.5.0 End data with . + +01.592 250-3.5.3 Session ID=<23385-20251210053925-0338-0001> + +01.592 250-3.5.3 data stream received: 1 Kbytes within 0.041 seconds) + +01.592 250 3.5.3 Message accepted for delivery + QUIT + +01.633 221 2.0.0 Bye, closing connection CNT=23385-20251210053925-0338 + +01.633 (Contact terminated, condition=) + +01.635 (127.0.0.1 RVS='localhost.localdomain' delta=' 2' -> new credit='107') + +#----------------------------- +#Wed Dec 10 05:39:26 2025 +05:39:26.985 Start CNT=23387-20251210053926-0983 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:26 -0500 + HELO example.com + +00.089 250 mailleur.example.com, link (cleartext) ready, your IP/FQDN=[127.0.0.1/localhost.localdomain] + MAIL FROM: + +00.133 250 2.1.3 postmaster@example.com sender ok + RCPT TO: + +00.176 250 5.6.7 Address will be processed + DATA + +00.217 354 3.5.0 End data with . + +00.258 250-3.5.3 Session ID=<23387-20251210053926-0983-0000> + +00.258 250-3.5.3 data stream received: 1 Kbytes within 0.041 seconds) + +00.258 250 3.5.3 Message accepted for delivery + QUIT + +00.299 221 2.0.0 Bye, closing connection CNT=23387-20251210053926-0983 + +00.299 (Contact terminated, condition=) + +00.301 (127.0.0.1 RVS='localhost.localdomain' delta=' 2' -> new credit='109') + +#----------------------------- +#Wed Dec 10 05:39:27 2025 +05:39:27.295 Start CNT=23390-20251210053927-0293 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:27 -0500 + ORGN: 213.209.157.107 + +00.091 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:27 -0500 + helo example.com + +00.133 250 mailleur.example.com, link (cleartext) ready, your IP/FQDN=[213.209.157.107/No.Reverse] + MAIL FROM: + (Remote No.Reverse[213.209.157.107] credit='-5' too low) + +00.174 556-4.5.7 Originator server IP [213.209.157.107] black listed + +00.174 556 5.5.4 Closing connection + +00.175 (Contact terminated, condition=) + +00.176 (213.209.157.107 RVS='No.Reverse' delta=' -1' -> new credit=' -6') + +#----------------------------- +#Wed Dec 10 05:39:27 2025 +05:39:27.483 Start CNT=23392-20251210053927-0482 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:27 -0500 + ORGN: 213.209.157.108 + +00.091 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:27 -0500 + starttls + +00.234 220 2.0.0 Ready to start TLS + (crypted link is now set in 'server' mode, security level='2') + EHLO example.com + +00.300 250-mailleur.example.com, link (crypted) ready, your IP/FQDN=[213.209.157.108/No.Reverse] + +00.300 250-AUTH PLAIN LOGIN DIGEST-MD5 + +00.300 250-SIZE 52428800 + +00.300 250-8BITMIME + +00.301 250 ENHANCEDSTATUSCODES + AUTH LOGIN + +00.346 334 VXNlcm5hbWU6 + dXRmOC3DocO2X8O8w7FAZXhhbXBsZS5jb20= + +00.388 334 UGFzc3dvcmQ6 + dXRmOC3DocO2X8O8w7E= + +00.429 ---- Auth accepted for user= + +00.430 235 5.7.5 authentication successful + MAIL FROM: + +00.472 250 2.1.3 trouble@mailref1.example.com sender ok + RCPT TO: + +00.515 250 5.6.7 Address will be processed + DATA + +00.558 354 3.5.0 End data with . + +00.599 250-3.5.3 Session ID=<23392-20251210053927-0482-0000> + +00.599 250-3.5.3 data stream received: 1 Kbytes within 0.041 seconds) + +00.599 250 3.5.3 Message accepted for delivery + QUIT + +00.642 221 2.0.0 Bye, closing connection CNT=23392-20251210053927-0482 + +00.642 (Contact terminated, condition=) + +00.644 (213.209.157.108 RVS='No.Reverse' delta=' 6' -> new credit=' 1') + +#----------------------------- +#Wed Dec 10 05:39:28 2025 +05:39:28.137 Start CNT=23394-20251210053928-0135 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:28 -0500 + ORGN: 192.168.254.25 + +00.091 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:28 -0500 + starttls + +00.233 220 2.0.0 Ready to start TLS + (crypted link is now set in 'server' mode, security level='2') + EHLO example.com + +00.299 250-mailleur.example.com, link (crypted) ready, your IP/FQDN=[192.168.254.25/No.Reverse] + +00.299 250-AUTH PLAIN LOGIN DIGEST-MD5 + +00.299 250-SIZE 52428800 + +00.300 250-8BITMIME + +00.300 250 ENHANCEDSTATUSCODES + MAIL FROM: + +00.346 250 2.1.3 trouble@mailref1.example.com sender ok + RCPT TO: + +00.389 250 5.6.7 Address will be processed + DATA + +00.431 354 3.5.0 End data with . + +00.472 250-3.5.3 Session ID=<23394-20251210053928-0135-0000> + +00.472 250-3.5.3 data stream received: 1 Kbytes within 0.041 seconds) + +00.472 250 3.5.3 Message accepted for delivery + QUIT + +00.515 221 2.0.0 Bye, closing connection CNT=23394-20251210053928-0135 + +00.515 (Contact terminated, condition=) + +00.517 (192.168.254.25 RVS='No.Reverse' delta=' 2' -> new credit=' 7') + +#----------------------------- +#Wed Dec 10 05:39:28 2025 +05:39:28.665 Start CNT=23396-20251210053928-0663 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:28 -0500 + ORGN: 18.209.86.113 + +00.209 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:28 -0500 + EHLO keeper-us-east-1d.mxtoolbox.com + +00.209 250-mailleur.example.com, link (cleartext) ready, your IP/FQDN=[18.209.86.113/keeper-us-east-1d.mxtoolbox.com] + +00.209 250-STARTTLS + +00.209 250-AUTH DIGEST-MD5 + +00.209 250-SIZE 52428800 + +00.209 250-8BITMIME + +00.209 250 ENHANCEDSTATUSCODES + MAIL FROM: + +00.380 250 2.1.3 supertool@mxtoolboxsmtpdiag.com sender ok + RCPT TO: + +00.382 250 5.6.7 Address will be processed + RCPT TO: + +00.669 555 2.8.0 No MX nor IP for for domain + RCPT TO: + +01.673 555 2.8.0 No relay accepted for domain + DATA + +03.673 354 3.5.0 End data with . + +03.673 250-3.5.3 Session ID=<23396-20251210053928-0663-0000> + +03.673 250-3.5.3 data stream received: 1 Kbytes within 0.000 seconds) + +03.673 250 3.5.3 Message accepted for delivery + QUIT + +03.714 221 2.0.0 Bye, closing connection CNT=23396-20251210053928-0663 + +03.715 (Contact terminated, condition=) + +03.717 (18.209.86.113 RVS='keeper-us-east-1d.mxtoolbox.com' delta=' 0' -> new credit=' 5') + +#----------------------------- +#Wed Dec 10 05:39:32 2025 +05:39:32.391 Start CNT=23398-20251210053932-0389 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:32 -0500 + ORGN: 209.85.222.45 + +00.090 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:32 -0500 + EHLO keeper-us-east-1d.mxtoolbox.com + +00.131 250-mailleur.example.com, link (cleartext) ready, your IP/FQDN=[209.85.222.45/mail-ua1-f45.google.com] + +00.131 250-STARTTLS + +00.131 250-AUTH DIGEST-MD5 + +00.131 250-SIZE 52428800 + +00.131 250-8BITMIME + +00.131 250 ENHANCEDSTATUSCODES + MAIL FROM: SIZE=2958 + +00.266 250 2.1.3 nobody@gmail.com sender ok + RCPT TO: + +00.269 250 5.6.7 Address will be processed + DATA + +00.310 354 3.5.0 End data with . + +00.351 250-3.5.3 Session ID=<23398-20251210053932-0389-0000> + +00.351 250-3.5.3 data stream received: 1 Kbytes within 0.041 seconds) + +00.351 250 3.5.3 Message accepted for delivery + QUIT + +00.392 221 2.0.0 Bye, closing connection CNT=23398-20251210053932-0389 + +00.392 (Contact terminated, condition=) + +00.394 (209.85.222.45 RVS='mail-ua1-f45.google.com' delta=' 2' -> new credit=' 7') + +#----------------------------- +#Wed Dec 10 05:39:32 2025 +05:39:32.794 Start CNT=23404-20251210053932-0793 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:32 -0500 + HELO [192.219.254.34] + +00.088 250 mailleur.example.com, link (cleartext) ready, your IP/FQDN=[127.0.0.1/localhost.localdomain] + HELO 192.219.254.35 + +00.129 250 mailleur.example.com, link (cleartext) ready, your IP/FQDN=[127.0.0.1/localhost.localdomain] + HELO domain + +00.170 250 mailleur.example.com, link (cleartext) ready, your IP/FQDN=[127.0.0.1/localhost.localdomain] + HELO 8.8.8.8 + +00.212 250 mailleur.example.com, link (cleartext) ready, your IP/FQDN=[127.0.0.1/localhost.localdomain] + EHLO .com + +00.254 501 5.5.4 HELO argument is incorrect, closing connection. + +00.254 (Contact terminated, condition=) + +00.255 (127.0.0.1 RVS='localhost.localdomain' delta=' -1' -> new credit='108') + +#----------------------------- +#Wed Dec 10 05:39:33 2025 +05:39:33.159 Start CNT=23408-20251210053933-0158 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:33 -0500 + EHLO domain..com + +00.002 501 5.5.4 HELO argument is incorrect, closing connection. + +00.002 (Contact terminated, condition=) + +00.003 (127.0.0.1 RVS='localhost.localdomain' delta=' -1' -> new credit='107') + +#----------------------------- +#Wed Dec 10 05:39:33 2025 +05:39:33.273 Start CNT=23410-20251210053933-0272 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:33 -0500 + EHLO [.192.219.254.1] + +00.002 501 5.5.4 HELO argument is incorrect, closing connection. + +00.002 (Contact terminated, condition=) + +00.003 (127.0.0.1 RVS='localhost.localdomain' delta=' -1' -> new credit='106') + +#----------------------------- +#Wed Dec 10 05:39:33 2025 +05:39:33.287 Start CNT=23412-20251210053933-0286 + (Contact open from [127.0.0.1] to [127.127.10.25:1025]) + +00.001 220 mailleur.example.com, ESMTP (cleartext) mailleur-0.18.30-dvl; Wed, 10 Dec 2025 05:39:33 -0500 + AUTH DIGEST-MD5 + +00.088 334 cmVhbG09Im1haWxsZXVyLWVtYWlsIixub25jZT0iTlRRd1VGRlNSRTVyYlc4MmNHUm9aVmM9Iixxb3A9YXV0aCxhbGdvcml0aG09bWQ1LXNlc3MsY2hhcnNldD11dGYtOA== + +00.129 ---- Auth Rejected status='504' for user= pass=<$1(a_digest_md5)> + +02.130 504 5.7.4 wrong authentication + +02.131 (Contact terminated, condition=) + +02.132 (127.0.0.1 RVS='localhost.localdomain' delta=' 0' -> new credit='106') diff --git a/test_area/var/spool/mailleur/scanner-logs/event-20251210.jrl b/test_area/var/spool/mailleur/scanner-logs/event-20251210.jrl new file mode 100644 index 0000000..2e79902 --- /dev/null +++ b/test_area/var/spool/mailleur/scanner-logs/event-20251210.jrl @@ -0,0 +1,32 @@ + +#----------------------------- +#Wed Dec 10 05:39:29 2025 +#2 remote IP to scan +05:39:29.591 IP[01]: 192.168.254.25 bl.spamcop.net -> NOT listed + +00.076 IP[01]: 192.168.254.25 sbl.spamhaus.org -> NOT listed + +00.183 IP[01]: 192.168.254.25 b.barracudacentral.org -> NOT listed + +00.460 IP[01]: 192.168.254.25 bl.blocklist.de -> NOT listed + +00.460 IP[01]: 192.168.254.25 ips.backscatterer.org -> NOT listed + +00.525 IP[01]: 192.168.254.25 hostkarma.junkemailfilter.co -> NOT listed + +00.525 IP[01]: 192.168.254.25 RVS='No.Reverse' delta=' 0' -> new credit=' 7' + + +00.595 IP[02]: 18.209.86.113 bl.spamcop.net -> NOT listed + +00.664 IP[02]: 18.209.86.113 sbl.spamhaus.org -> NOT listed + +00.748 IP[02]: 18.209.86.113 b.barracudacentral.org -> NOT listed + +00.987 IP[02]: 18.209.86.113 bl.blocklist.de -> NOT listed + +00.987 IP[02]: 18.209.86.113 ips.backscatterer.org -> NOT listed + +01.111 IP[02]: 18.209.86.113 hostkarma.junkemailfilter.co -> NOT listed + +01.111 IP[02]: 18.209.86.113 RVS='keeper-us-east-1d.mxtoolbox.com' delta=' 0' -> new credit=' 5' + + +#----------------------------- +#Wed Dec 10 05:39:36 2025 +#1 remote IP to scan +05:39:36.787 IP[01]: 209.85.222.45 bl.spamcop.net -> NOT listed + +00.060 IP[01]: 209.85.222.45 sbl.spamhaus.org -> NOT listed + +00.146 IP[01]: 209.85.222.45 b.barracudacentral.org -> NOT listed + +00.388 IP[01]: 209.85.222.45 bl.blocklist.de -> NOT listed + +00.388 IP[01]: 209.85.222.45 ips.backscatterer.org -> NOT listed + +00.459 IP[01]: 209.85.222.45 hostkarma.junkemailfilter.co -> NOT listed + +00.459 IP[01]: 209.85.222.45 RVS='mail-ua1-f45.google.com' delta=' 0' -> new credit=' 7' + diff --git a/test_area/var/spool/mailleur/scanner-logs/event-20251211.jrl b/test_area/var/spool/mailleur/scanner-logs/event-20251211.jrl new file mode 100644 index 0000000..bdddece --- /dev/null +++ b/test_area/var/spool/mailleur/scanner-logs/event-20251211.jrl @@ -0,0 +1,32 @@ + +#----------------------------- +#Thu Dec 11 05:37:50 2025 +#2 remote IP to scan +05:37:50.625 IP[01]: 213.209.157.108 bl.spamcop.net -> NOT listed + +00.143 IP[01]: 213.209.157.108 sbl.spamhaus.org -> Listed by SBL, see https://check.spamhaus.org/sbl/query/SBL689956 + +00.227 IP[01]: 213.209.157.108 b.barracudacentral.org -> NOT listed + +00.623 IP[01]: 213.209.157.108 bl.blocklist.de -> NOT listed + +00.923 IP[01]: 213.209.157.108 ips.backscatterer.org -> NOT listed + +01.052 IP[01]: 213.209.157.108 hostkarma.junkemailfilter.co -> NOT listed + +01.052 IP[01]: 213.209.157.108 RVS='No.Reverse' delta=' -1' -> new credit=' 0' + + +01.128 IP[02]: 127.0.0.1 bl.spamcop.net -> NOT listed + +01.179 IP[02]: 127.0.0.1 sbl.spamhaus.org -> NOT listed + +01.264 IP[02]: 127.0.0.1 b.barracudacentral.org -> NOT listed + +01.504 IP[02]: 127.0.0.1 bl.blocklist.de -> NOT listed + +01.650 IP[02]: 127.0.0.1 ips.backscatterer.org -> NOT listed + +01.750 IP[02]: 127.0.0.1 hostkarma.junkemailfilter.co -> NOT listed + +01.750 IP[02]: 127.0.0.1 RVS='localhost' delta=' 0' -> new credit='106' + + +#----------------------------- +#Thu Dec 11 05:39:34 2025 +#1 remote IP to scan +05:39:35.075 IP[01]: 18.209.86.113 bl.spamcop.net -> NOT listed + +00.067 IP[01]: 18.209.86.113 sbl.spamhaus.org -> NOT listed + +00.179 IP[01]: 18.209.86.113 b.barracudacentral.org -> NOT listed + +00.419 IP[01]: 18.209.86.113 bl.blocklist.de -> NOT listed + +00.637 IP[01]: 18.209.86.113 ips.backscatterer.org -> NOT listed + +00.707 IP[01]: 18.209.86.113 hostkarma.junkemailfilter.co -> NOT listed + +00.707 IP[01]: 18.209.86.113 RVS='keeper-us-east-1d.mxtoolbox.com' delta=' 0' -> new credit=' 5' + diff --git a/test_area/var/spool/mailleur/sender-logs/event-20251210.jrl b/test_area/var/spool/mailleur/sender-logs/event-20251210.jrl new file mode 100644 index 0000000..3d116bc --- /dev/null +++ b/test_area/var/spool/mailleur/sender-logs/event-20251210.jrl @@ -0,0 +1,172 @@ + +#----------------------------- +#Wed Dec 10 05:39:32 2025 +#main-session-id=23294-20251210053924-0332 +05:39:32.470 Now Connected to MX + +00.001 220 smtp1.example.com ESMTP clement-2.8.1-91; Wed, 10 Dec 2025 05:39:32 -0500 + EHLO example.com + +00.006 250-smtp1.example.com Hello devel5.safe.ca [192.219.254.70], please to meet you + +00.047 250-ENHANCEDSTATUSCODES + +00.047 250-8BITMIME + +00.047 250-SIZE + +00.047 250-AUTH PLAIN LOGIN + +00.047 250-STARTTLS + +00.047 250 HELP + STARTTLS + +00.048 220 Ready to start TLS + (crypted link is now set in 'client' mode, security level='2') + EHLO example.com + +00.122 250-smtp1.example.com Hello devel5.safe.ca [192.219.254.70], please to meet you + +00.122 250-ENHANCEDSTATUSCODES + +00.122 250-8BITMIME + +00.122 250-SIZE + +00.122 250-AUTH PLAIN LOGIN + +00.122 250 HELP + MAIL FROM: + +00.128 250 ... sender ok + RCPT TO: + +00.730 250 Address accepted + RCPT TO: + +00.736 250 Address accepted + DATA + +00.738 354 Enter mail, end with "." on a line by itself + +00.788 250 Message accepted for delivery (Session ID=<00737-20251210053932-0cc60ea7>) + Data stream Sent: 1 Kbytes within 0.052 seconds + Transmission completed successfully + RSET + +01.250 250 Reset state + MAIL FROM: + +01.254 250 ... sender ok + RCPT TO: + +01.259 250 Address accepted + DATA + +01.261 354 Enter mail, end with "." on a line by itself + +01.311 250 Message accepted for delivery (Session ID=<00737-20251210053933-0cc6138b>) + Data stream Sent: 1 Kbytes within 0.051 seconds + Transmission completed successfully + RSET + +01.486 250 Reset state + MAIL FROM: + +01.490 250 ... sender ok + RCPT TO: + +01.494 250 Address accepted + RCPT TO: + +01.499 250 Address accepted + DATA + +01.501 354 Enter mail, end with "." on a line by itself + +01.551 250 Message accepted for delivery (Session ID=<00737-20251210053933-0cc61479>) + Data stream Sent: 1 Kbytes within 0.052 seconds + Transmission completed successfully + RSET + +01.906 250 Reset state + MAIL FROM: + +01.910 250 ... sender ok + RCPT TO: + +01.915 250 Address accepted + RCPT TO: + +01.920 250 Address accepted + DATA + +01.922 354 Enter mail, end with "." on a line by itself + +01.972 250 Message accepted for delivery (Session ID=<00737-20251210053934-0cc6161e>) + Data stream Sent: 1 Kbytes within 0.051 seconds + Transmission completed successfully + QUIT + +02.045 221 smtp1.example.com closing connection + +#----------------------------- +#Wed Dec 10 05:39:34 2025 +#main-session-id=23383-20251210053924-0903 +05:39:34.531 Now Connected to MX + +00.002 220 mailpostg.example.com, ESMTP (cleartext) mailleur-0.13.88-dvl; Wed, 10 Dec 2025 05:39:34 -0500 + EHLO mailref1.example.com + +00.003 250-mailpostg.example.com, link (cleartext) ready, your IP/FQDN=[192.219.254.70/devel5.safe.ca] + +00.003 250-STARTTLS + +00.003 250-AUTH DIGEST-MD5 + +00.003 250-SIZE 52428800 + +00.003 250-8BITMIME + +00.003 250 ENHANCEDSTATUSCODES + STARTTLS + +00.103 220 2.0.0 Ready to start TLS + (crypted link is now set in 'client' mode, security level='2') + EHLO mailref1.example.com + +00.148 250-mailpostg.example.com, link (crypted) ready, your IP/FQDN=[192.219.254.70/devel5.safe.ca] + +00.149 250-AUTH PLAIN LOGIN DIGEST-MD5 + +00.150 250-SIZE 52428800 + +00.151 250-8BITMIME + +00.153 250 ENHANCEDSTATUSCODES + MAIL FROM: + +00.154 250 2.1.3 trouble@mailref1.example.com.. sender ok + RCPT TO: + +00.156 250 2.6.4 Address accepted + DATA + +00.157 354 3.5.0 End data with . + +00.199 250-3.5.3 Session ID=<00522-20251210053934-0531-0000> + +00.200 250-3.5.3 data stream received: 1 Kbytes within 0.041 seconds) + +00.201 250 3.5.3 Message accepted for delivery + Data stream Sent: 1 Kbytes within 0.044 seconds + Transmission completed successfully + RSET + +00.202 250-2.1.0 flushed session 00522-20251210053934-0531-0000 + +00.242 250 2.1.0 opening new session 00522-20251210053934-0531-0001 + MAIL FROM: + +00.244 250 2.1.3 trouble@mailref1.example.com.. sender ok + RCPT TO: + +00.246 250 2.6.4 Address accepted + DATA + +00.247 354 3.5.0 End data with . + +00.289 250-3.5.3 Session ID=<00522-20251210053934-0531-0001> + +00.290 250-3.5.3 data stream received: 1 Kbytes within 0.042 seconds) + +00.291 250 3.5.3 Message accepted for delivery + Data stream Sent: 1 Kbytes within 0.045 seconds + Transmission completed successfully + RSET + +00.292 250-2.1.0 flushed session 00522-20251210053934-0531-0001 + +00.333 250 2.1.0 opening new session 00522-20251210053934-0531-0002 + MAIL FROM: + +00.334 250 2.1.3 trouble@mailref1.example.com.. sender ok + RCPT TO: + +00.336 250 2.6.4 Address accepted + DATA + +00.338 354 3.5.0 End data with . + +00.380 250-3.5.3 Session ID=<00522-20251210053934-0531-0002> + +00.381 250-3.5.3 data stream received: 1 Kbytes within 0.042 seconds) + +00.382 250 3.5.3 Message accepted for delivery + Data stream Sent: 1 Kbytes within 0.046 seconds + Transmission completed successfully + QUIT + +00.383 221 2.0.0 Bye, closing connection CNT=00522-20251210053934-0531 + +#----------------------------- +#Wed Dec 10 05:39:34 2025 +#main-session-id=23383-20251210053924-0903 +05:39:34.922 Now Connected to MX + +00.026 220 mailmysql.example.com, ESMTP (cleartext) mailleur-0.13.95-dvl; Wed, 10 Dec 2025 05:39:34 -0500 + EHLO mailref1.example.com + +00.026 250-mailmysql.example.com, link (cleartext) ready, your IP/FQDN=[192.219.254.70/devel5.safe.ca] + +00.026 250-STARTTLS + +00.026 250-AUTH DIGEST-MD5 + +00.026 250-SIZE 52428800 + +00.026 250-8BITMIME + +00.026 250 ENHANCEDSTATUSCODES + STARTTLS + +00.129 220 2.0.0 Ready to start TLS + (crypted link is now set in 'client' mode, security level='2') + EHLO mailref1.example.com + +00.197 250-mailmysql.example.com, link (crypted) ready, your IP/FQDN=[192.219.254.70/devel5.safe.ca] + +00.198 250-AUTH PLAIN LOGIN DIGEST-MD5 + +00.200 250-SIZE 52428800 + +00.201 250-8BITMIME + +00.202 250 ENHANCEDSTATUSCODES + MAIL FROM: + +00.205 250 2.1.3 trouble@mailref1.example.com.. sender ok + RCPT TO: + +00.212 250 2.6.4 Address accepted + DATA + +00.214 354 3.5.0 End data with . + +00.255 250-3.5.3 Session ID=<01634-20251210053934-0922-0000> + +00.257 250-3.5.3 data stream received: 1 Kbytes within 0.042 seconds) + +00.258 250 3.5.3 Message accepted for delivery + Data stream Sent: 1 Kbytes within 0.045 seconds + Transmission completed successfully + QUIT + +00.259 221 2.0.0 Bye, closing connection CNT=01634-20251210053934-0922 diff --git a/tools/DIGEST-MD5 b/tools/DIGEST-MD5 new file mode 100644 index 0000000..c797e0a --- /dev/null +++ b/tools/DIGEST-MD5 @@ -0,0 +1,88 @@ +Sequence pour "calculer la reponse digest-MD5 +#----------------------------------------- +https://stackoverflow.com/questions/40505711/digest-md5-response-generation + +chris:elwood.innosoft.com:secret + -> eb5a750053e4d2c34aa84bbc9b0b6ee7 + +A1: +chris+secret nonce cnonce +eb5a750053e4d2c34aa84bbc9b0b6ee7:OA6MG9tEQGm2hh:OA6MHXh6VqTrRk + -> 54442ff1f394d9d0de1205cef4d9cebe + +A2 digest-uri="imap/elwood.innosoft.com" +AUTHENTICATE:imap/elwood.innosoft.com + -> 15e3594677e51ade69715d1cb7d207ba + +RESPONSE + A1 nonce nc-value cnonce qpop A2 +54442ff1f394d9d0de1205cef4d9cebe:OA6MG9tEQGm2hh:00000001:OA6MHXh6VqTrRk:auth:15e3594677e51ade69715d1cb7d207ba + -> 26ef1190b643a36e879673066098379c +OK. +#----------------------------------------- +RFC-2831 +example 1 (B64) +X chris:elwood.innosoft.com:secret + Y -> eb5a750053e4d2c34aa84bbc9b0b6ee7 + +A1 +chris+secret nonce cnonce +eb5a750053e4d2c34aa84bbc9b0b6ee7:OA6MG9tEQGm2hh:OA6MHXh6VqTrRk + HA1 -> 54442ff1f394d9d0de1205cef4d9cebe + +A2 digest-uri="imap/elwood.innosoft.com" +AUTHENTICATE:imap/elwood.innosoft.com + HA2 -> 15e3594677e51ade69715d1cb7d207ba + +RESPONSE + HA1 nonce nc-value cnonce qpop HA2 +54442ff1f394d9d0de1205cef4d9cebe:OA6MG9tEQGm2hh:00000001:OA6MHXh6VqTrRk:auth:15e3594677e51ade69715d1cb7d207ba + -> 26ef1190b643a36e879673066098379c +expected-> d388dad90d4bbd760a152321f2143af7 + NO Match +#------- +example 2 (ACAP) +chris:elwood.innosoft.com:secret + -> eb5a750053e4d2c34aa84bbc9b0b6ee7 +A1 +chris+secret nonce cnonce +eb5a750053e4d2c34aa84bbc9b0b6ee7:OA9BSXrbuRhWay:OA9BSuZWMSpW8m + -> da2ad3976e8e37a03ecd844797a82ae7 + +A2 digest-uri="acap/elwood.innosoft.com" +AUTHENTICATE:acap/elwood.innosoft.com + -> c557ec746787450143826ac2c55cbabf + +RESPONSE + A1 nonce nc-value cnonce qpop A2 +da2ad3976e8e37a03ecd844797a82ae7:OA9BSXrbuRhWay:00000001:OA9BSuZWMSpW8m:auth:c557ec746787450143826ac2c55cbabf + -> 90771dc5643a801bb9a9bcbb1ed3cd34 + NO Match + + + +#----------------------------------------- +#Essais avec mailleur (password xxx) +webmaster@example.com:mailleur.example.com:xxx + -> 841ece3c65e16f381f58f3ee5c28dabc + +A1 +webmaster+secret nonce cnonce +841ece3c65e16f381f58f3ee5c28dabc:ABCDEF:0b5f7bf8d392423e355bd2e2375fcd25 + HEX=38343165636533633635653136663338316635386633656535633238646162633A4142434445463A3062356637626638643339323432336533353562643265323337356663643235 + HA1 -> 94a52c447501f0729d2f2a07dfde9c9e + +A2 digest-uri="smtp/127.127.10.25" +AUTHENTICATE:smtp/127.127.10.25 + HEX=41555448454E5449434154453A736D74702F3132372E3132372E31302E3235 + HA2 -> df0b39e40b72a0f55dba5c2e153b0b7f + + +RESPONSE + A1 nonce nc-value cnonce qpop A2 +94a52c447501f0729d2f2a07dfde9c9e:ABCDEF:00000001:0b5f7bf8d392423e355bd2e2375fcd25:auth:df0b39e40b72a0f55dba5c2e153b0b7f + HEX=94a52c447501f0729d2f2a07dfde9c9e:ABCDEF:00000001:0b5f7bf8d392423e355bd2e2375fcd25:auth:df0b39e40b72a0f55dba5c2e153b0b7 + + -> 3eafcc0a2e5d920e4b3ee691b2cf9e15 + NO Match + caaee0870f16e83f8176e0de724567a1 diff --git a/tools/DIGEST-MD5-1 b/tools/DIGEST-MD5-1 new file mode 100644 index 0000000..5339d11 --- /dev/null +++ b/tools/DIGEST-MD5-1 @@ -0,0 +1,112 @@ +#----------------------------------------- +#Essais avec mailleur (password xxx) +webmaster@example.com:mailleur.example.com:xxx + -> 841ece3c65e16f381f58f3ee5c28dabc + +A1 007862:asterisk:1q2w3e + HA1 -> 64e5dd333209a9af67ec11d61b3c6479 + +A2 REGISTER:sip:192.168.55.167:5060 + HA2 -> 7df6ad58ee02df3e342fe72722bd624c + + +RESPONSE + HA1 nonce nc-value cnonce qpop HA2 +64e5dd333209a9af67ec11d61b3c6479:1612176383/ac153881bb7f5c7fafe2179aa4ed5617:00000001:CC77FDAA:auth:7df6ad58ee02df3e342fe72722bd624c + HRSP=611d34af182ff56ffec67a04ce8561e5 + Match + +#-------------------------------# +X webmaster@example.com:devel5.safe.ca:mailleur2 + Y -> 139f041506766c07cab7dc7bd842e535 + +A1 139f041506766c07cab7dc7bd842e535:ABCDEF:DjrYLBA3zOo=: + HA1 -> b4e0e53f97f1ec651567be200ded6216 + +A2 AUTHENTICATE:smtp/devel5.safe.ca + HA2 -> 41054b020583decd30bce12313b60579 + + HA1 nonce nc-value cnonce qpop HA2 +b4e0e53f97f1ec651567be200ded6216:ABCDEF:00000001:DjrYLBA3zOo=:auth:41054b020583decd30bce12313b60579 + +#-------------------------------# +X webmaster@example.com:devel5.safe.ca:xxx + Y -> 9bf22611048932ad8661a24966fcc9da + +A1 60dbd555ac12ca306e2a011af850062f:abcdef:f4d9a4fdf85df7bc50d74ab893673f08 + HA1 -> 2630ba89adf72bddf006949fc68be360 + HEXA1 -> 3236333062613839616466373262646466303036393439666336386265333630 + +A2 AUTHENTICATE:smtp/devel5.safe.ca + Ha2 -> d0b815ab45006cd0a0ae2a1e44c26311 + HEXA2 -> 6430623831356162343530303663643061306165326131653434633236333131 + + + HEXA1 nonce nc-value cnonce qpop HEXA2 +3236333062613839616466373262646466303036393439666336386265333630:abcdef:00000001:f4d9a4fdf85df7bc50d74ab893673f08:auth:6430623831356162343530303663643061306165326131653434633236333131 + -> d975a253dbeb1463d5e81621c62de806 + NO Match + Expected 1a23eaa7400ca40d732c5518df1c6bf6 + + + +#-------------------------------# +A1 webmaster@example.com:devel5.safe.ca:xxx + HA1 -> 60dbd555ac12ca306e2a011af850062f + +A2 AUTHENTICATE:smtp/devel5.safe.ca + HA2 -> d0b815ab45006cd0a0ae2a1e44c26311 + +md5-sess +MHA2 60dbd555ac12ca306e2a011af850062f:abcdef:491ea65a17ebf2375c6de7b89089a0c6 + HMHA2-> 72926dc581112b30f0fb5835b16eb98f + +AU 72926dc581112b30f0fb5835b16eb98f:abcdef:00000001:491ea65a17ebf2375c6de7b89089a0c6:auth:d0b815ab45006cd0a0ae2a1e44c26311 + a8b1d5e4d239a7342ba25edf07a92161 + + +R 23734732d5893f5f4c8db0d11afdb16f + + +#-------------------------------# +#RFC 2831 +A1 chris:elwood.innosoft.com:secret + HA1 -> eb5a750053e4d2c34aa84bbc9b0b6ee7 + +A3 eb5a750053e4d2c34aa84bbc9b0b6ee7:OA6MG9tEQGm2hh:OA6MHXh6VqTrRk + HA3 -> 54442ff1f394d9d0de1205cef4d9cebe + +A5 chris:elwood.innosoft.com:secret:OA6MG9tEQGm2hh:OA6MHXh6VqTrRk + HA5 -> 64fab581c08cd3607db0e2cb7448f8fc + +#Using 16 octet MD5 hash +A7 chris:elwood.innosoft.com:secret + MA7 -> 53e4d2c34aa84bbc + +A9 53E4D2C34AA84BBC:OA6MG9tEQGm2hh:OA6MHXh6VqTrRk + HA9 -> ed24c93d123ef0a9f86b6284e21f9795 (lower) + HA9 -> 808ab19ea0b8021813668e78659d4a61 (Upper) + +#using MD4 +A11 chris:elwood.innosoft.com:secret + MD4 -> efc8655e58a71662cd7e05321207a166 +A13 efc8655e58a71662cd7e05321207a166:OA6MG9tEQGm2hh:OA6MHXh6VqTrRk + HA13-> f36feb336734edd02e66eefbe2bc410d + +# +A2 AUTHENTICATE:imap/elwood.innosoft.com + HA2 -> 15e3594677e51ade69715d1cb7d207ba + +AU3 54442ff1f394d9d0de1205cef4d9cebe:OA6MG9tEQGm2hh:00000001:OA6MHXh6VqTrRk:auth:15e3594677e51ade69715d1cb7d207ba + HA2 -> 26ef1190b643a36e879673066098379c + (MAtch Question + https://stackoverflow.com/questions/40505711/digest-md5-response-generation) + + +AU5 64fab581c08cd3607db0e2cb7448f8fc:OA6MG9tEQGm2hh:00000001:OA6MHXh6VqTrRk:auth:15e3594677e51ade69715d1cb7d207ba + HAU4-> d1e92278b0fe2998049370e46965d610 + +AU9 808ab19ea0b8021813668e78659d4a61:OA6MG9tEQGm2hh:00000001:OA6MHXh6VqTrRk:auth:15e3594677e51ade69715d1cb7d207ba + +AU13 f36feb336734edd02e66eefbe2bc410d:OA6MG9tEQGm2hh:00000001:OA6MHXh6VqTrRk:auth:15e3594677e51ade69715d1cb7d207ba + diff --git a/tools/DIGEST-MD5-2 b/tools/DIGEST-MD5-2 new file mode 100644 index 0000000..d72f530 --- /dev/null +++ b/tools/DIGEST-MD5-2 @@ -0,0 +1,25 @@ +#---------------------------- +#RFC 2831 + +A1 chris:elwood.innosoft.com:secret + MD5 -> eb5a750053e4d2c34aa84bbc9b0b6ee7 + ASC ëZuSäÒÃJ¨K¼�␋nç + +HA1 ëZuSäÒÃJ¨K¼�␋nç:OA6MG9tEQGm2hh:OA6MHXh6VqTrRk + MD5 -> 31eff9910059e25fc196bb1fd4f3b6a2 + +A2 AUTHENTICATE:imap/elwood.innosoft.com + HA2 -> 15e3594677e51ade69715d1cb7d207ba + +Reponse 31eff9910059e25fc196bb1fd4f3b6a2:A6MG9tEQGm2hh:00000001:OA6MHXh6VqTrRk:auth:15e3594677e51ade69715d1cb7d207ba + MD5 -> + + + +#---------------- +# +USR webmaster@example.com:devel5.safe.ca:xxx + MD5 -> 60dbd555ac12ca306e2a011af850062f + +A1 `��U��0n*��P/:abcdef:241d0e88112556c60f8154a8da8f3ce7 + MD5 -> diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..7662208 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,112 @@ +#-------------------------------------------------------------------- +#Executable generation area +#-------------------------------------------------------------------- +debug : + @ $(MAKE) -s OPTIME="-g" DEBUG="-DDEBUG" exe + @ echo "tools compiled in '$@' mode now ready" + +prod : + @ $(MAKE) -s OPTIME="-g -O2" exe + @ echo "tools compiled in '$@' mode now ready" + +exe : + $(MAKE) $(EXE) + +allclean \ +clean : + - rm -fr *.o $(EXE) toremake + - rm -fr ../bin/* + +#-------------------------------------------------------------------- +#Equivalences +#-------------------------------------------------------------------- +EXE= \ + chkhex \ + digmd5 \ + +SRC= \ + chkhex.c \ + digmd5.c \ + +#-------------------------------------------------------------------- +#definitions +#-------------------------------------------------------------------- +CC = gcc +LD = gcc -g +CFLAGS = -I ../lib -Wall $(OPTIME) +LIBMAIL = ../lib/libmail.a + +LIBS = $(LIBMAIL) \ + -luuid \ + -lcrypto \ + -lcrypt \ + -lssl \ + +#-------------------------------------------------------------------- +VALKIND = "definite,possible,indirect" +#testing area +tstmd5 : digmd5 + @ ./digmd5 xxx $(BASE64) + +valmd5 : digmd5 + @ valgrind \ + --leak-check=full \ + --show-leak-kinds=$(VALKIND) \ + ./digmd5 xxx $(BASE64) + +dbgmd5 : digmd5 + @ gdb \ + --args \ + ./digmd5 xxx $(BASE64) + +tsthex : chkhex + @ ./chkhex \ + $(HEXA) + +dbghex : chkhex + @ gdb \ + --args \ + ./chkhex \ + $(HEXA) + +valhex : chkhex + @ valgrind \ + --leak-check=full \ + --show-leak-kinds=$(VALKIND) \ + ./chkhex \ + $(HEXA) + +#-------------------------------------------------------------------- +#Dependances +#-------------------------------------------------------------------- + +chkhex : toremake chkhex.o + @ $(LD) $(LDFLAGS) -o ../tools/$@ $@.o $(LIBS) + +chkhex.o: chkhex.c \ + ../lib/unidig.h \ + ../lib/subcnv.h \ + + +digmd5 : toremake digmd5.o + @ $(LD) $(LDFLAGS) -o ../tools/$@ $@.o $(LIBS) + +digmd5.o: digmd5.c \ + ../lib/unidig.h \ + ../lib/unipar.h \ + ../lib/uniprc.h \ + ../lib/subrou.h + +toremake: Makefile + touch toremake + - rm -f $(EXE) *.o + +#-------------------------------------------------------------------- +HEXA = \ + e7680cee0538ac00aff721c5c96e3d4b\ + 1d9908089a1ca0c347758b81fe61b6a4\ + Z7680cee0538ac00aff721c5c96e3d4b\ + Too_short \ + +BASE64 = Y2hhcnNldD11dGYtOCxjbm9uY2U9ImFkZDJhNmM0ODFlZjYzMTA2ZWY4MDNlOGJmMzE4ZGQyIixkaWdlc3QtdXJpPSJzbXRwL2RldmVsNS5zYWZlLmNhIixuYz0wMDAwMDAwMSxub25jZT0iYWJjZGVmIixxb3A9YXV0aCxyZWFsbT0iZGV2ZWw1LnNhZmUuY2EiLHJlc3BvbnNlPTBiM2VkZThjODgyODg4OTFhMDY2MDNkOWQwYjg0ZjZmLHVzZXJuYW1lPSJ3ZWJtYXN0ZXJAZXhhbXBsZS5jb20i +#-------------------------------------------------------------------- diff --git a/tools/chkhex.c b/tools/chkhex.c new file mode 100644 index 0000000..6b97bb5 --- /dev/null +++ b/tools/chkhex.c @@ -0,0 +1,61 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Validation program to check */ +/* MD5TYP/hexadecimal sequence */ +/* */ +/* Usage: */ +/* chkhexa an MD5 heaxdecimal number. */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include +#include + +#include "subcnv.h" +#include "unidig.h" + +/* + +*/ +/********************************************************/ +/* */ +/* Main routine */ +/* Read the the hexadecimal number */ +/* convert it to binary and convert-it back*/ +/* to hexadecimal and compare it. */ +/* */ +/********************************************************/ +int main(int argc,char *argv[]) + +{ +int status; + +status=0; +for (int i=1;i\n",argv[i]); + } +return status; +} diff --git a/tools/digmd5.c b/tools/digmd5.c new file mode 100644 index 0000000..a5a6881 --- /dev/null +++ b/tools/digmd5.c @@ -0,0 +1,147 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +/********************************************************/ +/* */ +/* Validation program to check DIGEST-MD5 Exchange */ +/* */ +/* Usage: */ +/* digmd5 secret_pass base64_string */ +/* */ +/********************************************************/ +#include +#include +#include +#include +#include + +#include "subcnv.h" +#include "subrou.h" +#include "unidig.h" +#include "unipar.h" +#include "uniprc.h" + +#define DIGMD5 "digmd5" //application name +/* + +*/ +/********************************************************/ +/* */ +/* Procedure to check the DIGEST response */ +/* */ +/********************************************************/ +static int chkresponse(int argc,char *argv[]) + +{ +#define OPEP "digmd5.c:chkresponse," + +int status; +char *cleartext; +RSPTYP *resp; +int phase; +_Bool proceed; + +status=-1; +cleartext=cnv_getb64(argv[1]); +phase=0; +proceed=(cleartext!=(char *)0); +while (proceed==true) { + switch (phase) { + case 0 : //extracting data + (void) rou_alert(0,"cleartext=<%s>",cleartext); + resp=dig_parseresp(cleartext); + break; + case 1 : { //checking + char *HA0; + + if ((HA0=dig_hashresp(resp,"AUTHENTICATE",argv[0]))!=(char *)0) { + if (strcmp(HA0,resp->response)==0) { + (void) rou_alert(0,"Expected=<%s>",resp->response); + (void) rou_alert(0,"Computed=<%s>",HA0); + status=0; + } + HA0=rou_freestr(HA0); + } + } + break; + case 2 : //free memory + resp=dig_freeresp(resp); + break; + default : //SAFE Guard + proceed=false; + break; + } + phase++; + } +cleartext=rou_freestr(cleartext); +return status; + +#undef OPEP +} +/* + +*/ +/********************************************************/ +/* */ +/* Main routine */ +/* Read the challenge response in base 64 */ +/* and check if the challange response is */ +/* OK. */ +/* */ +/********************************************************/ +int main(int argc,char *argv[]) + +{ +int status; +int phase; +ARGTYP *params; +_Bool proceed; + +status=0; +params=(ARGTYP *)0; +foreground=true; +phase=0; +proceed=true; +while (proceed==true) { + switch (phase) { + case 0 : //checking parameters + if ((params=par_getparams(argc,argv,"d:hr:v"))==(ARGTYP *)0) + phase=999; //no need to go further + break; + case 1 : //check if we have file to scan + if (params->argc!=2) { + (void) rou_alert(0,"Unable to proceed with test"); + (void) rou_alert(0,"\tthe test pattern number should be 2"); + (void) rou_alert(0,"\tsee Makefile 'tstmd5:' entry as example"); + status=-1; + phase=999; + } + break; + case 2 : + (void) rou_modesubrou(true); + (void) rou_setappname(DIGMD5); + (void) prc_preptitle(argc,argv,environ); + foreground=true; + break; + case 3 : //doing main task + status=chkresponse(params->argc,params->argv); + switch (status) { + case 0 : + (void) rou_alert(0,"dig_hashresp is working ok"); + break; + default : + (void) rou_alert(0,"dig_hashresp is NOT working fine"); + break; + } + break; + case 4 : //main task completed + (void) prc_cleantitle(); + params=par_freeparams(params); + (void) rou_modesubrou(false); + break; + default : //end of task + proceed=false; + break; + } + phase++; + } +(void) exit(status); +} diff --git a/tools/genpsdusr.sh b/tools/genpsdusr.sh new file mode 100755 index 0000000..3c2a936 --- /dev/null +++ b/tools/genpsdusr.sh @@ -0,0 +1,16 @@ +#! /usr/bin/bash +#---------------------------------------------------------- +#procedure to generate an ASCII list of user to +#populate and test database +#---------------------------------------------------------- +max=$1; +if [ -z $1 ] ; then + max=1000; + fi +for (( num=0; num<$max; num++ )) + do + ( + fnum=$(printf "%05d\n" "$num") + echo "INSERT INTO emails (email) values ('z-popusr$fnum@example.com');"; + ) + done diff --git a/www/.lvlmai.php.swp b/www/.lvlmai.php.swp new file mode 100644 index 0000000..fe9be34 Binary files /dev/null and b/www/.lvlmai.php.swp differ diff --git a/www/coloration.js b/www/coloration.js new file mode 100644 index 0000000..e286874 --- /dev/null +++ b/www/coloration.js @@ -0,0 +1,84 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +// to change columne header colors +// +let columns = []; +let currentSearch = ""; + +// Récupération des éléments +const searchInput = document.getElementById("searchInput"); +const limitSelect = document.getElementById("limitSelect"); + +// Header click pour multi-colonnes +document.querySelectorAll(".filter-col").forEach(th => { + th.addEventListener("click", () => { + const col = th.getAttribute("trkey"); + if (columns.includes(col)) { + columns = columns.filter(c => c !== col); + th.classList.remove("active"); + } else { + columns.push(col); + th.classList.add("active"); + } + refresh(); + }); +}); + +// Recherche et changement de limit +if (searchInput) { + searchInput.addEventListener("input", refresh); +} +if (limitSelect) { + limitSelect.addEventListener("change", refresh); +} + +// AJAX vers le même fichier +function refresh() { + const form = new FormData(); + + currentSearch = searchInput ? searchInput.value.trim() : ""; + form.append("search", currentSearch); + + const limitValue = limitSelect ? limitSelect.value : 0; + form.append("limit", limitValue); + + const activeColumns = columns.length ? columns : ["remoteip", "reverse", "creation"]; + activeColumns.forEach(c => form.append("columns[]", c)); + + fetch("", { method: "POST", body: form }) + .then(r => r.text()) // <- récupère le texte brut + .then(text => { + console.log("Server response:", text); + try { + const json = JSON.parse(text); + renderTable(json.rows, json.search); + } catch(e) { + console.error("JSON parse error:", e); + } + }); + +} + +// Remplissage tableau avec surbrillance +function renderTable(rows, search) { + console.log("AJAX: nombre de lignes reçues =", rows.length); + const tbody = document.querySelector("#dataTable tbody"); + if (!tbody) return; + + tbody.innerHTML = ""; + const re = search ? new RegExp(search, "gi") : null; + + for (const row of rows) { + const tr = document.createElement("tr"); + const cells = ["remoteip", "reverse", "creation"].map(c => { + let val = row[c] === null ? "NULL" : row[c]; + if (re) val = val.replace(re, m => `${m}`); + return `${val}`; + }); + tr.innerHTML = cells.join(""); + tbody.appendChild(tr); + } +} + +// Load initial +refresh(); + diff --git a/www/coloration.js.org b/www/coloration.js.org new file mode 100644 index 0000000..1468c03 --- /dev/null +++ b/www/coloration.js.org @@ -0,0 +1,65 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab +// to change columne header colors +// +let columns=[]; +let currentSearch=""; + +const searchInput = document.getElementById("searchInput"); +const limitSelect = document.getElementById("limitSelect"); + +// Header click pour multi-colonnes +document.querySelectorAll(".filter-col").forEach(th=>{ + th.addEventListener("click",()=>{ + const col = th.getAttribute("trkey"); + if (columns.includes(col)){ + columns = columns.filter(c=>c!==col); + th.classList.remove("active"); + } + else { + columns.push(col); + th.classList.add("active"); + } + refresh(); + }); +}); + +// Recherche et changement de limit +searchInput.addEventListener("input",refresh); +limitSelect.addEventListener("change",refresh); + +// AJAX vers le même fichier +function refresh(){ +currentSearch = searchInput.value.trim(); +const form = new FormData(); +form.append("search", currentSearch); +form.append("limit", limitSelect.value); + +const activeColumns = columns.length ? columns : ["remoteip","reverse","creation"]; +activeColumns.forEach(c=>form.append("columns[]",c)); + +fetch("", {method:"POST", body:form}) + .then(r=>r.json()) + .then(json=>renderTable(json.rows,json.search)); +} + +// Remplissage tableau avec surbrillance +function renderTable(rows,search){ +console.log("AJAX: nombre de lignes reçues =", rows.length); +const tbody=document.querySelector("#dataTable tbody"); +tbody.innerHTML=""; +const re = search ? new RegExp(search,"gi") : null; +for(const row of rows){ + const tr=document.createElement("tr"); + const cells = ["remoteip","reverse","creation"].map(c=>{ + // NULL -> "NULL" + let val = row[c] === null ? "NULL" : row[c]; + if(re) val = val.replace(re,m=>`${m}`); + return `${val}`; + }); + tr.innerHTML=cells.join(""); + tbody.appendChild(tr); + } +} + +// Load initial +refresh(); diff --git a/www/complex.java b/www/complex.java new file mode 100644 index 0000000..65fcb2f --- /dev/null +++ b/www/complex.java @@ -0,0 +1,41 @@ +add_filter( 'the_password_form', 'wpse_12172023_custom_post_password_wrong_msg' ); + +/** + * Add a message to the password form. + * + * @wp-hook the_password_form + * @param string $form + * @return string + */ +function wpse_12172023_custom_post_password_wrong_msg( $form ) +{ + // No cookie, the user has not sent anything until now. + if ( ! isset( $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] ) ) { + return $form; + } + + // The refresh came from a different page, the user has not sent anything until now. + if ( wp_get_raw_referer() != get_permalink() ) { + return $form; + } + + // Translate and escape. + $msg = esc_html__( 'Oops! Looks like your password is incorrect. Just ask your proctor for the right one.', 'your_text_domain' ); + + // We have a cookie, but it doesn’t match the password. + $msg = "

$msg

"; + ?> + +connection=new PDO("$dbtype:host={$dbhost};dbname={$dbname};",$dbuser); + $this->connection->setAttribute(PDO::ATTR_PERSISTENT,true); + $this->connection->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); + $this->connection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC); + } catch(Exception $e) { + throw new Exception($e->getMessage()); + } + } + + // Insert a row/s in a Database Table + public function Insert($statement="" ,$parameters=[]) { + try { + $stmt=$this->connection->prepare($statement); + return $stmt->execute($parameters); + } catch(Exception $e) { + throw new Exception($e->getMessage()); + } + } + + // Select a row/s in a Database Table + public function Select($statement="",$parameters=[]) { + try { + rou_alert(0,"$this->OPEP JMPDBG select=<$statement>"); + return $this->executeStatement($statement,$parameters); + } catch(Exception $e) { + throw new Exception($e->getMessage()); + } + } + + +// Update a row/s in a Database Table + public function Update( ) { + } + + // Remove a row/s in a Database Table + public function Remove( ) { + } + + // execute statement + private function executeStatement($statement="",$parameters=[]) { + try { + $stmt=$this->connection->prepare($statement); + $stmt->execute($parameters); + return $stmt; + }catch(Exception $e) { + throw new Exception($e->getMessage()); + } + } + + // Quote a string safely for SQL + public function quote(string $str): string { + return $this->connection->quote($str); + } + } + + +//============================================================== +// +// To open (according DBTYP) A database acces +// +//============================================================== +function sql_connect() + +{ +$OPEP="devsal.php, sql_connect"; + +$dbinfo=null; +$dbuser=getenv("APPNAME"); +$dbtype=getenv("DB_TYPE"); +$dbname=getenv("DB_NAME"); +$dbhost=getenv("DB_HOST"); +$dbport=getenv("DB_PORT"); +switch($dbtype) { +case 'MYSQL' : + $dbinfo=new devsql("mysql",$dbhost,$dbname,$dbuser); + break; + case 'POSTGRESQL' : + $dbinfo=new devsql("pgsql",$dbhost,$dbname,$dbuser); + break; + default : + unset($dbinfo); + $daterr="Connect Database, type <".$dbtype."> is unexpected!"; + throw new ErrorException($daterr); + break; +} +rou_alert(0,"$OPEP connect to database"); +return $dbinfo; +} + +//============================================================== +// +// To close database acces previously access +// +//============================================================== +function sql_close(devsql $dbinfo) + +{ +$OPEP="devsql.php, sql_close"; + +rou_alert(0,"$OPEP JMPDBG disconnect database"); +$dbinfo->connection=NULL; +} + +//============================================================== +// +// To do a SQL query to database +// +//============================================================== +function sql_query($conn,$reqst) + +{ +$dbtype=getenv("DB_TYPE"); +} + +//============================================================== +// +// Function to return the number of record within a +// database table. +// +//============================================================== +function sql_getnumrec($dbsql,$select,$table) + +{ +$OPEP="gessql.php:sql_getnumrec"; + +$recnum=NULL; +if ($dbsql!=NULL) { + $stmt=$dbsql->Select("Select count(*) from $table $select"); + $recnum=$stmt->fetchColumn(); + } +return $recnum; +} + +?> diff --git a/www/directives.js b/www/directives.js new file mode 100644 index 0000000..89d557f --- /dev/null +++ b/www/directives.js @@ -0,0 +1,6 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab + +//============================================================== +//all system functions +//============================================================== + diff --git a/www/exetbl.php b/www/exetbl.php new file mode 100644 index 0000000..83a7faa --- /dev/null +++ b/www/exetbl.php @@ -0,0 +1,12 @@ +require_once 'TableFilter.php'; +$pdo = new PDO("pgsql:host=localhost;dbname=mailleur","mailleur","mailleurpass", [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION +]); + +$filter = new TableFilter($pdo, "actions", ["remoteip","reverse","creation"]); + +// Exemple simple : +$rows = $filter->fetchFiltered(["remoteip","reverse"], "localhost", 20); + +// Ensuite ton PHP construit son HTML/JS à partir de $rows + diff --git a/www/gesdis.php b/www/gesdis.php new file mode 100644 index 0000000..b1b4575 --- /dev/null +++ b/www/gesdis.php @@ -0,0 +1,218 @@ + + + + + +EOT; +$click1=""; +$click2=""; +$click3=""; +$admcolor="black"; +if ($isadmin==true) + $admcolor="red"; +switch ($pageref) { + case "lvllog" : + $sellang=""; + break; + case "lvlmai" : + $entete="Email management"; + $out="Logout"; + if ($isadmin==true) { + $remotes="SMTP servers"; + $users="Users management"; + $click1="$remotes"; + $click2="$users"; + } + $click3="$out"; + break; + case "lvlusr" : + $entete="Users management"; + //$entete=gettranslate($userlang,"User Management"); + $main="Email management"; + $out="Logout"; + $click2="$main"; + $click3="$out"; + break; + case "lvlrmt" : + $entete="SMTP servers"; + $main="Email management"; + $out="Logout"; + $click2="$main"; + $click3="$out"; + break; + default : + $color="red"; + $data="???"; + break; + } + +$STR = << + + + + + +
+ +mailbox + + +$entete +
+
+ + + + + +
+ $sellang + $logname + + + + + + + +
+

+ $click1 +

+
+

+ $click2 +

+
+

+ $click3 +

+
+
+
+EOT; + +return $STR; +} + +//============================================================== +// +// To display screen footer +// +//============================================================== +function footer($pageref) + +{ +include "release.php"; + +$today=date("Y, D M d H:i:s T"); + +$dbtype=getenv("DB_TYPE"); +$sql="unknown"; +switch($dbtype) { + case 'MYSQL' : + $sql="mysql"; + break; + case 'POSTGRESQL' : + $sql="pgsql"; + break; + default : + $sql="undefined"; + break; +} + +$STR = << + + + + + + +
+Version: $m_release-$sql, ($pageref) + +$copyright + +$today +
+
+ +EOT; + +return $STR; +} + +//============================================================== +// +// To generate the HTML starter +// +//============================================================== +function starthtml() + +{ +$theme="light"; +$curtime=time(); //Loading time stamp + +$STR = << + + + +Mailleur WEB Interface + + + +EOT; + +return $STR; +} + +//============================================================== +// +// To generate the HTML end +// +//============================================================== +function endhtml() + +{ +$curtime=time(); //Loading time stamp + +$STR = << + + + + + +EOT; + +return $STR; +} + +?> diff --git a/www/gessql.php b/www/gessql.php new file mode 100644 index 0000000..017cc0f --- /dev/null +++ b/www/gessql.php @@ -0,0 +1,337 @@ +db = sql_connect(); + $this->table = $table; + $this->limit = $limit; + $this->offset = $offset; + } + + // protecting data format + public function quote($value) { + return $this->db->quote($value); + } + /** + * Add the release function + **/ + public function release(): void { + if ($this->db !== NULL) { + sql_close($this->db); + } + } + + /** + * Add a WHERE condition + **/ + public function where(string $datawhere): self { + + $this->where = $datawhere; + return $this; + } + + /** + * Set ORDER BY clause + **/ + public function order(string $order): self { + + $this->order = $order; + return $this; + } + + /** + * Set LIMIT for pagination + **/ + public function limit(int $n): self { + + $this->limit = $n; + return $this; + } + + /** + * Set Column selection + **/ + public function columns(array $cols): self { + $this->columns = implode(', ', $cols); + return $this; + } + + /** + * Execute the query and return results + */ + public function get(): array { + + $sql = "SELECT " . ($this->columns ?? "*") . " FROM {$this->table}"; + if ($this->where) { + $sql .= " WHERE {$this->where}"; + } + + if ($this->order) { + $sql .= " ORDER BY {$this->order}"; + } + + if ($this->limit !== null) { + $sql .= " LIMIT {$this->limit}"; + } + + if ($this->offset > 0) { + $sql .= " OFFSET {$this->offset}"; + } + + rou_alert(0,"$this->OPEP, JMPDBG rqst sql=<$sql>"); + $stmt = $this->db->Select($sql); + return $stmt->fetchAll(); + } + + /** + * Count total number of items matching the current WHERE conditions + */ + public function getnumrec(): int { + + $sql = "SELECT COUNT(*) AS cnt FROM {$this->table}"; + + if ($this->where) { + $sql .= " WHERE {$this->where}"; + } + + $stmt = $this->db->Select($sql); + $row = $stmt->fetch(); + return (int) $row['cnt']; + } + + /** ----------------------------- **/ + /** Pagination / navigation **/ + /** ----------------------------- **/ + + /** + * Move offset to next page + * Does NOT fetch data + */ + public function goNext(): int { + + if ($this->limit !== null) { + $last=max($this->getnumrec(),$this->limit); + $this->offset = min($last-$this->limit,$this->offset+$this->limit); + } + return $this->offset; + } + + /** + * Move offset to previous page + * Does NOT fetch data + */ + public function goPrevious(): int { + + if ($this->limit !== null) { + $this->offset = max(0, $this->offset - $this->limit); + } + return $this->offset; + } + + /** + * Move offset to first page + * Does NOT fetch data + */ + public function goFirst(): int { + + $this->offset = 0; + return $this->offset; + } + + /** + * Move offset to last page + * Does NOT fetch data + */ + public function goLast(): int { + + if ($this->limit !== null) { + $total = $this->getnumrec(); + $this->offset = max(0, $total - $this->limit); + } + return $this->offset; + } + + /** + * Get current offset value + */ + public function getOffset(): int { + + return $this->offset; + } +} + +//============================================================== +// +// Function to check if password is the right one +// +//============================================================== +function sql_checkpassword($dbsql,$logname,$password) + +{ +$OPEP="gessql.php:sql_checkpassword"; + +$isgood=false; +$phase=0; +$proceed=true; +while ($proceed==true) { + //rou_alert(0,"$OPEP, JMPDBG phase=$phase"); + switch ($phase) { + case 0 : //do we have both logname and password + if ($logname=="" || $password=="") { + rou_alert(0,"$OPEP, logname=<$logname> or password=<$password> missing!"); + $phase=999; //trouble trouble + } + break; + case 1 : //extracting crypted password + $stmt=$dbsql->Select("Select * from emails where email='$logname'"); + $dbpass=$stmt->fetch(PDO::FETCH_ASSOC)['password']; + if ($dbpass==NULL) { //is user known? + rou_alert(0,"$OPEP, logname=<$logname> missing from database"); + $phase=999; //user unknown, trouble trouble + } + break; + case 2 : //'computing' crypted password + $idpass=$dbpass; + $ptr=strrchr($idpass,'$'); + if ($ptr!=NULL) + $idpass=substr($idpass,0,strlen($idpass)-strlen($ptr)+1); + $coded=crypt($password,$idpass); + if (strcmp($dbpass,$coded)!=0) { + rou_alert(0,"$OPEP, user=<$logname> wrong password=<$password>"); + $phase=999; //bad password + } + break; + case 3 : //everything fine + $random=(string)rand(0,9999999); + $uniqid=uniqid("",true); + $delay=time()+(24*3600); + $limit=date("Y-m-d H:i:s",$delay); + setcookie(getenv("APPNAME"),"$random$uniqid",$delay,"/"); + $fields="cookuuid,email,expire"; + $values="'$random$uniqid','$logname','$limit'"; + $dbsql->Insert("Insert into cookies ($fields) values ($values)"); + $isgood=true; + break; + default : //SAFE Guard + $proceed=false; + break; + } + $phase++; + } +return $isgood; +} + +//============================================================== +// +// Function to get a log name if a cookie is available +// +//============================================================== +function sql_setlogname($dbsql) + +{ +global $isadmin; +global $logname; +global $userlang; +global $dislang; + +$OPEP="gessql.php:sql_setlogname"; + +$isadmin=0; +$logname=NULL; +$expire=NULL; +$cookie=NULL; +$phase=0; +$proceed=true; +while ($proceed==true) { + //rou_alert(0,"$OPEP, JMPDBG phase=$phase"); + switch ($phase) { + case 0 : //do we have a cookie + if (isset($_COOKIE[getenv("APPNAME")])==0) + $phase=999; + break; + case 1 : //is the cookie within database + $cookie=$_COOKIE[getenv("APPNAME")]; + $cookie=htmlspecialchars($cookie); + $stmt=$dbsql->Select("Select * from cookies where cookuuid='$cookie'"); + $expire=$stmt->fetch(PDO::FETCH_ASSOC)['expire']; + if ($expire==null) { + rou_alert(0,"$OPEP, cookie <$cookie> expire not found in DB!"); + $phase=999; + } + break; + case 2 : //checking if cookie expired + $texpire=strtotime($expire); + if (time()>$texpire) { + rou_alert(0,"$OPEP, cookie <$cookie> time limite"); + $phase=999; + } + break; + case 3 : //extracting logname + $stmt=$dbsql->Select("Select * from cookies where cookuuid='$cookie'"); + $logname=$stmt->fetch(PDO::FETCH_ASSOC)['email']; + if ($logname==NULL) { //is user known? + rou_alert(0,"$OPEP, cookie <$cookie> not found in DB"); + $phase=999; + } + break; + case 4 : //getting user information + $stmt=$dbsql->Select("Select * from emails where email='$logname'"); + if ($stmt==NULL) { //is user really known? + rou_alert(0,"$OPEP, cookie but user <$logname> missing from DB?"); + $logname=NULL; + $phase=999; + } + break; + case 5 : //getting user working language + $dislang="en"; + $language=$stmt->fetch(PDO::FETCH_ASSOC)['lang']; + rou_alert(0,"$OPEP, JMPDBG langage=$language"); + if ($language!=NULL) { + switch ($language) { + case "FRA" : + $dislang="fr"; + break; + case "ENG" : + default : //NO BREAK + break; + } + } + break; + case 6 : //checking if logname is an admin + $stmt=$dbsql->Select("Select * from admins where email='$logname'"); + $id=$stmt->fetch(PDO::FETCH_ASSOC)['email']; + if ($id!=NULL) + $isadmin=true; + break; + default : //SAFE Guard + $proceed=false; + break; + } + $phase++; + } +rou_alert(0,"$OPEP, now logname=<$logname>"); +} + +?> diff --git a/www/index.php b/www/index.php new file mode 120000 index 0000000..336b484 --- /dev/null +++ b/www/index.php @@ -0,0 +1 @@ +lvllog.php \ No newline at end of file diff --git a/www/lvllog.php b/www/lvllog.php new file mode 100644 index 0000000..b8317c3 --- /dev/null +++ b/www/lvllog.php @@ -0,0 +1,141 @@ + + + + + Authentication + + + + + + + + +
+
+ + + + + + + + + + +
Email: + + +
Password: + + + Show +
+ + + + + +
+ + + + + +
+ +
+
+
+
+ + + +
+
+ +EOT; + +return $STR; +} + +//============================================================== +// +// To display login screen body +// +//============================================================== +function body() + +{ +global $isadmin; + +$start=starthtml(); +$stop=endhtml(); +$top=topper($isadmin,NULL,"lvllog"); +$footer=footer("lvllog"); +$login=login(); + +$STR = <<"; + echo "alert('wrong username or password. Please try again.');"; + echo ""; + break; + default : + header('Location: lvlmai.php'); + break; + } + } + +//display main screen +echo body(); +?> + + + diff --git a/www/lvlmai.php b/www/lvlmai.php new file mode 100644 index 0000000..7b174e0 --- /dev/null +++ b/www/lvlmai.php @@ -0,0 +1,344 @@ + [], // on remplira plus tard + 'search' => $_POST['search'] ?? '' + ]); + + exit; // <<< CRITIQUE +} + +include_once "subrou.php"; +include_once "unienv.php"; +include_once "gesdis.php"; +include_once "gessql.php"; + +// Defining the application name +global $myfilename; +$myfilename="lvlmai"; + +//============================================================== +// Table header generation +//============================================================== +function tblheader(string $dsearch,int $numrec,int $offset,int $limit, string $selectedField) + +{ +global $userlang; +global $myfilename; + +$filterOptions = [ + 'smtpfrom' => 'Originator', + 'rcptto' => 'Recipient', + 'creation' => 'Date', + ]; + +$optionsHtml = ''; + +foreach ($filterOptions as $value => $trkey) { + $selected = ($selectedField === $value) ? ' selected' : ''; + + $optionsHtml .= + ''; +} +error_log($optionsHtml); + +$dsearchHtml = htmlspecialchars($dsearch,ENT_QUOTES|ENT_SUBSTITUTE); + +$debut=$offset+1; +$STR = << + + +
+ + + + + + + +$debut/$numrec +
+ + +
+ + Search + + + +
+ + +
+ + + + +
+ + + +EOT; + +return $STR; +} + +//============================================================== +// Main screen body generation +//============================================================== +function body($logname) + +{ +global $userlang; +global $isadmin; +global $myfilename; + +$limit=20; +$offset=0; +$dsearch=""; +$selectedField = 'rcptto'; + + +if (isset($_POST['limit'])) + $limit=intval($_POST['limit']); +if (isset($_POST['offset'])) + $offset=intval($_POST['offset']); + +$rqst = new probe("actions",$limit,$offset); + +if (isset($_POST['columns']) && is_array($_POST['columns'])) { + $cols = $_POST['columns']; // conserver tableau tel quel + $rqst->columns($cols); +} + +if (isset($_POST['dsearch'])) { + $dsearch=trim($_POST['dsearch']); + if (strlen($dsearch)>0) { + // sécuriser le champ sélectionné + $allowedFields = ['smtpfrom','rcptto','creation']; + if (!in_array($selectedField,$allowedFields)) + $selectedField = 'rcptto'; + + // filtrage selon le champ choisi + $safeSearch = $rqst->quote('%' . $dsearch . '%'); + if ($selectedField === 'creation') { + // pour la date, on peut filtrer par LIKE + $rqst->where("$selectedField::text LIKE $safeSearch"); + } + else { + $rqst->where("$selectedField LIKE $safeSearch"); + } + } +} + +$numrec=$rqst->getnumrec(); + +if (isset($_POST['scanner'])) { + $scanner=$_POST['scanner']; + switch ($scanner) { + case "golast" : + $offset=$rqst->goLast(); + break; + case "gonext" : + $offset=$rqst->goNext(); + break; + case "goprevious" : + $offset=$rqst->goPrevious(); + break; + case "gofirst" : + $offset=$rqst->goFirst(); + break; + default : + break; + } + } + +$actions=$rqst->order("creation desc") + ->limit($limit) + ->GET(); + +if (!is_array($actions)) { + $actions = []; + } + +if(isset($_POST['ajax']) && $_POST['ajax'] == 1) { + header('Content-Type: application/json'); + echo json_encode([ + 'rows' => $actions, + 'search' => $dsearch + ]); + exit; // très important pour ne pas générer le reste de la page + } + + +$line=""; +$count=$offset+1; +foreach($actions as $action) { + $info=substr($action['info'],3,1); + $status=$action['status']; + $subject=htmlspecialchars($action['subject'],ENT_QUOTES); + if (($subject==NULL) || (strlen($subject)==0)) + $subject=htmlspecialchars($action['info'],ENT_QUOTES); + switch ($status) { + case 250: + $bgcolor="#90EE90"; + break; // light green + case 460: + $bgcolor="#ff6666"; + $subject=htmlspecialchars($action['info'],ENT_QUOTES); + break; // light red + case 551: + $bgcolor="#FF7F50"; + break; // coral + case 555: + $bgcolor="#D3D3D3"; + break; // light gray + default: + $bgcolor="yellow"; + break; + } + $date=$action['creation']; + $reverse=$action['reverse']; + $remoteip=$action['remoteip']; + $smtpfrom=$action['smtpfrom']; + $recipient=$action['rcptto']; + $emailfrom=htmlspecialchars($action['emailfrom'],ENT_QUOTES); + + // Generating the table contents + $line .= "\r\n"; + $line .= "$count\r\n"; + $line .= "$status\r\n"; + $line .= "$date\r\n"; + $line .= "$remoteip\r\n"; + $line .= "$reverse\r\n"; + $line .= "$smtpfrom
$emailfrom\r\n"; + $line .= "$recipient\r\n"; + $line .= "$subject\r\n"; + $line .= "\r\n"; + + $count++; + } + +//connection to database not needed anymore +$rqst->release(); +unset($rqst); + +$start=starthtml(); +$stop=endhtml(); +$top=topper($isadmin,$logname,"$myfilename"); +$footer=footer("$myfilename"); +$tblheader=tblheader($dsearch,$numrec,$offset,$limit,$selectedField); +$tblfooter=""; +if ($limit>30) + $tblfooter=$tblheader; + +$STR = << +$tblheader + + + + + + + + + + + + + + +$line + +
Num +Status + +Date + +IP + +Reverse IP + +Originator + +Recipient + +Subject +
+$tblfooter + +
+$footer +$stop +EOT; + +return $STR; +} + +//============================================================== +// Script execution +//============================================================== +global $logname; + +rou_openlog(); + +$dbsql=sql_connect(); +sql_setlogname($dbsql); +sql_close($dbsql); + +if ($logname!=NULL) { + echo body($logname); + } +else { + header('Location: lvllog.php'); + } +rou_closelog(); +?> + diff --git a/www/lvlrmt.php b/www/lvlrmt.php new file mode 100644 index 0000000..478ce91 --- /dev/null +++ b/www/lvlrmt.php @@ -0,0 +1,220 @@ + + + +
+ + + + + + + +$debut/$numrec +
+ + +
+ +Search + + + +
+ + +
+ + + + +
+ + + +EOT; + +return $STR; +} + +//section to generate the main screen body +function body($logname) + +{ +$OPEP="lvlrmt.php:body"; + +global $isadmin; +global $logname; + +$limit=20; +$offset=0; +$remoteip=""; +if (isset($_POST['limit'])) + $limit=intval($_POST['limit']); +if (isset($_POST['offset'])) + $offset=intval($_POST['offset']); + +$rqst=NEW probe("remotes",$limit,$offset); + +if (isset($_POST['remoteip'])) { + $remoteip=trim(($_POST['remoteip'])); + if (strlen($remoteip)>0) + $rqst->where("remoteip like '%$remoteip%'"); + } +$numrec=$rqst->getnumrec(); + +if (isset($_POST['scanner'])) { + $scanner=$_POST['scanner']; + switch ($scanner) { + case "golast" : + $offset=$rqst->goLast(); + break; + case "gonext" : + $offset=$rqst->goNext(); + break; + case "goprevious" : + $offset=$rqst->goPrevious(); + break; + case "gofirst" : + $offset=$rqst->goFirst(); + break; + default : + break; + } + } +$remotes=$rqst->order("remoteip asc") + ->limit($limit) + ->get(); +$line=""; +$count=$offset; +foreach($remotes as $remote) { + $count++; + $bgcolor="white"; + if ($count & 1 ) { + $bgcolor="green"; + } + $ip=$remote['remoteip']; + $reverse=$remote['reverse']; + $last=$remote['lastupdate']; + $credit=$remote['credit']; + $line=$line."\r\n"; + $line=$line."$count \r\n"; + $line=$line."\r\n"; + $line=$line." $ip\r\n"; + $line=$line."\r\n"; + $line=$line."$reverse\r\n"; + $line=$line."$last\r\n"; + $line=$line."$credit\r\n"; + $line=$line.""; + } +//connection to database not needed anymore +$rqst->release(); +unset($rqst); + +rou_closelog(); + +$start=starthtml(); +$stop=endhtml(); +$top=topper($isadmin,$logname,"lvlrmt"); +$footer=footer("lvlrmt"); +$tblheader=tblheader($remoteip,$numrec,$offset,$limit); +$tblfooter=""; +if ($limit>30) + $tblfooter=$tblheader; + +$STR = << +.table-userlist tr:nth-child(odd) + { + background-color: #66ff99; /*light green */ + color: black ; + } + +.table-userlist tr:nth-child(even) + { + background-color: white; + color: black ; + } + + +
+$tblheader + + + + + + + +$line +
IPReverselastemailcredit
+$tblfooter +
+
+
+$footer +$stop +EOT; + +return $STR; +} + +rou_openlog(); +$dbsql=sql_connect(); +sql_setlogname($dbsql); +sql_close($dbsql); + +if ($logname!=NULL) { + echo body($logname); + } +else { + header('Location: lvllog.php'); + } +rou_closelog(); +?> + + + diff --git a/www/lvlusr.php b/www/lvlusr.php new file mode 100644 index 0000000..616d09e --- /dev/null +++ b/www/lvlusr.php @@ -0,0 +1,217 @@ + + + +
+ + + + + + + +$debut/$numrec +
+ + +
+ +Search + + + +
+ + +
+ + + + +
+ + + +EOT; + +return $STR; +} + +//section to generate the main screen body +function body($logname) + +{ +$OPEP="lvlusr.php:body"; + +global $isadmin; +global $logname; + +$limit=20; +$offset=0; +$username=""; +if (isset($_POST['limit'])) + $limit=intval($_POST['limit']); +if (isset($_POST['offset'])) + $offset=intval($_POST['offset']); +$rqst=NEW probe("emails",$limit,$offset); +if (isset($_POST['username'])) { + $username=trim(($_POST['username'])); + if (strlen($username)>0) + $rqst->where("email like '%$username%'"); + } +$numrec=$rqst->getnumrec(); +if (isset($_POST['scanner'])) { + $scanner=$_POST['scanner']; + switch ($scanner) { + case "golast" : + $offset=$rqst->goLast(); + break; + case "gonext" : + $offset=$rqst->goNext(); + break; + case "goprevious" : + $offset=$rqst->goPrevious(); + break; + case "gofirst" : + $offset=$rqst->goFirst(); + break; + default : + break; + } +} +$emails=$rqst->order("email asc") + ->limit($limit) + ->get(); +$line=""; +$count=$offset; +foreach($emails as $email) { + $count++; + $bgcolor="white"; + if ($count & 1 ) { + $bgcolor="green"; + } + $name=$email['email']; + $last=$email['lastemail']; + $max=$email['mxspace']; + $lock=$email['locked']; + $line=$line."\r\n"; + $line=$line."$count \r\n"; + $line=$line."\r\n"; + $line=$line." $name\r\n"; + $line=$line."\r\n"; + $line=$line."$last\r\n"; + $line=$line."$max\r\n"; + $line=$line."$lock\r\n"; + $line=$line.""; + } +//connection to database not needed anymore +$rqst->release(); +unset($rqst); + +$start=starthtml(); +$stop=endhtml(); +$top=topper($isadmin,$logname,"lvlusr"); +$footer=footer("lvlusr"); +$tblheader=tblheader($username,$numrec,$offset,$limit); +$tblfooter=""; +if ($limit>30) + $tblfooter=$tblheader; + +$STR = << +.table-userlist tr:nth-child(odd) + { + background-color: #66ff99; /*light green */ + color: black ; + } + +.table-userlist tr:nth-child(even) + { + background-color: white; + color: black ; + } + + +
+ +$tblheader +
+ + + + + + +$line +
Emaillastemailmxspacelocked
+$tblfooter +
+
+
+$footer +$stop +EOT; + +return $STR; +} + + +rou_openlog(); +$dbsql=sql_connect(); +sql_setlogname($dbsql); +sql_close($dbsql); + +if ($logname!=NULL) { + echo body($logname); + } +else { + header('Location: lvllog.php'); + } +rou_closelog(); +?> + + + diff --git a/www/passval.html b/www/passval.html new file mode 100644 index 0000000..3e5710b --- /dev/null +++ b/www/passval.html @@ -0,0 +1,153 @@ + + + + + + + + +

Password Validation

+

Try to submit the form.

+ +
+
+ + + + + + + +
+
+ +
+

Password must contain the following:

+

A lowercase letter

+

A capital (uppercase) letter

+

A number

+

Minimum 8 characters

+
+ + + + + diff --git a/www/reg-icons/Wwalczyszyn-Android-Style-Mail.96.png b/www/reg-icons/Wwalczyszyn-Android-Style-Mail.96.png new file mode 100644 index 0000000..9bf62b5 Binary files /dev/null and b/www/reg-icons/Wwalczyszyn-Android-Style-Mail.96.png differ diff --git a/www/reg-icons/folder.gif b/www/reg-icons/folder.gif new file mode 100644 index 0000000..4826460 Binary files /dev/null and b/www/reg-icons/folder.gif differ diff --git a/www/reg-icons/login.gif b/www/reg-icons/login.gif new file mode 100644 index 0000000..e131950 Binary files /dev/null and b/www/reg-icons/login.gif differ diff --git a/www/release.in b/www/release.in new file mode 100644 index 0000000..ca4995e --- /dev/null +++ b/www/release.in @@ -0,0 +1,13 @@ + diff --git a/www/release.php b/www/release.php new file mode 100644 index 0000000..488b832 --- /dev/null +++ b/www/release.php @@ -0,0 +1,13 @@ + diff --git a/www/res/chat.php b/www/res/chat.php new file mode 100644 index 0000000..fe1708f --- /dev/null +++ b/www/res/chat.php @@ -0,0 +1,106 @@ + + + + + +Tableau filtrable "super débile écoeurant" + + + + +

Recherche filtrable “Super, débile, écoeurante” 😎

+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + diff --git a/www/res/chat1.php b/www/res/chat1.php new file mode 100644 index 0000000..1c88c09 --- /dev/null +++ b/www/res/chat1.php @@ -0,0 +1,130 @@ + + + + + +Tableau Filtrable Ultime 😎 + + + + +

Recherche “Ultime, Écoeurante, Joyeuse” 😎

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + diff --git a/www/res/chat2.php b/www/res/chat2.php new file mode 100644 index 0000000..796ba8a --- /dev/null +++ b/www/res/chat2.php @@ -0,0 +1,141 @@ +" . htmlspecialchars($field) . ""; + } + return $html; +} + +// Génération du HTML du corps +function generateTableBody(array $data): string { + $html = ''; + foreach ($data as $row) { + $html .= ""; + foreach ($row as $cell) { + $html .= "" . htmlspecialchars($cell) . ""; + } + $html .= ""; + } + return $html; +} + +// Injection des contenus dans des variables +$tableHeaderHTML = generateTableHeader($fields); +$tableBodyHTML = generateTableBody($data); +?> + + + + + +Tableau filtrable Super + + + + +

Tableau filtrable “Super”

+ + + + + + + + + + +
+ + + + + + diff --git a/www/res/chat3.php b/www/res/chat3.php new file mode 100644 index 0000000..9debfeb --- /dev/null +++ b/www/res/chat3.php @@ -0,0 +1,169 @@ +pdo = $pdo; + $this->table = $table; + $this->columns = $columns; + } + + public function fetchFiltered(array $selectedColumns, string $search, int $limit): array + { + if(empty($selectedColumns) || trim($search)===''){ + $sql = "SELECT * FROM {$this->table} ORDER BY creation DESC LIMIT :limit"; + $stmt = $this->pdo->prepare($sql); + $stmt->bindValue(':limit', $limit, PDO::PARAM_INT); + $stmt->execute(); + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } + + $whereParts = []; + $params = []; + foreach($selectedColumns as $i => $col){ + if(!in_array($col,$this->columns,true)) continue; + $whereParts[] = "$col ILIKE :s$i"; + $params[":s$i"] = "%$search%"; + } + $where = implode(" OR ", $whereParts); + $sql = "SELECT * FROM {$this->table} WHERE $where ORDER BY creation DESC LIMIT :limit"; + $stmt = $this->pdo->prepare($sql); + foreach($params as $k=>$v) $stmt->bindValue($k,$v); + $stmt->bindValue(':limit', $limit, PDO::PARAM_INT); + $stmt->execute(); + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } +} + +/* ======================================================= + Gestion AJAX + ======================================================= */ +if(php_sapi_name()!=='cli' && isset($_POST['search'])){ + header("Content-Type: application/json"); + $pdo = new PDO("pgsql:host=localhost;dbname=mailleur","mailleur","mailleurpass", + [PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]); + $filter = new TableFilter($pdo,"actions",["remoteip","reverse","creation"]); + $selected = $_POST["columns"]??[]; + $search = $_POST["search"]??""; + $limit = (int)($_POST["limit"]??20); + $data = $filter->fetchFiltered($selected,$search,$limit); + echo json_encode($data); + exit; +} + +/* ======================================================= + Page HTML + ======================================================= */ +$lang = $_GET["lang"]??"en"; +$labels = ["en"=>["Remote IP","Reverse","Creation"],"fr"=>["IP distante","Reverse","Création"]]; +$colKeys = ["remoteip","reverse","creation"]; +$L = $labels[$lang]; +?> + + + + +Bigre Super-DB Paginated JMP + + + + + +
+ +
+ + +
+ + +
+ + + + + + $label): ?> + + + + + +
+ + + + + + diff --git a/www/res/chat4.php b/www/res/chat4.php new file mode 100644 index 0000000..91da797 --- /dev/null +++ b/www/res/chat4.php @@ -0,0 +1,192 @@ +pdo = $pdo; + $this->table = $table; + $this->columns = $columns; + } + + public function fetchFiltered(array $selectedColumns, string $search, int $limit): array + { + if(empty($selectedColumns)) $selectedColumns = $this->columns; + + if(trim($search)===''){ + $sql = "SELECT * FROM {$this->table} ORDER BY creation DESC LIMIT :limit"; + $stmt = $this->pdo->prepare($sql); + $stmt->bindValue(':limit', $limit, PDO::PARAM_INT); + $stmt->execute(); + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } + + $whereParts = []; + $params = []; + foreach($selectedColumns as $i => $col){ + if(!in_array($col,$this->columns,true)) continue; + $key = ":s$i"; + $whereParts[] = "$col ILIKE $key"; + $params[$key] = "%$search%"; + } + + $where = implode(" OR ", $whereParts); + $sql = "SELECT * FROM {$this->table} WHERE $where ORDER BY creation DESC LIMIT :limit"; + $stmt = $this->pdo->prepare($sql); + + foreach($params as $k=>$v){ + $stmt->bindValue($k,$v,PDO::PARAM_STR); + } + $stmt->bindValue(':limit', $limit, PDO::PARAM_INT); + $stmt->execute(); + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } +} + +/* ======================================================= + Gestion AJAX + ======================================================= */ +if(php_sapi_name()!=='cli' && isset($_POST['search'])){ + header("Content-Type: application/json"); + $pdo = new PDO("pgsql:host=localhost;dbname=mailleur","mailleur","mailleurpass", + [PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]); + $filter = new TableFilter($pdo,"actions",["remoteip","reverse","creation"]); + + $selected = $_POST["columns"]??[]; + if(empty($selected)) $selected = ["remoteip","reverse","creation"]; + + $search = $_POST["search"]??""; + $limit = (int)($_POST["limit"]??20); + $data = $filter->fetchFiltered($selected,$search,$limit); + echo json_encode(["rows"=>$data,"search"=>$search]); + exit; +} + +/* ======================================================= + Page HTML + ======================================================= */ +$lang = $_GET["lang"]??"en"; +$labels = ["en"=>["Remote IP","Reverse","Creation"],"fr"=>["IP distante","Reverse","Création"]]; +$colKeys = ["remoteip","reverse","creation"]; +$L = $labels[$lang]; +?> + + + + +Super-DB Paginated Highlight + + + + + +
+ +
+ + +
+ + +
+ + + + + + $label): ?> + + + + + +
+ + + + + + diff --git a/www/res/gestbl.php b/www/res/gestbl.php new file mode 100644 index 0000000..d64cf41 --- /dev/null +++ b/www/res/gestbl.php @@ -0,0 +1,75 @@ +gestbl.php + Generic and autonomous class to search an filter table + contents. + ======================================================= */ + +class TableFilter { + +private PDO $pdo; +private string $table; +private array $columns; +private int $limit; + +/** + * Constructor + * @param PDO $pdo PDO connection + * @param string $table Table name + * @param array $columns Columns available for filtering + **/ +public function __construct(PDO $pdo, string $table, array $columns) { + $this->pdo=$pdo; + $this->table=$table; + $this->columns=$columns; + $this->limit=20; + } + +/** + * Set LIMIT for extraction and filtering + **/ + +/** + * Fetch filtered rows from the table + * + * @param array $selectedColumns Columns to filter (subset of $this->columns) + * @param string $search Search text + * @param int $limit Number of rows to return + * @return array Associative array of rows + **/ +public function fetchFiltered(array $selectedColumns,string $search=''): array { + // If no columns selected, use all + if (empty($selectedColumns)) $selectedColumns = $this->columns; + + // If search is empty, just SELECT with LIMIT + if (trim($search) === '') { + $sql = "SELECT * FROM {$this->table} ORDER BY 1 LIMIT :limit"; + $stmt = $this->pdo->prepare($sql); + $stmt->bindValue(':limit', $this->limit, PDO::PARAM_INT); + $stmt->execute(); + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } + + // Build WHERE clause for multiple columns + $whereParts = []; + $params = []; + foreach ($selectedColumns as $i => $col) { + if (!in_array($col, $this->columns, true)) continue; + $key = ":s$i"; + $whereParts[] = "$col ILIKE $key"; + $params[$key] = "%$search%"; + } + $where = implode(" OR ", $whereParts); + // Prepare and execute statement + $sql = "SELECT * FROM {$this->table} WHERE $where ORDER BY 1 LIMIT :limit"; + $stmt = $this->pdo->prepare($sql); + foreach ($params as $k => $v) { + $stmt->bindValue($k, $v, PDO::PARAM_STR); + } + $stmt->bindValue(':limit', $this->limit, PDO::PARAM_INT); + $stmt->execute(); + // Return associative array + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } +} + diff --git a/www/res/unilng.php b/www/res/unilng.php new file mode 100644 index 0000000..6029e83 --- /dev/null +++ b/www/res/unilng.php @@ -0,0 +1,27 @@ + diff --git a/www/res/unimar.php b/www/res/unimar.php new file mode 100644 index 0000000..a508534 --- /dev/null +++ b/www/res/unimar.php @@ -0,0 +1,34 @@ + diff --git a/www/res/unipos.php b/www/res/unipos.php new file mode 100644 index 0000000..f8c0856 --- /dev/null +++ b/www/res/unipos.php @@ -0,0 +1,68 @@ +connection = new PDO("mysql:host={$dbhost};dbname={$dbname};",$username); + $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->connection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); + } + + // Insert a row/s in a Database Table + public function Insert() { + } + + // Select a row/s in a Database Table + public function Select() { + } + + // Update a row/s in a Database Table + public function Update( ) { + } + + // Remove a row/s in a Database Table + public function Remove( ) { + } + + // execute statement + private function executeStatement( ){ + } + + } + +//============================================================== +// To connect to a local/remote POSTGRESQL database +//============================================================== +function pos_connect($dbhost,$dbusr,$dbname,$dbport) + +{ +$OPEP="unipop.php, pos_connect"; + +$seq="host=$dbhost user=$dbusr dbname=$dbname port=$dbport"; +$conn=pg_connect($seq); +return $conn; +} + + +//============================================================== +// To disconnect from a local/remote POSTGRESQL database +//============================================================== +function pos_close(PgSql\Connection $sqlptr) + +{ +$OPEP="unipos, pos_close"; + +pg_close($sqlptr); +unset($sqlptr); +return 0; +} +?> + diff --git a/www/selectajax.js b/www/selectajax.js new file mode 100644 index 0000000..62fbe86 --- /dev/null +++ b/www/selectajax.js @@ -0,0 +1,87 @@ +/*! + * selectajax.js + * + * Handles AJAX POST for column selection and search, + * updates the HTML table dynamically in lvlmai.php. + * + * Dependencies: none (vanilla JS) + * + * Main contributor: Chap, ID-20251216-001 + */ + +document.addEventListener('DOMContentLoaded', function() { + + const form = document.getElementById('searchForm'); + if (!form) return; // safety if form is missing + + form.addEventListener('submit', function(e) { + e.preventDefault(); // prevent page reload + + const formData = new FormData(form); + formData.set('ajax', '1'); + + // Safety retry mechanism to wait for DOM readiness + const maxRetries = 20; + let retryCount = 0; + + function sendFetch() { + fetch('lvlmai.php', { method: 'POST', body: formData }) + .then(resp => resp.json()) + .then(data => { + const headerRow = document.getElementById('headerRow'); + const bodyRows = document.getElementById('bodyRows'); + + if (!headerRow || !bodyRows) { + if (retryCount < maxRetries) { + retryCount++; + console.warn(`DOM not ready yet, retry ${retryCount}`); + setTimeout(sendFetch, 100); // retry after 100ms + } else { + console.error("headerRow or bodyRows not found after max retries"); + } + return; + } + + // Clear previous table content + //headerRow.innerHTML = ''; + bodyRows.innerHTML = ''; + + if (!data || !data.rows || data.rows.length === 0) return; + + // Dynamic headers + //Object.keys(data.rows[0]).forEach(col => { + // const th = document.createElement('th'); + // th.textContent = col; + // headerRow.appendChild(th); + //}); + + // Table rows + data.rows.forEach(row => { + const tr = document.createElement('tr'); + Object.values(row).forEach(val => { + const td = document.createElement('td'); + td.textContent = val ?? ''; // handle nulls + tr.appendChild(td); + }); + bodyRows.appendChild(tr); + }); + + console.log("JMPDBG data:", data); + + // Dispatch event for other scripts (translations, color, sorting) + document.dispatchEvent(new CustomEvent('tableDataUpdated', { + detail: { + rowsCount: data.rows.length, + search: data.search ?? '' + } + })); + + }) + .catch(err => console.error('AJAX Error:', err)); + } + + sendFetch(); + }); + +}); + diff --git a/www/selectajax.js.ang b/www/selectajax.js.ang new file mode 100644 index 0000000..3791aed --- /dev/null +++ b/www/selectajax.js.ang @@ -0,0 +1,88 @@ +/** + * selectajax.js + * + * Handles AJAX POST for column selection and search input, + * then dynamically updates the HTML table in lvlmai.php. + * + * Dependencies: vanilla JS only + * + * Main contributor: Chap, iteration-ref: 20251216-001 + * + * Usage: include this script at the end of the HTML body to ensure DOM readiness. + */ + +function initSelectAjax(retryCount = 0) { + const maxRetries = 20; // maximum retry attempts if DOM not ready + + const form = document.getElementById('searchForm'); + const headerRow = document.getElementById('headerRow'); + const bodyRows = document.getElementById('bodyRows'); + + if (!form || !headerRow || !bodyRows) { + if (retryCount < maxRetries) { + console.log("initSelectAjax: DOM not ready, retry #" + (retryCount + 1)); + setTimeout(() => initSelectAjax(retryCount + 1), 100); // wait 100ms + } else { + console.error("initSelectAjax: DOM elements not found after max retries"); + } + return; + } + + form.addEventListener('submit', function(e) { + e.preventDefault(); // prevent page reload + + const formData = new FormData(form); + formData.set('ajax', '1'); + + fetch('lvlmai.php', { + method: 'POST', + body: formData + }) + .then(resp => resp.text()) + .then(text => { + console.log("Raw response:", text); + try { + return JSON.parse(text); + } catch(err) { + console.error("Failed to parse JSON:", err); + throw err; + } + }) + .then(data => { + if (!data.rows) { + console.error("No 'rows' in response data"); + return; + } + + // Clear previous table content + headerRow.innerHTML = ''; + bodyRows.innerHTML = ''; + + // Populate table header dynamically + const keys = Object.keys(data.rows[0]); + keys.forEach(col => { + const th = document.createElement('th'); + th.textContent = col; + headerRow.appendChild(th); + }); + + // Populate table body + data.rows.forEach(row => { + const tr = document.createElement('tr'); + keys.forEach(key => { + const td = document.createElement('td'); + td.textContent = row[key]; + tr.appendChild(td); + }); + bodyRows.appendChild(tr); + }); + + console.log("Table updated with", data.rows.length, "rows"); + }) + .catch(err => console.error("AJAX error:", err)); + }); +} + +// Initialize after script load +document.addEventListener('DOMContentLoaded', initSelectAjax); + diff --git a/www/selectajax.js.bad b/www/selectajax.js.bad new file mode 100644 index 0000000..8920fd5 --- /dev/null +++ b/www/selectajax.js.bad @@ -0,0 +1,67 @@ +document.addEventListener('DOMContentLoaded', function() { + + const form = document.getElementById('searchForm'); + if (!form) return; + + form.addEventListener('submit', function(e) { + e.preventDefault(); + + const formData = new FormData(form); + formData.set('ajax', '1'); + + fetch('lvlmai.php', { + method: 'POST', + body: formData + }) + .then(response => { + if (!response.ok) { + throw new Error("HTTP error " + response.status); + } + return response.json(); // 🔴 ÉTAPE MANQUANTE + }) + .then(data => { + + console.log("JMPDBG data:", data); + + if (!data.rows) { + console.error("No data.rows in response"); + return; + } + + const headerRow = document.getElementById('headerRow'); + const bodyRows = document.getElementById('bodyRows'); + + if (!headerRow || !bodyRows) { + console.error("thead or tbody not found"); + return; + } + + headerRow.innerHTML = ''; + bodyRows.innerHTML = ''; + + console.log("JMPDBG rows:", data.rows.length); + + if (data.rows.length === 0) return; + + // Headers + Object.keys(data.rows[0]).forEach(col => { + const th = document.createElement('th'); + th.textContent = col; + headerRow.appendChild(th); + }); + + // Rows + data.rows.forEach(row => { + const tr = document.createElement('tr'); + Object.values(row).forEach(val => { + const td = document.createElement('td'); + td.textContent = val ?? ''; + tr.appendChild(td); + }); + bodyRows.appendChild(tr); + }); + }) + .catch(err => console.error("AJAX error:", err)); + }); +}); + diff --git a/www/selectajax.js.fra b/www/selectajax.js.fra new file mode 100644 index 0000000..3489907 --- /dev/null +++ b/www/selectajax.js.fra @@ -0,0 +1,64 @@ +function initSelectAjax(retryCount = 0) { + const maxRetries = 20; // nombre maximum de tentatives + const form = document.getElementById('searchForm'); + const headerRow = document.getElementById('headerRow'); + const bodyRows = document.getElementById('bodyRows'); + + if (!form || !headerRow || !bodyRows) { + if (retryCount < maxRetries) { + console.warn(`DOM incomplet, réessai ${retryCount + 1}/${maxRetries} dans 100ms...`); + setTimeout(() => initSelectAjax(retryCount + 1), 100); + } else { + console.error("Échec d'initialisation AJAX : DOM incomplet après 20 tentatives"); + } + return; + } + + form.addEventListener('submit', function(e) { + e.preventDefault(); + + const formData = new FormData(form); + formData.set('ajax', '1'); + + fetch('lvlmai.php', { method: 'POST', body: formData }) + .then(resp => resp.text()) + .then(text => { + console.log("Réponse brute :", text); + try { + return JSON.parse(text); + } catch(err) { + console.error("Erreur parsing JSON :", err, text); + throw err; + } + }) + .then(data => { + headerRow.innerHTML = ''; + bodyRows.innerHTML = ''; + + if (!data.rows || data.rows.length === 0) return; + + // en-têtes + Object.keys(data.rows[0]).forEach(col => { + const th = document.createElement('th'); + th.textContent = col; + headerRow.appendChild(th); + }); + + // lignes + data.rows.forEach(row => { + const tr = document.createElement('tr'); + Object.values(row).forEach(val => { + const td = document.createElement('td'); + td.textContent = val ?? ''; + tr.appendChild(td); + }); + bodyRows.appendChild(tr); + }); + }) + .catch(err => console.error('Erreur AJAX:', err)); + }); +} + +// Appel sécurisé au chargement du DOM +document.addEventListener('DOMContentLoaded', () => initSelectAjax()); + diff --git a/www/subrou.php b/www/subrou.php new file mode 100644 index 0000000..139d148 --- /dev/null +++ b/www/subrou.php @@ -0,0 +1,43 @@ +=$dbglvl) + syslog(LOG_INFO,"dbg=$debug, $report"); +} + +rou_openlog(); +?> diff --git a/www/theme.css b/www/theme.css new file mode 100644 index 0000000..9419ea5 --- /dev/null +++ b/www/theme.css @@ -0,0 +1,66 @@ +/* theme.css */ + +/* ===================== + Light Theme (default) + ===================== */ +:root { + --bg-color: white; + --text-color: black; + + --highlight-bg: lightyellow; + --highlight-text: black; + + --filter-col-bg: lavender; + --filter-col-hover-bg: lightsteelblue; + --filter-col-active-bg: cornflowerblue; + --filter-col-text: darkblue; +} + +/* ===================== + Dark Theme + ===================== */ +.dark { + --bg-color: black; + --text-color: gainsboro; + + --highlight-bg: darkslategray; + --highlight-text: lightgoldenrodyellow; + + --filter-col-bg: dimgray; + --filter-col-hover-bg: slategray; + --filter-col-active-bg: steelblue; + --filter-col-text: lightblue; +} + +/* ===================== + Generic elements + ===================== */ +body { + background-color: var(--bg-color); + color: var(--text-color); + font-family: sans-serif; +} + +/* Column header behavior */ +.filter-col { + cursor: pointer; + color: var(--filter-col-text); + background-color: var(--filter-col-bg); +} + +/* Mouse hover on column header */ +.filter-col:hover { + background-color: var(--filter-col-hover-bg); +} + +/* Active (selected) column header */ +.filter-col.active { + background-color: var(--filter-col-active-bg); +} + +/* Highlighted table cells or rows */ +.highlight { + background-color: var(--highlight-bg); + color: var(--highlight-text); +} + diff --git a/www/theme2.css b/www/theme2.css new file mode 100644 index 0000000..60b9b3f --- /dev/null +++ b/www/theme2.css @@ -0,0 +1,52 @@ +/* theme.css */ + +/* ===================== + Light Theme (default) + ===================== */ +:root { + --bg-color: #ffffff; /* background color */ + --text-color: #000000; /* text color */ + --highlight-bg: #ff9; /* highlight background */ + --highlight-text: #000; /* highlight text color */ + --filter-col-bg: #f7f7ff; /* filter column background */ + --filter-col-active-bg: #cce; /* active filter column background */ + --filter-col-text: #003; /* filter column text color */ +} + +/* ===================== + Dark Theme + ===================== */ +.dark { + --bg-color: #1e1e1e; + --text-color: #e0e0e0; + --highlight-bg: #553333; + --highlight-text: #fff0b0; + --filter-col-bg: #333344; + --filter-col-active-bg: #5566aa; + --filter-col-text: #aaccff; +} + +/* ===================== + Generic elements using variables + ===================== */ +body { + background-color: var(--bg-color); + color: var(--text-color); + font-family: sans-serif; +} + +.filter-col { + cursor: pointer; + color: var(--filter-col-text); + background: var(--filter-col-bg); +} + +.filter-col.active { + background: var(--filter-col-active-bg); +} + +.highlight { + background: var(--highlight-bg); + color: var(--highlight-text); +} + diff --git a/www/translations.js b/www/translations.js new file mode 100644 index 0000000..4ad97c7 --- /dev/null +++ b/www/translations.js @@ -0,0 +1,90 @@ +// vim: smarttab tabstop=8 shiftwidth=2 expandtab + +//language table +const TR = + [ + ["Authentication", "Authentification"], + ["Date", "Date"], + ["Email", "Courriel"], + ["Email management","Gestion des courriers"], + ["Login", "Connexion"], + ["Logout", "Deconnexion"], + ["Main screen", "Ecran Principal"], + ["Originator", "Expediteur"], + ["Password", "Mot de passe"], + ["Recipient", "Destinataire"], + ["Reverse IP", "IP inversée"], + ["SMTP servers", "Serveurs SMTP"], + ["Search", "Recherche"], + ["Subject", "Sujet"], + ["Show", "Afficher"], + ["Status", "Statut"], + ["Users management","Gestion des usagers"], + [null, null] + ]; + +var translationMap = new Map(); + +// Building EN/FR dictionnaries +const translationEn = new Map(); +const translationFr = new Map(); + +for (const [en, fr] of TR) { + if (en === null) break; //detecting end of table + translationEn.set(en, en); + translationFr.set(en, fr); + } + +translationMap.set("en", translationEn); +translationMap.set("fr", translationFr); + +//============================================================== +//function to translate login screen +//============================================================== +function updateTranslations() + +{ +let translationLng = document.getElementById("first-choice").value; +let translatables = document.getElementsByClassName("translatable"); +let map = translationMap.get(translationLng); + +for (let i of translatables) { + let key = i.getAttribute("trkey") || i.parentElement.getAttribute("trkey"); + +// gestion si la clé n'existe pas + let value; + if (map.has(key)) { + value = map.get(key); + } + else { + console.warn(`Traduction manquante pour "${key}"`); + value = `${key}`; // valeur par défaut : le mot anglais + } + + if (i.tagName === 'INPUT') { + i.value = key; + } + else { + i.innerHTML = value; + } + } +} + +//============================================================== +//function to show password contents +//============================================================== +function showpass() + +{ +let datain=document.getElementById("myInput"); +if (datain.type==="password") { + datain.type="text"; + } +else { + datain.type="password"; + } +} + +//execute function at first display +updateTranslations(); +//============================================================== diff --git a/www/unienv.php b/www/unienv.php new file mode 100644 index 0000000..d2be85c --- /dev/null +++ b/www/unienv.php @@ -0,0 +1,57 @@ + is Missing!"); + $phase=999; //no need to go further + } + break; + case 1 : //opening file + $fopen=fopen($env_file_path,'r'); + if (!$fopen) { + throw new ErrorException("Unable to read file <".($env_file_path).">!"); + $phase=999; + } + break; + case 2 : //scanning file + while (($line=fgets($fopen))!==false) { + if (substr(trim($line),0,1)=='#') + continue; + if (empty(trim($line))) + continue; + $line_no_comment=explode("#",$line,2)[0]; + $env_ex=preg_split('/(\s?)\=(\s?)/',$line_no_comment); + $env_name=trim($env_ex[0]); + $env_value=""; + if (isset($env_ex[1])) + $env_value=trim($env_ex[1]); + putenv("$env_name=$env_value"); + } + break; + case 3 : //closing file + fclose($fopen); + break; + default : //SAFE Guard + $proceed=false; + break; + } + $phase++; + } +} + +loadenv(); +?>