--- /dev/null
+#====================================================================
+#Makefile to build the package
+#default make
+default : clean prod
+#--------------------------------------------------------------------
+#Makefile with all data for GIT
+include Makefile.git
+#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
+#===================================================================
--- /dev/null
+#===================================================================
+#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
--- /dev/null
+#====================================================================
+#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)-$(DISTVER).$(DISTREL)-*.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@@/$(DISTVER).$(DISTREL)/g' \
+ -e 's/@@RELEASE@@//g' \
+ < $< > $@
+
+
+
+cleanrpm:
+ @ rm -fr $(RPMDIR)/* spec
+
+#====================================================================
+#rpm definitions
+RPMDIR = $(CURDIR)/rpmbuild
+SRC = $(RPMDIR)/SOURCES
+SRPM = $(RPMDIR)/SRPMS
+#====================================================================
+DISTVER = $(shell echo `grep VERSION lib/numver.h | cut -d '"' -f2`)
+DISTREL = $(shell echo `grep RELEASE lib/numver.h | cut -d '"' -f2`)
+APPV = $(DISTVER).$(DISTREL)
+APLV = $(APPN)-$(APPV)
+#====================================================================
--- /dev/null
+#--------------------------------------------------------------------
+#to prepare git function
+#version change
+CURTAG = $(shell git rev-parse --abbrev-ref HEAD)
+BRANCH = $(shell echo $(CURTAG) | cut -d '-' -f3)
+VERSION = $(shell echo $(CURTAG) | cut -d '-' -f2)
+RELEASE = $(shell git rev-list --count $(CURTAG) ^tag-$(VERSION))
+NEXTREL = $(shell echo $(RELEASE) + 1 |bc)
+MAILREL = $(shell echo $(VERSION)-$(NEXTREL)-$(BRANCH))
+#--------------------------------------------------------------------
+#--------------------------------------------------------------------
+#to check if git find difference
+github :
+ @ (cd pub-mailleur ; git push --tags $@ $(BR):$(BR))
+
+allcom : commit maincom
+
+maincom : clean
+ @ git add . mailleur
+ @ git commit -a
+ @ $(MAKE) -s push
+
+push :
+ git push --tags origin $$BR:$$BR ;
+
+commit : fclean dovers
+ @ ( \
+ cd $(PUB) ; \
+ git add . ; \
+ git commit -a ; \
+ git push --tags origin $$BR:$$BR ; \
+ )
+
+BR = $(shell git branch | sed -e '/^[^*]/d' -e 's/* //')
+#--------------------------------------------------------------------
+gitcheck:
+ @ echo CURTAG=$(CURTAG)
+ @ echo BRANCH=$(BRANCH)
+ @ echo VERSION=$(VERSION)
+ @ echo RELEASE=$(RELEASE)
+
+#--------------------------------------------------------------------
+#to clean directory before a git commit
+fclean : clean
+ @ rm -fr core.*
+ @ rm -fr srcrpm/*
+
+#prepare version and working dirs
+dovers :
+ @ make -s clean
+ @ echo "Updating Version WITH $(BRANCH)"
+ @ ( \
+ echo -e "#define VERSION\t\"$(VERSION)\""; \
+ echo -e "#define RELEASE\t\"$(NEXTREL)\""; \
+ echo -e "#define BRANCH\t\"$(BRANCH)\""; \
+ ) > ./lib/numver.h
+ ( \
+ sed \
+ -e "s/=VERSION/=\"$(VERSION)\"/" \
+ -e "s/=NEXTREL/=\"$(NEXTREL)\"/" \
+ -e "s/=BRANCH/=\"$(BRANCH)\"/" \
+ -e "s/=MAILREL/=\"$(MAILREL)\"/" \
+ ./www/release.in \
+ ) > ./www/release.php
+
+PUB=mailleurXXXXX
+NEWGIT = $(shell cd mailleur ; git diff --exit-code > /dev/null; echo $$?)
+#--------------------------------------------------------------------
--- /dev/null
+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
+#-----------------------------------------------------------
--- /dev/null
+#--------------------------------------------------------------------
+#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
+#--------------------------------------------------------------------
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Validation program to check SPF extraction */
+/* library. */
+/* */
+/********************************************************/
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "subrou.h"
+#include "subafn.h"
+#include "unidns.h"
+#include "unipar.h"
+#include "uniprc.h"
+#include "gesspf.h"
+
+#define CHKSPF "chkspf" //application name
+
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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);
+ }
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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);
+}
--- /dev/null
+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-redhat-linux/11/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/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/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-redhat-linux/11/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
--- /dev/null
+// 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 <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#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;
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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");
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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<strlen(line))&&(strncmp(line,received,tocheck)==0))
+ phase++;
+ }
+ break;
+ case 3 : //can we test shorter
+ (void) rou_alert(0,"\n%s\tline %04d, fatal error! (on %s)",
+ titre,numline,testname);
+ (void) rou_alert(0,"expecting\t'%s'",line);
+ (void) rou_alert(0,"found\t\t'%s'",received);
+ phase=999;
+ break;
+ case 4 : //everything fine
+ //(void) rou_alert(0,"JMPDBG line <%s> OK!",line);
+ status=true;
+ break;
+ default : //SAFE Guard
+ received=rou_freestr(received);
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return status;
+#undef OPEP
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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 (next<argc) {
+ switch (phase) {
+ case 0 : //display scanned file
+ break;
+ case 1 : //scanning file
+ if (scanonefile(feed,argv[next])==false)
+ next=argc; //do not check next file
+ break;
+ case 2 : //incrementing numfile scanned
+ numfile++;
+ break;
+ default : //still file to be scanned
+ next++;
+ phase=0;
+ break;
+ }
+ phase++;
+ }
+feed->destport=rou_freestr(feed->destport);
+feed->destip=rou_freestr(feed->destip);
+feed->srcip=rou_freestr(feed->srcip);
+(void) free(feed);
+return numfile;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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);
+}
--- /dev/null
+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-redhat-linux/11/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/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-redhat-linux/11/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/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-redhat-linux/11/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/configuration-x86_64.h \
+ /usr/include/openssl/opensslv.h /usr/include/openssl/e_os2.h \
+ /usr/include/inttypes.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.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-redhat-linux/11/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/include/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Email Receiver */
+/* SMTP Daemon dedicated to receive Email. */
+/* */
+/********************************************************/
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#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"
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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);
+}
--- /dev/null
+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-redhat-linux/11/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/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-redhat-linux/11/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/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-redhat-linux/11/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/configuration-x86_64.h \
+ /usr/include/openssl/opensslv.h /usr/include/openssl/e_os2.h \
+ /usr/include/inttypes.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.h \
+ /usr/include/bits/stdint-uintn.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-redhat-linux/11/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/include/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
--- /dev/null
+// 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 <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#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;
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
--- /dev/null
+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-redhat-linux/11/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/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-redhat-linux/11/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/stdio_lim.h ../lib/gessql.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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
--- /dev/null
+// 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 <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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<argc;i++)
+ list=(char **)rou_addlist((void **)list,(void *)strdup(argv[i]));
+ phase++; //No nee to build list
+ foreground=true;//on pass only
+ }
+ break;
+ case 1 : //building the list according directory contents
+ list=eml_getqfilelist(list,TODO);
+ break;
+ case 2 : //do we have a list
+ if (list!=(char **)0) {
+ int num;
+ char **scan;
+
+ num=0;
+ scan=list;
+ while (*scan!=(char *)0) {
+ char *fname;
+ char *ptr;
+
+ fname=*scan;
+ (void) prc_settitle("%s:%s, sending <%s>",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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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);
+}
--- /dev/null
+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-redhat-linux/11/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/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-redhat-linux/11/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/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-redhat-linux/11/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/configuration-x86_64.h \
+ /usr/include/openssl/opensslv.h /usr/include/openssl/e_os2.h \
+ /usr/include/inttypes.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.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-redhat-linux/11/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/include/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
--- /dev/null
+// 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 <dirent.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "subrou.h"
+#include "unidns.h"
+#include "unieml.h"
+#include "unipar.h"
+#include "uniprc.h"
+#include "unisig.h"
+#include "geseml.h"
+
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
--- /dev/null
+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-redhat-linux/11/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/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-redhat-linux/11/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-redhat-linux/11/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/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
--- /dev/null
+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-----
--- /dev/null
+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-----
--- /dev/null
+-----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-----
--- /dev/null
+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-----
--- /dev/null
+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-----
--- /dev/null
+-----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-----
--- /dev/null
+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-----
--- /dev/null
+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-----
--- /dev/null
+#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
--- /dev/null
+#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
+#------------------------------------------------
--- /dev/null
+#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
+#------------------------------------------------
--- /dev/null
+#--------------------------------------------------------
+##Private address block which email can be relayed from
+127.0.0.0/8 #local loop number
+#--------------------------------------------------------
+#Setup you own list
--- /dev/null
+#--------------------------------------------------------
+##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
--- /dev/null
+#---------------------------------------------------
+#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
+
--- /dev/null
+#====================================================
+#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...
--- /dev/null
+#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 <example.com> 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...
--- /dev/null
+#====================================================
+# 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: <postmaster@example.com>
+R:250 2.1.3 postmaster@example.com sender ok
+S:RCPT TO: <webmaster@example.com>
+R:250 5.6.7 Address will be processed <webmaster@example.com>
+S:RCPT TO: <postmaster@example.com>
+R:250 5.6.7 Address will be processed <postmaster@example.com>
+#-------------------------------------------------------------------------
+#-sending data
+C:DATA 354 3.5.0 End data with <CR><LF>.<CR><LF>
+D:Subject: (feed000) Very Simple email contents
+C:T
+D:From: Maitre Post <postmaster@example.com>
+D:To: Maitre WEB <webmaster@example.com>
+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...
+#-------------------------------------------------------------------------
--- /dev/null
+#====================================================
+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: <postmaster@example.com> SIZE=1024
+R:250 2.1.3 postmaster@example.com sender ok
+S:RCPT TO: <user1@mailref1.example.com>
+R:250 5.6.7 Address will be processed <user1@mailref1.example.com>
+S:RCPT TO: <user2@mailref1.example.com>
+R:250 5.6.7 Address will be processed <user2@mailref1.example.com>
+#-------------------------------------------------------------------------
+#-sending data
+C:DATA 354 3.5.0 End data with <CR><LF>.<CR><LF>
+D:Subject: (feed001) Very Simple email contents
+D:From: Maitre Post <postmaster@example.com>
+D:To: Remote person <user1@mailref1.example.com>
+D:CC: Other person <user2@mailref1.example.com>
+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...
--- /dev/null
+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: <trouble@mailref1.example.com>
+R:250 2.1.3 trouble@mailref1.example.com sender ok
+S:RCPT TO: <webmaster@example.com>
+R:250 5.6.7 Address will be processed <webmaster@example.com>
+S:RCPT TO: <user1@mailref1.example.com>
+R:250 5.6.7 Address will be processed <user1@mailref1.example.com>
+S:RCPT TO: <user1@posdb.example.com>
+R:250 5.6.7 Address will be processed <user1@posdb.example.com>
+S:RCPT TO: <user1@mardb.example.com>
+R:250 5.6.7 Address will be processed <user1@mardb.example.com>
+#-------------------------------------------------------------------------
+#-sending data
+C:DATA 354 3.5.0 End data with <CR><LF>.<CR><LF>
+D:Subject: (feed002) Very Simple email contents 2 domains
+D:From: Maitre Post <postmaster@example.com>
+D:To: Maitre WEB <webmaster@example.com>
+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...
--- /dev/null
+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: <trouble@mailref1.example.com>
+R:250 2.1.3 trouble@mailref1.example.com sender ok
+S:RCPT TO: <user1@mailref1.example.com>
+R:250 5.6.7 Address will be processed <user1@mailref1.example.com>
+S:RCPT TO: <user2@mailref1.example.com>
+R:250 5.6.7 Address will be processed <user2@mailref1.example.com>
+S:RCPT TO: <no-one@example.com>
+R:551 5.6.0 <no-one@example.com> unknown user
+#-------------------------------------------------------------------------
+#-sending data
+C:DATA 354 3.5.0 End data with <CR><LF>.<CR><LF>
+D:Subject: feed003 email first part
+D:From: Tester <trouble@mailref1.example.com>
+D:To: A User1 <user1@mailref1.example.com>
+D:Cc: A User2 <user2@mailref1.example.com>
+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: <postmaster@mailref1.example.com>
+R:250 2.1.3 postmaster@mailref1.example.com sender ok
+S:RCPT TO: <user2@mailref1.example.com>
+R:250 5.6.7 Address will be processed <user2@mailref1.example.com>
+S:RCPT TO: <user1@mailref1.example.com>
+R:250 5.6.7 Address will be processed <user1@mailref1.example.com>
+#-------------------------------------------------------------------------
+#-sending data
+C:DATA 354 3.5.0 End data with <CR><LF>.<CR><LF>
+D:Subject: feed003 email second part
+D:From: Tester <trouble@mailref1.example.com>
+D:To: A User1 <user1@mailref1.example.com>
+D:Cc: A User2 <user2@mailref1.example.com>
+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...
--- /dev/null
+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: <postmaster@example.com>
+R:250 2.1.3 postmaster@example.com sender ok
+S:RCPT TO: <utf8-áö_üñ@example.com>
+R:250 5.6.7 Address will be processed <utf8-áö_üñ@example.com>
+#-------------------------------------------------------------------------
+#-sending data
+C:DATA 354 3.5.0 End data with <CR><LF>.<CR><LF>
+D:Subject: (feed004) Email using UTF-8 characters
+C:T
+D:From: Maitre Post <postmaster@example.com>
+D:To: Maitre WEB <webmaster@example.com>
+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...
+#-------------------------------------------------------------------------
--- /dev/null
+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: <trouble@mailref1.example.com>
+R:556-4.5.7 Originator server IP [213.209.157.107] black listed...
+R:556 5.5.4 Closing connection
+R:Disconnected
+#-------------------------------------------------------------------------
--- /dev/null
+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: <trouble@mailref1.example.com>
+R:250 2.1.3 trouble@mailref1.example.com sender ok
+S:RCPT TO: <user1@posdb.example.com>
+R:250 5.6.7 Address will be processed <user1@posdb.example.com>
+#-sending data
+C:DATA 354 3.5.0 End data with <CR><LF>.<CR><LF>
+D:Subject: (feed006) A email to a not existing user after authentication
+D:From: Trouble maker <trouble@mailref1.example.com>
+D:To: Not existing <dom1user3@mailref1.example.com>
+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...
--- /dev/null
+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: <trouble@mailref1.example.com>
+R:250 2.1.3 trouble@mailref1.example.com sender ok
+S:RCPT TO: <user1@posdb.example.com>
+R:250 5.6.7 Address will be processed <user1@posdb.example.com>
+#-sending data
+C:DATA 354 3.5.0 End data with <CR><LF>.<CR><LF>
+D:Subject: (feed006) A email to a not existing user after authentication
+D:From: Trouble maker <trouble@mailref1.example.com>
+D:To: Not existing <dom1user3@mailref1.example.com>
+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...
--- /dev/null
+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:<supertool@mxtoolboxsmtpdiag.com>
+R:250 2.1.3 supertool@mxtoolboxsmtpdiag.com sender ok
+S:RCPT TO: <webmaster@example.com>
+R:250 5.6.7 Address will be processed <webmaster@example.com>
+S:RCPT TO:<test@mxtoolboxsmtpdiag.com>
+R:555 2.8.0 No MX nor IP for for domain <mxtoolboxsmtpdiag.com>
+S:RCPT TO: <user1@posdb.example.com>
+R:555 2.8.0 No relay accepted for domain <posdb.example.com>
+#-------------------------------------------------------------------------
+#-sending data
+C:DATA 354 3.5.0 End data with <CR><LF>.<CR><LF>
+D:Subject: (feed008) sending email to local only
+D:From: Maitre Post <postmaster@example.com>
+D:To: Maitre WEB <webmaster@example.com>
+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...
--- /dev/null
+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:<nobody@gmail.com> SIZE=2958
+R:250 2.1.3 nobody@gmail.com sender ok
+S:RCPT TO:<user1@mailleur.example.com>
+R:250 5.6.7 Address will be processed <user1@mailleur.example.com>
+#-------------------------------------------------------------------------
+#-sending data
+C:DATA 354 3.5.0 End data with <CR><LF>.<CR><LF>
+D:Subject: (feed008) sending email to local only
+D:From: A Nobody <nobody@gmail.com>
+D:To: A simple very local user <user1@mailleur.example.com>
+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...
--- /dev/null
+#====================================================
+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.
+#====================================================
--- /dev/null
+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
--- /dev/null
+#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: <postmaster@example.com>
+R:250 2.1.3 postmaster@example.com sender ok
+S:RCPT TO: <user1@subdom0.example.com>
+R:563 5.6.4 No valid MX found for recipient domain name (domain=subdom0.example.com)
+S:RCPT TO: <user1@mailref1.example.com>
+R:250 5.6.7 Address will be processed <user1@mailref1.example.com>
+S:QUIT
+R:221 2.0.0 Bye, closing connection...
+#-------------------------------------------------------------------------
--- /dev/null
+#====================================================
+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: <trouble@mailref1.example.com>
+R:250 2.1.3 trouble@mailref1.example.com sender ok
+#---------------------------------------------
+S:RCPT TO: <dom1user3@example.com>
+R:551 5.6.5 <dom1user3@example.com> unknown user
+S:RCPT TO: <dom1user3@mailref1.example.com>
+R:250 5.6.7 Address will be processed <dom1user3@mailref1.example.com>
+S:RCPT TO: <user1@posdb.example.com>
+R:250 5.6.7 Address will be processed <user1@posdb.example.com>
+#-------------------------------------------------------------------------
+#-sending data
+C:DATA 354 3.5.0 End data with <CR><LF>.<CR><LF>
+D:Subject: (feed11) A email to a not existing user
+D:From: Trouble maker <mailref1.example.com>
+D:To: Not existing <dom1user3@mailref1.example.com>
+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...
--- /dev/null
+#====================================================
+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: <trouble@mailref1.example.com>
+R:250 2.1.3 trouble@mailref1.example.com sender ok
+S:RCPT TO: <user1@subdom0.example.com>
+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...
--- /dev/null
+#====================================================
+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@
--- /dev/null
+#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...
+#-------------------------------------------------------------------------
--- /dev/null
+#very simple test to feed SMTP server
+#====================================================
+T:(feed20) Testing double connectopm
+R:220 mailleur.example.com, ESMTP (cleartext) mailleur...
+#====================================================
+#-------------------------------------------------------------------------
--- /dev/null
+#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: <postmaster@example.com>
+R:250 2.1.3 postmaster@example.com sender ok
+S:RCPT TO: <root@example.com>
+R:250 5.6.7 Address will be processed <root@example.com>
+S:RCPT TO: <jmp@example.com>
+R:250 5.6.7 Address will be processed <jmp@example.com>
+#-------------------------------------------------------------------------
+#-sending data
+C:DATA 354 3.5.0 End data with <CR><LF>.<CR><LF>
+D:Subject: (feed030) Very Simple email contents
+C:T
+D:From: Maitre Post <postmaster@example.com>
+D:To: Big Master <root@example.com>
+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...
+#-------------------------------------------------------------------------
--- /dev/null
+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
--- /dev/null
+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...
--- /dev/null
+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:<user1@postdb.example.com>
+R:250 2.1.3 webmaster@example.com sender ok
+S:QUIT
+R:221 2.0.0 Bye, closing connection...
--- /dev/null
+$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"
+ )
+
+;---------------------------------------------------------------------
--- /dev/null
+#========================================================
+#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
+#--------------------------------------------------------
--- /dev/null
+#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
+#------------------------------------------------
--- /dev/null
+# -------------------------------
+# 70-mailleur-mysql-conf
+# Configuration Dovecot to use Mariadb server
+# -------------------------------
+sql_driver = mysql
+
+mysql remote {
+ host = localhost.localdomain
+ user = mailleur
+ dbname = mailleur
+ }
--- /dev/null
+# -------------------------------
+# 70-pgsql.conf
+# Configuration Dovecot to use PostgreSQL server
+# -------------------------------
+sql_driver = pgsql
+
+pgsql remote {
+ parameters {
+ host = localhost.localdomain
+ user = mailleur
+ dbname = mailleur
+ }
+ }
--- /dev/null
+# -------------------------------
+# 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}';
+ }
+
+
--- /dev/null
+#--------------------------------------------------------------------
+#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`
+#--------------------------------------------------------------------
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Log management implementation module */
+/* */
+/********************************************************/
+#include <linux/limits.h>
+#include <sys/file.h>
+#include <errno.h>
+#include <malloc.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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
+}
--- /dev/null
+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-redhat-linux/11/include/stddef.h \
+ /usr/include/stdio.h /usr/include/bits/libc-header-start.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/stdio_lim.h /usr/include/bits/floatn.h \
+ /usr/include/bits/floatn-common.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/************************************************/
+/* */
+/* device level, logs management */
+/* declaration. */
+/* */
+/************************************************/
+#ifndef DEVLOG
+#define DEVLOG
+
+#include <stdio.h>
+
+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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Low level subroutine declaration */
+/* to handle TCP socket. */
+/* */
+/********************************************************/
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#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;
+
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;i<got;i++,buffer++) {
+ if (*buffer=='\000')
+ *buffer='?';
+ }
+ soc->carin+=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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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 (;count<max;count++) {
+ soc->carin=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;
+}
--- /dev/null
+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-redhat-linux/11/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/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-redhat-linux/11/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/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-redhat-linux/11/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/configuration-x86_64.h \
+ /usr/include/openssl/opensslv.h /usr/include/openssl/e_os2.h \
+ /usr/include/inttypes.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.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-redhat-linux/11/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/include/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Low level subroutine declaration */
+/* to handle tcp Socket. */
+/* */
+/********************************************************/
+#ifndef DEVSOC
+#define DEVSOC
+
+#include <sys/socket.h>
+#include <stdbool.h>
+#include <time.h>
+
+#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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Low level subroutine implementation */
+/* to handle SQL request */
+/* */
+/********************************************************/
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
--- /dev/null
+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-redhat-linux/11/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/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/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-redhat-linux/11/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
--- /dev/null
+// 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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Implement all routine to manage email transport */
+/* exchange. */
+/* */
+/********************************************************/
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+
+#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;
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* Procedure to compare 2 transaction struct */
+/* */
+/********************************************************/
+static int cmp_sessid(const void *p1,const void *p2)
+
+
+{
+return strcmp((*((TRATYP **)p1))->sessid,(*((TRATYP **)p2))->sessid);
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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);
+ }
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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++;
+ }
+ }
+ }
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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 <line=%s> (config?)",OPEP,line);
+ phase=999; //No data within line
+ }
+ break;
+ default :
+ (void) rou_alert(0,"%s Unexpected code within <line=%s> (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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
--- /dev/null
+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-redhat-linux/11/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/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-redhat-linux/11/include/stdbool.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/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/configuration-x86_64.h \
+ /usr/include/openssl/opensslv.h /usr/include/openssl/e_os2.h \
+ /usr/include/inttypes.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.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-redhat-linux/11/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/include/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Define all procedure to manage email transport */
+/* data. */
+/* */
+/********************************************************/
+#ifndef GESEML
+#define GESEML
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Implement all routine to manage SMTP low level */
+/* exchange. */
+/* */
+/********************************************************/
+#include <errno.h>
+#include <malloc.h>
+#include <resolv.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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;
+
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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);
+ }
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
--- /dev/null
+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-redhat-linux/11/include/stddef.h \
+ /usr/include/stdio.h /usr/include/bits/libc-header-start.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/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/struct_mutex.h \
+ /usr/include/bits/struct_rwlock.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.h \
+ /usr/include/arpa/nameser_compat.h /usr/include/bits/types/res_state.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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
--- /dev/null
+// 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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Module to manage complexe SQL request */
+/* */
+/********************************************************/
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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}
+ };
+
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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<lastupdate) and (lastscan<%s) "
+ "order by lastscan asc limit 10";
+
+char **rmtip;
+SQLRES *rs;
+int num;
+char *again;
+int phase;
+_Bool proceed;
+
+rmtip=(char **)0;
+rs=(SQLRES *)0;
+num=0;
+again=sql_caldate(sqlptr,"NOW()",delay);
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //do we have some remote IP
+ if ((rs=sql_gettupple(sqlptr,cmd,again))==(SQLRES *)0) {
+ (void) rou_alert(0,"%s unable to get remoteip list "
+ "(Database BUG?)",OPEP);
+ phase=999; //No need to go further
+ }
+ break;
+ case 1 : //how many entry do we have
+ if ((num=sql_getnbrtupple(sqlptr,rs))<=0) {
+ phase++; //no need to extract list
+ }
+ break;
+ case 2 : //extracting list
+ for (int i=0;i<num;i++) {
+ const char *ip;
+
+ ip=sql_getvalue(sqlptr,rs,i,"remoteip");
+ if (ip!=(const char *)0)
+ rmtip=(char **)rou_addlist((void **)rmtip,
+ (void *)strdup(ip));
+ }
+ break;
+ case 3 : //clearing result
+ rs=sql_droptupple(sqlptr,rs);
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+again=rou_freestr(again);
+return rmtip;
+
+#undef OPEP
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* Procedure to add an event reference within the */
+/* data-base event table. */
+/* */
+/********************************************************/
+PUBLIC int sql_addevent(SQLPTR *sqlptr,char *session,int debut,int fin)
+
+{
+static char *ins="INSERT INTO "EVTTBL" (sessid,start,stop) values(%s)";
+
+int done;
+
+done=-1;
+if (sqlptr!=(SQLPTR *)0) {
+ char *goodses;
+ char *values;
+
+ goodses=sql_gooddata(sqlptr,session);
+ (void) rou_asprintf(&values,"%s,%d,%d",goodses,debut,fin);
+ done=sql_request(sqlptr,ins,values);
+ values=rou_freestr(values);
+ goodses=rou_freestr(goodses);
+ }
+return done;
+}
--- /dev/null
+gessql.o gessql.d : gessql.c /usr/include/stdc-predef.h /usr/include/malloc.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-redhat-linux/11/include/stddef.h \
+ /usr/include/stdio.h /usr/include/bits/libc-header-start.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/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/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 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-redhat-linux/11/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 unisql.h gessql.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 devsql.h
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/************************************************/
+/* */
+/* gestion level fto manage sql request */
+/* */
+/************************************************/
+#ifndef GESSQL
+#define GESSQL
+
+#include <stdbool.h>
+
+#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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Module to manage TCP communication */
+/* */
+/********************************************************/
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#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
+}
--- /dev/null
+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-redhat-linux/11/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/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/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-redhat-linux/11/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/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-redhat-linux/11/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/configuration-x86_64.h \
+ /usr/include/openssl/opensslv.h /usr/include/openssl/e_os2.h \
+ /usr/include/inttypes.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.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-redhat-linux/11/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/include/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/************************************************/
+/* */
+/* gestion level to handle TCP */
+/* communication */
+/* */
+/************************************************/
+#ifndef GESTCP
+#define GESTCP
+
+#include <stdbool.h>
+
+#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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Implement all routine to manage SMTP low level */
+/* exchange. */
+/* */
+/********************************************************/
+#include <arpa/inet.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "subafn.h"
+#include "subrou.h"
+#include "subcnv.h"
+#include "unidig.h"
+#include "unieml.h"
+#include "uniprc.h"
+#include "devlog.h"
+#include "gestcp.h"
+#include "gessql.h"
+#include "geseml.h"
+#include "lvleml.h"
+
+//env variable to define the list of relayable
+#define RELAYS "RELAYABLE"
+
+static const char *cry="(crypted link is now set in '%s' mode, security level='%d')";
+
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to update the termination condition */
+/* within contact. */
+/* current session. */
+/* */
+/********************************************************/
+static void setterminator(CONTYP *contact,const char *condition)
+
+{
+if (contact!=(CONTYP *)0) {
+ contact->termend=rou_freestr(contact->termend);
+ contact->termend=strdup(condition);
+ }
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to update database and free the */
+/* current session. */
+/* */
+/********************************************************/
+static void freesessid(CONTYP *contact)
+
+{
+if (contact->session!=(SESTYP *)0) {
+ if (contact->mailfrom!=(char *)0) {
+ contact->session->sfrom=strdup(contact->mailfrom);
+ (void) sql_mngses(contact->sqlptr,sql_update,&(contact->session));
+ }
+ contact->session=sql_freeses(contact->session);
+ }
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to manage curent SMTP session data */
+/* within contact. */
+/* */
+/********************************************************/
+static void getsessid(CONTYP *contact)
+
+{
+if (contact!=(CONTYP *)0) {
+ char *newsid;
+
+ newsid=eml_getcursesid(contact->mainsesid,contact->numreset);
+ contact->session=(SESTYP *)calloc(1,sizeof(SESTYP));
+ contact->session->sessid=newsid;
+ (void) sql_mngses(contact->sqlptr,sql_insert,&(contact->session));
+ }
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to free memory used by contact */
+/* */
+/********************************************************/
+static CONTYP *freecontact(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:freecontact"
+
+if (contact!=(CONTYP *)0) {
+ long debut;
+ long fin;
+
+ debut=0;
+ fin=0;
+ (void) freesessid(contact);
+ contact->logptr=log_closelog(contact->logptr,&debut,&fin);
+ if (contact->mainsesid!=(char *)0) {
+ (void) sql_addevent(contact->sqlptr,contact->mainsesid,debut,fin);
+ contact->mainsesid=rou_freestr(contact->mainsesid);
+ }
+ contact->sqlptr=sql_closesql(contact->sqlptr);
+ contact->termend=rou_freestr(contact->termend);
+ contact->relayok=(AFNTYP **)rou_freelist((void **)contact->relayok,
+ (genfree_t)afn_freeipnum);
+ contact->recipients=(RCPTYP **)rou_freelist((void **)contact->recipients,
+ (genfree_t)eml_freerecipient);
+ contact->authname=rou_freestr(contact->authname);
+ contact->mailfrom=rou_freestr(contact->mailfrom);
+ contact->fqdn=rou_freestr(contact->fqdn);
+ contact->peername=rou_freestr(contact->peername);
+ contact->peerip=rou_freestr(contact->peerip);
+ contact->locserv=rou_freestr(contact->locserv);
+ contact->localafns=(AFNTYP **)rou_freelist((void **)contact->localafns,
+ (genfree_t)afn_freeipnum);
+ contact->locip=rou_freestr(contact->locip);
+ contact->locname=rou_freestr(contact->locname);
+ (void) free(contact);
+ contact=(CONTYP *)0;
+ }
+return contact;
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to get the domain code */
+/* */
+/********************************************************/
+static _Bool setlocdom(CONTYP *contact,RCPTYP *rcpt)
+
+{
+#define OPEP "lvleml.c:setlocdom,"
+
+char done;
+int phase;
+_Bool proceed;
+
+done=true;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d' parm=<%s>",OPEP,phase,parameter);
+ switch (phase) {
+ case 0 : //is RCPT ok;
+ if ((rcpt==(RCPTYP *)0)||(rcpt->domain==(char *)0)) {
+ (void) rou_alert(0,"%s Recipient is NULL (Bug!?)",OPEP);
+ done=false;
+ phase=999;
+ }
+ break;
+ case 1 : //check about local domain, TEMPORARY code
+ int status;
+
+ status=dns_is_domain_local(rcpt->domain,contact->localafns);
+ switch (status) {
+ case dns_nomx :
+ done=false;
+ break;
+ case dns_local :
+ rcpt->code='L'; //domain is local
+ break;
+ case dns_remote :
+ rcpt->code='R'; //domain is remote
+ break;
+ default :
+ (void) rou_alert(0,"%s Unexpected status='%d' for domain<%s>",
+ OPEP,status,rcpt->domain);
+ break;
+ }
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return done;
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send the signon once the contact */
+/* with peer is detected. */
+/* */
+/********************************************************/
+static void signon(CONTYP *contact)
+
+{
+#define FMT "%d %s, ESMTP (%s) %s-%s; %s"
+
+if (contact!=(CONTYP *)0) {
+ const char *mode;
+ char signon[100];
+
+ mode=soc_getstrmode(contact->socptr);
+ (void) snprintf(signon,sizeof(signon),FMT,
+ SIGNON,contact->locname,
+ mode,
+ APPNAME,
+ rou_getversion(),
+ rou_ascsysstamp(time((time_t *)0)));
+ (void) eml_transmit(contact,true,"%s",signon);
+ }
+#undef FMT
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send ready link information */
+/* is a correct one */
+/* */
+/********************************************************/
+static void linkready(CONTYP *contact,_Bool suite)
+
+{
+const char *mode;
+_Bool flush;
+char sepa;
+
+sepa=' ';
+flush=true;
+if (suite==true) {
+ flush=false;
+ sepa='-';
+ }
+mode=soc_getstrmode(contact->socptr);
+(void) eml_transmit(contact,flush,"%d%c%s, link (%s) ready, your IP/FQDN=[%s/%s]",
+ CMDOK,sepa,contact->locname,mode,
+ contact->peerip,contact->peername);
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to add received information to */
+/* the email contents. */
+/* */
+/********************************************************/
+static _Bool addreceived(CONTYP *contact,FILE *data)
+
+{
+_Bool status;
+time_t curtime;
+const char *esmtp;
+int phase;
+_Bool proceed;
+
+status=true;
+esmtp="ESMTP";
+curtime=time((time_t *)0);
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //Inserting the remote information
+ (void) fprintf(data,"Received: from %s (IP=[%s], originator=<%s>)\n",
+ contact->peername,contact->peerip,contact->mailfrom);
+ break;
+ case 1 : //Inserting the Receive information
+ if (contact->privilege==rel_authentic)
+ esmtp="ESMTPA";
+ (void) fprintf(data,"\tby %s ([%s:%s]/%s-%s) with %s\n",
+ contact->locname,
+ contact->locip,
+ contact->locserv,
+ appname,rou_getversion(),
+ esmtp);
+ break;
+ case 2 : //Inserting TLS information
+ if (soc_iscrypted(contact->socptr)==true) {
+ char *cipherid;
+
+ cipherid=soc_getcipherid(contact->socptr);
+ if (cipherid!=(char *)0)
+ (void) fprintf(data,"\t(%s)\n",cipherid);
+ cipherid=rou_freestr(cipherid);
+ }
+ break;
+ case 3 : //Inserting ID information
+ (void) fprintf(data,"\tid <%s@%s>;\n",
+ contact->session->sessid,contact->locname);
+ break;
+ case 4 : //date information
+ (void) fprintf(data,"\t%s\n",rou_ascsysstamp(curtime));
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return status;
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to check remote IP credit */
+/* */
+/********************************************************/
+static int checkcredit(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:checkcredit,"
+
+int status;
+SRVTYP *srv;
+int phase;
+_Bool proceed;
+
+status=FAILED;
+srv=(SRVTYP *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //reading remote server information
+ if (sql_mngremote(contact->sqlptr,sql_select,contact->peerip,&srv)==false) {
+ (void) rou_alert(0,"%s Unable to find server data for remote <%s> (BUg?)",
+ OPEP,contact->peerip);
+ phase=999;
+ }
+ break;
+ case 1 : //checking credential
+ if (srv->links>1) {
+ status=ALREADY;
+ (void) eml_note(contact,NULL,"%d 4.5.6 already connected",status);
+ (void) eml_transmit(contact,true,"%d 4.5.6 already connected",status);
+ phase=999; //To many server connected
+ }
+ break;
+ case 2 : //checking if black listed (low credit)
+ if (srv->credit<0) {
+ char *cmt;
+ const char *ninfo;
+
+ cmt=srv->listing;
+ ninfo="%d-4.5.7 Originator server IP [%s] black listed <%s>";
+ if (cmt==(char *)0)
+ cmt="credit too low";
+ (void) log_fprintlog(contact->logptr,false,"(Remote %s[%s] credit='%d' %s)",
+ contact->peername,
+ contact->peerip,
+ srv->credit,"too low");
+ status=BLCKLST;
+ (void) eml_note(contact,NULL,ninfo,status,contact->peerip,cmt);
+ (void) eml_transmit(contact,true,ninfo,status,contact->peerip,cmt);
+ (void) setterminator(contact,"Remote server credit is too low");
+ phase=999; //To many server connected
+ }
+ break;
+ case 3 : //remote server is "credible"
+ status=CMDOK;
+ break;
+ default : //SAFE Guard, freeing memory
+ srv=sql_freesrv(srv);
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return status;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to split a plain authentication string*/
+/* Match with the user provided. */
+/* */
+/********************************************************/
+static void split_auth_plain(char *sequence,char *data[3])
+
+{
+char *locdata[3];
+char *dup;
+char *ptr;
+int count;
+
+(void) memset(locdata,'\000',sizeof(locdata));
+dup=strdup(sequence);
+ptr=dup;
+for (count=0;(count<3)&&(ptr!=(char *)0);count++) {
+ char *mark;
+
+ if ((mark=strstr(ptr,IOBNULL))!=(char *)0) {
+ *mark='\000';
+ mark+=strlen(IOBNULL);
+ }
+ locdata[count]=strdup(ptr);
+ ptr=mark;
+ }
+(void) memmove(data,locdata,sizeof(locdata));
+dup=rou_freestr(dup);
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to check if the password submitted */
+/* Match with the user provided. */
+/* */
+/********************************************************/
+static _Bool checklogin(CONTYP *contact,char **rmtpass,char *sequence)
+
+{
+#define OPEP "lvleml.c:checklogin,"
+
+_Bool isok;
+char *data[3];
+char *givenhash;
+int phase;
+_Bool proceed;
+
+isok=false;
+(void) memset(data,'\000',sizeof(data));
+givenhash=(char *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //make sure we have data
+ (void) split_auth_plain(sequence,data);
+ if ((data[1]==(char *)0)||(data[2]==(char *)0)) {
+ (void) rou_alert(0,"%s missing data from <%s> (Bug?)",OPEP,sequence);
+ phase=999; //No need to go further
+ }
+ break;
+ case 1 : //do we have valide data?
+ if ((strlen(data[1])==0)||(strlen(data[2])==0)) {
+ (void) rou_alert(0,"%s data[1]=<%s> or data[2]=<%s> missing (Remote Bug?)",
+ OPEP,data[1],data[2]);
+ phase=999; //No need to go further
+ }
+ break;
+ case 2 : { //checking user password
+ USRTYP *usr;
+
+ usr=(USRTYP *)0;
+ contact->authname=rou_freestr(contact->authname);
+ contact->authname=strdup(data[1]);
+ *rmtpass=strdup(data[2]);
+ if (sql_mngusr(contact->sqlptr,sql_select,data[1],&usr)==true) {
+ char *givenpass;;
+
+ givenpass=data[2];
+ if (usr->password==(char *)0) {
+ (void) rou_alert(0,"%s usr=<%s> password empty, assigning one",
+ OPEP,data[1]);
+ usr->password=cnv_getrndstr(10);
+ }
+ if (usr->password[0]=='$') {
+ char *ptr;
+ char idsalt[100];
+
+ (void) memset(idsalt,'\000',sizeof(idsalt));
+ (void) strncpy(idsalt,usr->password,sizeof(idsalt)-1);
+ if ((ptr=strrchr(idsalt,'$'))!=(char *)0) {
+ ptr++;
+ *ptr='\000';
+ }
+ if ((ptr=crypt(givenpass,idsalt))==(char *)0) {
+ (void) rou_alert(0,"%s Trouble to crypt (Bug?) givenpass=<%s> "
+ "salt=<%s> (error=<%s>)",
+ OPEP,givenpass,idsalt,strerror(errno));
+ ptr=data[2]; //trying to overcome
+ }
+ givenpass=ptr;
+ }
+ isok=(strcmp(givenpass,usr->password)==0);
+ usr=sql_freeusr(usr);
+ }
+ }
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+givenhash=rou_freestr(givenhash);
+for (int i=0;i<3;i++)
+ data[i]=rou_freestr(data[i]);
+return isok;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to manage authentication in "plain" */
+/* mode, return "decoded", NULL if not extracted */
+/* */
+/********************************************************/
+static void get_auth_plain(CONTYP *contact,char *received,char **rmtpass)
+
+{
+#define OPEP "lvleml.c:get_auth_plain,"
+
+char *decoded;
+
+*rmtpass=(char *)0;
+decoded=(char *)0;
+if ((received==(char *)0)||(strlen(received)==0)) {
+ char *line;
+ int got;
+
+ line=(char *)0;
+ (void) eml_transmit(contact,true,"%d 5.7.1 Please provide auth sequence",SENDB64);
+ got=tcp_getline(contact->socptr,contact->delay,&line);
+ if (got>0) {
+ (void) log_fprintlog(contact->logptr,false,"%s",line);
+ decoded=cnv_getb64(line);
+ line=rou_freestr(line);
+ }
+ }
+else
+ decoded=cnv_getb64(received);
+if (decoded!=(char *)0) {
+ if (checklogin(contact,rmtpass,decoded)==true) {
+ contact->credit+=2;
+ contact->privilege=rel_authentic;
+ }
+ decoded=rou_freestr(decoded);
+ }
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to manage authentication in "login" */
+/* mode, return goodpass true if successful */
+/* */
+/********************************************************/
+static void get_auth_login(CONTYP *contact,char **rmtpass)
+
+{
+static char *logdat[]={"VXNlcm5hbWU6", //Username: in B64
+ "UGFzc3dvcmQ6", //Password: in B64
+ (char *)0};
+char local[200];
+
+(void) memset(local,'\000',sizeof(local));
+for (int i=0;i<2;i++) {
+ char *line;
+ char *ptr;
+ int got;
+
+ (void) strcat(local,IOBNULL);
+ (void) eml_transmit(contact,true,"%d %s",SENDB64,logdat[i]);
+ got=tcp_getline(contact->socptr,contact->delay,&line);
+ if (got<=0) {
+ const char *ninfo="%d 5.7.2 auth sequence missing";
+
+ (void) strcpy(local,"");
+ (void) eml_note(contact,NULL,ninfo,UKNUSER);
+ (void) eml_transmit(contact,true,ninfo,UKNUSER);
+ break; //exiting from loop
+ }
+ (void) log_fprintlog(contact->logptr,false,"%s",line);
+ if ((ptr=cnv_getb64(line))!=(char *)0) {
+ (void) strncat(local,ptr,(sizeof(local)-1)-strlen(ptr));
+ ptr=rou_freestr(ptr);
+ }
+ line=rou_freestr(line);
+ }
+if (strlen(local)>0) {
+ if (checklogin(contact,rmtpass,local)==true) {
+ contact->credit+=2;
+ contact->privilege=rel_authentic;
+ }
+ }
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to manage authentication in */
+/* digest-md5 mode. */
+/* Return a builded "decoded" string from */
+/* the exchange with the remote sereur */
+/* see RFC 2831. */
+/* */
+/* */
+/********************************************************/
+static void get_auth_digest_md5(CONTYP *contact,char **rmtpass)
+
+{
+#define OPEP "lvleml.c:get_auth_digest_md5,"
+
+char *challenge;
+RSPTYP *resp;
+char answer[300];
+char hash[40];
+int phase;
+_Bool proceed;
+
+*rmtpass=strdup("$1(a_digest_md5)");
+challenge=(char *)0;
+resp=(RSPTYP *)0;
+(void) memset(answer,'\000',sizeof(answer));
+(void) memset(hash,'\000',sizeof(hash));
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //assign the reaml challeng
+ break;
+ case 1 : //Building the challenge sequence
+ if ((challenge=dig_getchallenge())==(char *)0) {
+ (void) rou_alert(0,"%s Unable to get challenge sequence (Bug!)",OPEP);
+ phase=999;
+ }
+ break;
+ case 2 : { //sending challenge to remote
+ char *b64;
+
+ b64=cnv_setb64(challenge);
+ (void) eml_transmit(contact,true,"%d %s",SENDB64,b64);
+ b64=rou_freestr(b64);
+ }
+ break;
+ case 3 : { //getting the challenge answer
+ char *line;
+
+ if (tcp_getline(contact->socptr,contact->delay,&line)>0) {
+ //if a clear text QUIT is received because of deep trouble
+ if (strcasecmp(line,"QUIT")!=0) {
+ char *res;
+
+ res=cnv_getb64(line);
+ (void) rou_alert(2,"%s received=<%s>",OPEP,res);
+ (void) snprintf(answer,sizeof(answer),"%s",res);
+ res=rou_freestr(res);
+ }
+ line=rou_freestr(line);
+ }
+ if (strlen(answer)==0)
+ phase=999; //no need to go further
+ }
+ break;
+ case 4 : //Parsing the answer
+ if ((resp=dig_parseresp(answer))==(RSPTYP *)0)
+ phase=999; //Unable to parse answer
+ break;
+ case 5 : //checking if we have a user name
+ if (resp->username==(char *)0) {
+ (void) rou_alert(0,"%s No username in challenge answer!",OPEP);
+ phase=999; //Unable to parse answer
+ }
+ break;
+ case 6 : { //getting the user name and password
+ USRTYP *usr;
+
+ contact->authname=rou_freestr(contact->authname);
+ contact->authname=strdup(resp->username);
+ if (sql_mngusr(contact->sqlptr,sql_select,resp->username,&usr)==true) {
+ if (usr->hash!=(char *)0)
+ (void) strncpy(hash,usr->hash,sizeof(hash)-1);
+ usr=sql_freeusr(usr);
+ }
+ if (strlen(hash)==0) {
+ (void) rou_alert(0,"%s user <%s> missing hash value!",OPEP,resp->username);
+ phase=999; //No need to go further
+ }
+ }
+ break;
+ case 7 : { //sending the rspauth sequence.
+ char *HAS;
+ char *rspauth;
+ char *b64;
+
+ if ((HAS=dig_hashresp(resp,"",hash))==(char *)0) {
+ (void) rou_alert(0,"%s Unable to get the hash rspauth (Bug!)",OPEP);
+ break;
+ }
+ (void) rou_asprintf(&rspauth,"rspauth=%s",HAS);
+ b64=cnv_setb64(rspauth);
+ (void) eml_transmit(contact,true,"%d %s",SENDB64,b64);
+ b64=rou_freestr(b64);
+ rspauth=rou_freestr(rspauth);
+ HAS=rou_freestr(HAS);
+ }
+ break;
+ case 8 : { //waiting client to send an empty line
+ char *line;
+ int count;
+
+ line=(char *)0;
+ count=tcp_getline(contact->socptr,contact->delay,&line);
+ if (count<0)
+ (void) rou_alert(0,"%s delay expired to get remote empty line (network?)",
+ OPEP);
+ line=rou_freestr(line); //EMPTY Line!
+ }
+ break;
+ case 9 : { //comparing result.
+ char *HA0;
+
+ if ((HA0=dig_hashresp(resp,"AUTHENTICATE",hash))==(char *)0) {
+ (void) rou_alert(0,"%s Unable to get the hash response (Bug!)",OPEP);
+ break;
+ }
+ if (strcmp(HA0,resp->response)==0) {
+ contact->credit+=3; //very good authentication
+ contact->privilege=rel_authentic;
+ }
+ HA0=rou_freestr(HA0);
+ }
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+resp=dig_freeresp(resp);
+challenge=rou_freestr(challenge);
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to extract authentication info. */
+/* return a login sequence as */
+/* 'username password' if successful */
+/* NULL if unable to extract login */
+/* */
+/********************************************************/
+static _Bool getauth(CONTYP *contact,char *buffer)
+
+{
+#define OPEP "lvleml.c:getauth,"
+#define DISP "---- "
+
+static char *vocloc[]={"PLAIN","LOGIN","DIGEST-MD5",(char *)0};
+
+int code;
+char *rmtpass;
+char local[200];
+int phase;
+_Bool proceed;
+
+code=-1;
+rmtpass=(char *)0;
+(void) memset(local,'\000',sizeof(memset));
+phase=0;
+proceed=true;
+while (proceed==true) {
+ (void) rou_dbglive(9,OPEP,"phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //empty phase
+ break;
+ case 1 : //check buffer
+ if ((buffer==(char *)0)||(strlen(buffer)==0)) {
+ const char *ninfo="%d 5.7.1 Missing auth type";
+
+ (void) eml_note(contact,NULL,ninfo,UKNUSER);
+ (void) eml_transmit(contact,true,ninfo,UKNUSER);
+ phase=999; //No need to go further
+ }
+ break;
+ case 2 : //check the authentication type
+ (void) strncpy(local,buffer,sizeof(local)-1);
+ for (code=0;vocloc[code]!=(char *)0;code++) {
+ if (strncasecmp(local,vocloc[code],strlen(vocloc[code]))==0) {
+ register int taille;
+ register char *ptr;
+
+ taille=strlen(vocloc[code]);
+ ptr=local+taille+1;
+ (void) memcpy(local,ptr,strlen(ptr)+1);
+ break;
+ }
+ }
+ if (vocloc[code]==(char *)0) {
+ static char *cmt="bad authentication type";
+
+ (void) rou_alert(0,"%s auth type <%s> unknown (Bug?)",OPEP,local);
+ (void) eml_note(contact,NULL,"%d %s",BADPAR,cmt);
+ (void) eml_transmit(contact,true,"%d 5.7.2 %s",BADPAR,cmt);
+ (void) setterminator(contact,cmt);
+ phase=999; //Trouble Trouble
+ }
+ break;
+ case 3 : //getting "username password" accorind login type
+ switch (code) {
+ case 0 : //AUTH PLAIN
+ if (soc_iscrypted(contact->socptr)==true)
+ (void) get_auth_plain(contact,local,&rmtpass);
+ else {
+ static char *cmt="Unsafe PLAIN auth mode";
+
+ contact->credit-=2;
+ (void) eml_note(contact,NULL,"%d %s",FAILED,cmt);
+ (void) eml_transmit(contact,true,"%d 5.7.3 %s",FAILED,cmt);
+ (void) setterminator(contact,cmt);
+ phase=999;
+ }
+ break;
+ case 1 : //AUTH LOGIN
+ if (soc_iscrypted(contact->socptr)==true)
+ (void) get_auth_login(contact,&rmtpass);
+ else {
+ static char *cmt="Unsafe LOGIN auth mode";
+
+ contact->credit-=2;
+ (void) eml_note(contact,NULL,"%d %s",FAILED,cmt);
+ (void) eml_transmit(contact,true,"%d 5.7.3 %s",FAILED,cmt);
+ (void) setterminator(contact,cmt);
+ phase=999;
+ }
+ break;
+ case 2 : //AUTH DIGEST-MD5
+ (void) get_auth_digest_md5(contact,&rmtpass);
+ break;
+ default : { //not yet implemented
+ static char *cmt="Unexpected auth mode";
+
+ (void) rou_alert(0,"%s auth type <%d> not yet implemented (Bug?!)",
+ OPEP,code);
+ (void) eml_note(contact,NULL,"%d 5.7.5 %s",FAILED,cmt);
+ (void) eml_transmit(contact,true,"%d 5.7.5 %s",FAILED,cmt);
+ (void) setterminator(contact,cmt);
+ phase=999;
+ }
+ break;
+ }
+ break;
+ case 4 : { //do we have a decoded sequence??
+ char *fmt;
+ char *auth;
+
+ fmt=DISP"Auth accepted for user=<%s>";
+ auth=contact->authname;
+ if (contact->privilege!=rel_authentic) {
+ fmt=DISP"Auth Rejected status='%d' for user=<%s> pass=<%s>";
+ (void) log_fprintlog(contact->logptr,true,fmt,BADAUTH,auth,rmtpass);
+ (void) sleep(2);
+ (void) eml_note(contact,NULL,"%d user <%s> pass=<%s> bad authentication",
+ BADAUTH,auth,rmtpass);
+ (void) eml_transmit(contact,true,"%d 5.7.4 wrong authentication",BADAUTH);
+ (void) setterminator(contact,"Authentication failure");
+ contact->credit-=1;
+ phase=999;
+ }
+ else {
+ (void) log_fprintlog(contact->logptr,true,fmt,auth);
+ (void) eml_note(contact,NULL,"%d 5.7.5 authentication successful",IDOK);
+ (void) eml_transmit(contact,true,"%d 5.7.5 authentication successful",IDOK);
+ contact->credit+=2;
+ }
+ }
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+rmtpass=rou_freestr(rmtpass);
+return (contact->privilege==rel_authentic);
+
+#undef DISP
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* checking if local recipient is acceptable. */
+/* */
+/********************************************************/
+static _Bool is_user_good(CONTYP *contact,char *rcptto)
+
+{
+_Bool isok;
+USRTYP *usr;
+int phase;
+_Bool proceed;
+
+isok=false;
+usr=(USRTYP *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //is user a local user
+ if ((sql_mngusr(contact->sqlptr,sql_select,rcptto,&usr))==false) {
+ (void) eml_note(contact,rcptto,"%d 5.6.0 <%s> unknown user",
+ UKNUSER,rcptto);
+ (void) eml_transmit(contact,true,"%d 5.6.0 <%s> unknown user",
+ UKNUSER,rcptto);
+ phase=999; //No user found in database
+ }
+ break;
+ case 1 : //are we in relaying mode
+ switch (contact->privilege) {
+ case rel_authentic :
+ case rel_isrelay : //everything fine
+ isok=true; //we accepte "internal user"
+ phase=999; //no need to check lock and spf
+ break;
+ default :
+ break;
+ }
+ break;
+ case 2 : //is user lock?
+ if (usr->lock==1) {
+ (void) eml_note(contact,rcptto,"%d 5.6.1 <%s> account lock",
+ EXPIRED,rcptto);
+ (void) eml_transmit(contact,true,"%d 5.6.1 <%s> account lock",
+ EXPIRED,rcptto);
+ phase=999; //No user found in database
+ }
+ break;
+ case 3 : //check is origin is SPF OK
+ switch (contact->fromspf) {
+ case spf_neutral : //'?' status
+ case spf_pass : //good SPF
+ isok=true;
+ break;
+ case spf_fail : //Bad SPF
+ (void) eml_note(contact,rcptto,"%d 5.6.6 %s from IP=[%s]",
+ FAILED,"Relaying not allowed",
+ contact->peerip);
+ (void) eml_transmit(contact,rcptto,"%d 5.6.6 %s from IP=[%s]",
+ FAILED,"Relaying not allowed",
+ contact->peerip);
+ break;
+ case spf_softfail : //Bad SPF
+ (void) eml_note(contact,rcptto,"%d 5.6.7 %s from IP=[%s]",
+ FAILED,"SPF soft fail not allowed",
+ contact->peerip);
+ (void) eml_transmit(contact,rcptto,"%d 5.6.7 %s from IP=[%s]",
+ FAILED,"SPF soft fail not allowed",
+ contact->peerip);
+ break;
+ default : //trouble trouble
+ (void) eml_note(contact,rcptto,"%d 5.6.8 %s (<%s> SPF unknown)",
+ FAILED,
+ "Originator domain BAD SPF definition",
+ contact->mailfrom);
+ (void) eml_transmit(contact,true,"%d 5.6.8 %s (<%s> SPF unknown)",
+ FAILED,
+ "Originator domain BAD SPF definition",
+ contact->mailfrom);
+ break;
+ }
+ break;
+ default : //SAFE Guard
+ usr=sql_freeusr(usr);
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return isok;
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* checking if remote recipient is relayable. */
+/* */
+/********************************************************/
+static _Bool is_remote_good(CONTYP *contact,RCPTYP *rmtusr)
+
+{
+#define OPEP "lvleml.c:is_remote_good,"
+
+_Bool remotegood;
+const char *cmt;
+int phase;
+_Bool proceed;
+
+remotegood=false;
+cmt=(const char *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : { //Is there an MX for the user remote domain
+ MXTYP **mxs;
+
+ cmt="No MX nor IP for";
+ if ((mxs=dns_getmx(rmtusr->domain))!=(MXTYP **)0) {
+ for (int i=0;mxs[i]!=(MXTYP *)0;i++) {
+ if (mxs[i]->mxip!=(char **)0) {
+ phase++; //No need to check for domain IP
+ break;
+ }
+ }
+ mxs=dns_freemxlist(mxs);
+ }
+ }
+ break;
+ case 1 : { //is the domain with an IP address
+ char **iplist;
+
+ if ((iplist=dns_get_ip_list(rmtusr->domain))==(char **)0)
+ phase=999; //not even an IP for domain
+ iplist=(char **)rou_freelist((void **)iplist,(genfree_t)rou_freestr);
+ }
+ break;
+ case 2 : //is connection acceptable
+ switch (contact->privilege) {
+ case rel_authentic :
+ case rel_isrelay : //everything fine
+ break;
+ case rel_plain :
+ cmt="No relay accepted";
+ contact->credit-=2; //Trying to abuse server
+ phase=999; //not relayable
+ break;
+ default :
+ cmt="Unchecked status";
+ phase=999; //not relayable
+ break;
+ }
+ break;
+ case 3 : //so it a good remote
+ remotegood=true;
+ break;
+ default : //SAFE Guard
+ if (remotegood==false) {
+ char *rcptto;
+
+ (void) rou_asprintf(&rcptto,"%s@%s",rmtusr->userid,rmtusr->domain);
+ (void) eml_note(contact,rcptto,"%d 2.8.0 %s for domain <%s>",
+ NORELAY,cmt,rmtusr->domain);
+ (void) eml_transmit(contact,true,"%d 2.8.0 %s for domain <%s>",
+ NORELAY,cmt,rmtusr->domain);
+ rcptto=rou_freestr(rcptto);
+ }
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return remotegood;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to check if helo or ehlo parameter */
+/* is a correct one */
+/* */
+/********************************************************/
+static _Bool isgoodfqdn(CONTYP *contact,char *parameter)
+
+{
+#define OPEP "lvleml.c:isgoodfqdn"
+#define HELL " !@#$%^&*()=+[]{}|\\:;'\"<>,?"
+
+_Bool good;
+int phase;
+_Bool proceed;
+
+good=false;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ (void) rou_dbglive(7,OPEP,"phase='%d' parm=<%s>",phase,parameter);
+ switch (phase) {
+ case 0 : //is parameter starting with '.'
+ if ((parameter[0]=='.')||(parameter[0]=='-'))
+ phase=999; //no allowed to start with dot or dash
+ break;
+ case 1 : //do we have '..' somewehre
+ if ((strstr(parameter,"..")!=(char *)0)||
+ (strstr(parameter,"-.")!=(char *)0)||
+ (strstr(parameter,".-")!=(char *)0))
+ phase=999; //no allowed to start with dot
+ break;
+ case 2 : //check if char set is allowed
+ if (strpbrk(parameter,HELL)!=(char *)0)
+ phase=999; //no a good charset
+ break;
+ case 3 : //checking if parameter is only ascii
+ int taille;
+
+ taille=strlen(parameter);
+ for (int i=0;i<taille;i++) {
+ if (isascii(parameter[i])==false) {
+ phase=999; //non ascii charatere
+ break;
+ }
+ }
+ break;
+ case 4 : //seems to be a good fqdn
+ good=true;
+ contact->fqdn=rou_freestr(contact->fqdn);
+ contact->fqdn=strdup(parameter);
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return good;
+
+#undef HELL
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to check if helo or ehlo parameter */
+/* is an acceptable one */
+/* */
+/********************************************************/
+static _Bool isgoodhelo(CONTYP *contact,char *parameter)
+
+{
+#define OPEP "lvleml.c:isgoodhelo"
+#define DETAIL "HELO argument is incorrect, closing connection"
+
+_Bool good;
+int last;
+char original[100];
+int phase;
+_Bool proceed;
+
+good=false;
+last=0;
+(void) memset(original,'\000',sizeof(original));
+phase=0;
+proceed=true;
+while (proceed==true) {
+ (void) rou_dbglive(7,OPEP,"phase='%d' domain=<%s>",phase,parameter);
+ switch (phase) {
+ case 0 : //checking if we have a parameter
+ if (parameter==(char *)0) {
+ (void) rou_alert(0,"%s sesid=<%s> fqdn is missing!",
+ OPEP,contact->mainsesid);
+ phase=999; //no parameter
+ }
+ break;
+ case 1 : //strip possible space at the end pf parameter
+ (void) strncpy(original,parameter,sizeof(original)-1);
+ last=strlen(parameter)-1;
+ while ((parameter[last]==' ')&&(last>=0)) {
+ parameter[last]='\000';
+ last--;
+ }
+ break;
+ case 2 : //cannot start with '.'
+ if (parameter[0]=='.') {
+ (void) rou_alert(0,"%s sesid=<%s> wrong fqdn=<%s>"
+ OPEP,contact->mainsesid,parameter);
+ phase=999; //wrong parameter
+ }
+ break;
+ case 3 : //check if we have an fqdn
+ if ((good=isgoodfqdn(contact,parameter))==true)
+ phase=999;
+ break;
+ case 4 : //is it an enclosed IP
+ if ((parameter[0]=='[')&&(parameter[last]==']')) {
+ parameter[last]='\000';
+ (void) memmove(parameter,parameter+1,last);
+ last--;
+ last--;
+ if (strlen(parameter)==0) {
+ phase=999;
+ }
+ }
+ break;
+ case 5 : //checking if it is starting or endig with dot
+ if ((parameter[0]=='.')||(parameter[last]=='.'))
+ phase=999; //yes but not acceptable
+ break;
+ case 6 : //checking fi double dot inside
+ if (strstr(parameter,"..")!=(char *)0)
+ phase=999; //yes but not acceptable
+ break;
+ case 7 : //are all character good
+ if (strlen(parameter)==strspn(parameter,".0123456789"))
+ good=true;
+ break;
+ default : //SAFE guard
+ if (good==false) {
+ (void) eml_note(contact,NULL,"%d 5.5.4 %s.",BADPAR,DETAIL);
+ (void) eml_transmit(contact,true,"%d 5.5.4 %s.",BADPAR,DETAIL);
+ }
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return good;
+
+#undef DETAIL
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to set create the sessid count*/
+/* file. This file is used to keep track */
+/* of the number of the sessionid|(rcpt) */
+/* used to send email to all recipient. */
+/* */
+/************************************************/
+static _Bool setcountfile(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:setcountfile,"
+
+_Bool status;
+int num;
+FILE *qfile;
+int phase;
+_Bool proceed;
+
+status=false;
+num=0;
+qfile=(FILE *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //is contact good
+ if ((contact==(CONTYP *)0)||(contact->session==(SESTYP *)0)) {
+ (void) rou_alert(0,"%s contact pointer or session is NULL (bug?)",OPEP);
+ phase=999;
+ }
+ break;
+ case 1 : //counting recipient number
+ if ((num=rou_nbrlist((void **)contact->recipients))==0)
+ phase=999; //No recipient!
+ break;
+ case 2 : //creating the count file
+ if ((qfile=eml_createqfile(contact->session->sessid,EXTCNT))==(FILE *)0) {
+ (void) rou_alert(0,"%s Unable to open 'count' qfile <%s> (error=<%s>)",
+ OPEP,contact->session->sessid,strerror(errno));
+ phase=999;
+ }
+ break;
+ case 3 : //inserting number of receipient
+ if (fprintf(qfile,"%d\n",num)<1) {
+ (void) rou_alert(0,"%s Unable to set 'count' in qfile <%s> (error=<%s>)",
+ OPEP,contact->session->sessid,strerror(errno));
+ (void) fclose(qfile);
+ phase=999; //trouble trouble
+ }
+ break;
+ case 4 : //closing count file
+ if (fclose(qfile)!=0) {
+ (void) rou_alert(0,"%s Unable to close qfile <%s> (error=<%s>)",
+ OPEP,contact->session->sessid,strerror(errno));
+ phase=999; //trouble trouble
+ }
+ break;
+ case 5 : //everything fine
+ status=true;
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return status;
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to set RCPT directive to */
+/* forward email to SMTP peers. */
+/* */
+/************************************************/
+static _Bool setdirectives(CONTYP *contact,char *ext)
+
+{
+#define OPEP "lvleml.c:setdirectives,"
+
+_Bool status;
+FILE *trans;
+int phase;
+_Bool proceed;
+
+status=false;
+trans=(FILE *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //Creating the file
+ if ((trans=eml_createqfile(contact->session->sessid,ext))==(FILE *)0)
+ phase=999; //trouble trouble
+ break;
+ case 1 : //write data to trans file;
+ if (eml_mktransfile(contact,trans)==false) {
+ (void) eml_closeqfile(trans);
+ phase=999; //Trouble trouble
+ }
+ break;
+ case 2 : //closing transfile
+ if (eml_closeqfile(trans)<0)
+ phase=999; //Trouble trouble
+ break;
+ case 3 : //everythin fine
+ status=true;
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+#undef OPEP
+return status;
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to send a simple SMTP ccommand*/
+/* (no need to have the response wording) */
+/* */
+/************************************************/
+static int simple_smtp_command(RMTTYP *rmt,char *fmt,...)
+
+{
+va_list args;
+char strloc[300];
+
+va_start(args,fmt);
+(void) vsnprintf(strloc,sizeof(strloc),fmt,args);
+va_end(args);
+return tcp_smtp_command(rmt,(char ***)0,strloc);
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to accept EMAIL contents from */
+/* SMTP peers. */
+/* Return true, if everything is fine */
+/* */
+/************************************************/
+//NOTE
+//MAIL FROM <sender> [BODY=7BIT|BODY=8BITMIME] [SIZE=number_of_bytes]
+static _Bool getdata(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:getdata,"
+#define EXTMP "tmp"
+
+_Bool done;
+FILE *queue;
+_Bool inheader;
+_Bool completed;
+u_long total;
+TIMESPEC start;
+int phase;
+_Bool proceed;
+
+done=false;
+queue=(FILE *)0;
+inheader=true;
+completed=false;
+total=0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //checking if we have recipient
+ if (rou_nbrlist((void **)contact->recipients)==0) {
+ char *cmt;
+
+ cmt="RCPT first. transaction protocol command out of sequence";
+ (void) eml_transmit(contact,true,"%d 5.5.0 %s",BADSEQ,cmt);
+ done=true; //lets say DATA will be issued
+ proceed=false; //No recipients
+ }
+ break;
+ case 1 : //opening the queue email
+ if ((queue=eml_createqfile(contact->session->sessid,""))==(FILE *)0)
+ phase=999; //trouble trouble
+ break;
+ case 2 : //adding received stamp to file
+ if (addreceived(contact,queue)==false)
+ phase=999; //trouble trouble
+ break;
+ case 3 : //sending 'go ahead' to remote
+ (void) clock_gettime(CLOCK_REALTIME,&start);
+ (void) eml_transmit(contact,true,"%d 3.5.0 %s",
+ DATAOK,"End data with <CR><LF>.<CR><LF>");
+ break;
+ case 4 : //get incoming line, detect 'single dot' as end
+ while (completed==false) {
+ int got;
+ char *line;
+
+ completed=false;
+ got=tcp_getline(contact->socptr,WAITRMT,&line);
+ if (got<0) { //data timeout
+ phase=999; //trouble trouble
+ break; //exiting loop
+ }
+ total+=got;
+ if (inheader==true) {
+ (void) eml_scan_headerline(contact->session,line);
+ if (strlen(line)==0)
+ inheader=false;
+ }
+ if (strcmp(line,".")==0) {
+ completed=true;
+ }
+ else {
+ if ((strlen(line)>1)&&(line[0]=='.'))
+ (void) memmove(line,line+1,strlen(line));
+ (void) fprintf(queue,"%s\n",line);
+ }
+ line=rou_freestr(line);
+ }
+ break;
+ case 5 : //got all data
+ if (eml_closeqfile(queue)<0)
+ phase=999; //Trouble trouble
+ break;
+ case 6 : //creating the count file
+ if (setcountfile(contact)==false)
+ phase=999; //Unable to create count file???
+ break;
+ case 7 : //renameing directive
+ contact->session->taille=total;
+ (void) setdirectives(contact,EXTMP);
+ if (eml_renameqfile(contact->session->sessid,EXTMP,EXTRANS)==false)
+ phase=999; //Trouble trouble
+ break;
+ case 8 : //everything fine
+ const char *fmt;
+ unsigned int delta;
+ char duration[40];
+
+ total+=1023;
+ total/=1024; //KBytes
+ delta=rou_getdifftime(&start);
+ (void) snprintf(duration,sizeof(duration),"%d.%03d",delta/1000,delta%1000);
+ contact->session->duration=strdup(duration);;
+ fmt="%d-3.5.3 Session ID=<%s>";
+ (void) eml_transmit(contact,false,fmt,CMDOK,contact->session->sessid);
+ fmt="%d-3.5.3 data stream received: %d Kbytes within %s seconds)";
+ (void) eml_transmit(contact,false,fmt,CMDOK,total,duration);
+ fmt="%d 3.5.3 Message accepted for delivery";
+ (void) eml_transmit(contact,true,fmt,CMDOK,contact->session->sessid);
+ done=true;
+ proceed=false; //task done
+ break;
+ default : //SAFE guard
+ (void) eml_transmit(contact,true,"%d 5.5.4 Server does not accept mail",
+ DATRJC);
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return done;
+
+#undef EXTMP
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to send an "HELO" message */
+/* if EHLO message is not accepted. */
+/* */
+/************************************************/
+static _Bool dohelo(CONTYP *contact,char *parameter)
+
+{
+#define OPEP "lvleml.c:dohelo"
+
+_Bool done;
+
+if ((done=isgoodhelo(contact,parameter))==false) {
+ (void) setterminator(contact,"HELO parameter missing");
+ contact->credit-=2;
+ }
+else
+ (void) linkready(contact,false);
+return done;
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to send an "HELO" message */
+/* if EHLO message is not accepted. */
+/* */
+/************************************************/
+static _Bool doehlo(CONTYP *contact,char *parameter)
+
+{
+static struct {
+ int display; //0 ->always, 1-->plain 2-->crypted
+ char *str; //the message to display
+ }ehlo[]={
+ {1,"STARTTLS"},
+ {1,"AUTH DIGEST-MD5"},
+ {2,"AUTH PLAIN LOGIN DIGEST-MD5"},
+ {0,"SIZE "MXMSIZE},
+ {0,"8BITMIME"},
+ {0,"ENHANCEDSTATUSCODES"},
+ {0,(char *)0}
+ };
+
+#define OPEP "lvleml.c:doehlo"
+
+_Bool done;
+int strstart;
+int phase;
+_Bool proceed;
+
+done=false;
+strstart=0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //Do we have a parameter
+ if ((done=isgoodhelo(contact,parameter))==false) {
+ (void) setterminator(contact,"HELO parameter incorrect");
+ contact->credit-=2; //penalty
+ phase=999; //Trouble trouble
+ }
+ break;
+ case 1 : //thereis an FQDN
+ (void) linkready(contact,true);
+ if (soc_iscrypted(contact->socptr)==true)
+ strstart++;
+ for (int i=strstart;ehlo[i].str!=(char *)0;i++) {
+ char space;
+
+ space='-';
+ if (ehlo[i+1].str==(char *)0)
+ space=' ';
+ switch (ehlo[i].display) {
+ case 0 : //always display
+ break;
+ case 1 : //display on plain only
+ if (soc_iscrypted(contact->socptr)==true)
+ continue;
+ break;
+ case 2 : //display on crypted only
+ if (soc_iscrypted(contact->socptr)==false)
+ continue;
+ break;
+ }
+ (void) eml_transmit(contact,false,"%d%c%s",CMDOK,space,ehlo[i].str);
+ }
+ (void) eml_transmit(contact,true,"");
+ done=true;
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return done;
+#undef DETAIL
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to manage a "ORGN:" */
+/* command from the SMTP client. */
+/* Purpose of this command is to simulate */
+/* (or overide) the IP remote client. */
+/* */
+/* NOTE: Only compiled in debug mode. */
+/* */
+/************************************************/
+#ifdef MODEDEBUG
+
+static _Bool set_orgn_rmtip(CONTYP *contact,char *rmtip)
+
+{
+#define OPEP "lvleml.c:set_orgn_rmtip,"
+
+_Bool isok;
+AFNTYP *afn;
+int phase;
+_Bool proceed;
+
+isok=false;
+afn=(AFNTYP *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //is the new IP valide
+ if ((afn=afn_getoneipnum(rmtip))==(AFNTYP *)0) {
+ (void) rou_alert(0,"%s <%s> is not a good ip (Testing?)",OPEP,rmtip);
+ phase=999;
+ }
+ break;
+ case 1 : //we have good ip, lets disconnect previous
+ if (sql_newconnect(contact->sqlptr,contact->peerip,-1)<0) {
+ (void) rou_alert(0,"%s Unable to update database remotes table (system?)"
+ OPEP);
+ phase=999;
+ }
+ break;
+ case 2 : { //ready to change IP'
+ char *reverse;
+
+ contact->peerip=rou_freestr(contact->peerip);
+ contact->peerip=strdup(rmtip);
+ reverse=afn_reversipnum(afn);
+ contact->peername=rou_freestr(contact->peername);
+ contact->peername=dns_get_reverse_addr(reverse);
+ reverse=rou_freestr(reverse);
+ }
+ break;
+ case 3 : //adjust privilege according new IP
+ switch (contact->privilege) {
+ case rel_authentic :
+ break;
+ case rel_isrelay : //need to force rel_plain
+ contact->privilege=rel_plain;
+ //NO BREAK;
+ case rel_plain :
+ if (afn_is_ip_relayable(contact->peerip,contact->relayok)==true)
+ contact->privilege=rel_isrelay; //IP is relayable
+ break;
+ default :
+ (void) rou_alert(0,"%s unexpected privilege '%d' (Bug?)",
+ OPEP,contact->privilege);
+ phase=999;
+ break;
+ }
+ break;
+ case 4 : //let update links
+ if (sql_newconnect(contact->sqlptr,rmtip,1)!=1) {
+ static char *end;
+
+ end="You have another connection still in progress";
+ (void) rou_alert(0,"%s <%s> Too many '%d' links! (Testing?)",
+ OPEP,rmtip,sql_newconnect(contact->sqlptr,rmtip,0));
+ (void) eml_transmit(contact,true,"%d contact denied <%s>",NOTNOW,end);
+ contact->termend=rou_freestr(contact->termend);
+ contact->termend=strdup(end);
+ contact->credit=-1; //small penalty
+ (void) sleep(1); //To avoid avalanche
+ (void) sql_newconnect(contact->sqlptr,rmtip,-1);
+ phase++; //connection rejected
+ }
+ break;
+ case 5 : //everything is now fine
+ (void) signon(contact);
+ isok=true;
+ break;
+ default : //SAFE Guard
+ afn=afn_freeipnum(afn);
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return isok;
+
+#undef OPEP
+}
+#endif
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to manage a "MAIL FROM:" */
+/* ommand from the SMTP client. */
+/* */
+/************************************************/
+static _Bool checkfrom(CONTYP *contact,char *mailfrom)
+
+{
+#define OPEP "lvleml.c:checkfrom"
+
+_Bool success;
+char *strsize;
+int status;
+int phase;
+_Bool proceed;
+
+success=false;
+strsize=(char *)0;
+status=CMDOK;
+proceed=true;
+phase=0;
+while (proceed==true) {
+ (void) rou_dbglive(9,OPEP,"Phase='%d'",phase);
+ switch (phase) {
+ case 0 : //do we have an originator
+ if ((mailfrom==(char *)0)||(strlen(mailfrom)<3)) {
+ (void) eml_transmit(contact,true,"%d 5.5.0 <%s> originator not specified",
+ BADPAR,mailfrom);
+ phase=999; //no need to go further
+ }
+ break;
+ case 1 : //do we have already a from
+ if (contact->mailfrom!=(char *)0) {
+ (void) eml_transmit(contact,true,"%d 5.5.1 '%s' %s",
+ BADPAR,contact->mailfrom,
+ "was previously defined as originator");
+ phase=999; //no need to go further
+ }
+ break;
+ case 2 : //do we have SIZE= component
+ if ((strsize=strchr(mailfrom,' '))!=(char *)0) {
+ while (*strsize==' ') {
+ *strsize='\000';
+ strsize++;
+ }
+ //JMPDBG need to check size
+ }
+ break;
+ case 3 : //check from format
+ if ((mailfrom[0]!='<')||(mailfrom[strlen(mailfrom)-1]!='>')) {
+ (void) eml_transmit(contact,true,"%d 5.5.3 '%s' bad Format error",
+ BADPAR,mailfrom);
+ phase=999; //no need to go further
+ }
+ mailfrom[strlen(mailfrom)-1]='\000';
+ (void) memmove(mailfrom,mailfrom+1,strlen(mailfrom));
+ break;
+ case 4 : //check if contact authenticated
+ switch (contact->privilege) {
+ case rel_isrelay : //Remote IP was already relaying
+ //NO BREAK;
+ case rel_authentic : //User was authenticated
+ break;
+ case rel_plain : //remote IP is plain
+ if ((status=checkcredit(contact))!=CMDOK) {
+ contact->credit=-1; //found bad guy.
+ (void) eml_transmit(contact,true,"%d 5.5.4 Closing connection",status);
+ phase=999; //bad credit not need to go further
+ }
+ break;
+ default :
+ (void) rou_alert(0,"%s unexpected priviliged='%d' (Bug?)",
+ OPEP,contact->privilege);
+ (void) eml_transmit(contact,true,"%d 5.5.5 Closing connection",FAILED);
+ phase=999; //bad credit not need to go further
+ break;
+ }
+ break;
+ case 5 : //Checking if the SPF is good from the originator
+ contact->fromspf=spf_getspf(mailfrom,contact->peerip);
+ (void) rou_dbglive(5,OPEP,"found SPF for <%s/[%s]> to be <%s>",
+ mailfrom,contact->peerip,
+ spf_spfASCII(contact->fromspf));
+ break;
+ case 6 : //everything ok
+ contact->mailfrom=strdup(mailfrom);
+ (void) eml_transmit(contact,true,"%d 2.1.3 %s sender ok",
+ CMDOK,contact->mailfrom);
+ success=true;
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return success;
+
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to manage a "RCPT TO:" */
+/* command from the SMTP client. */
+/* */
+/************************************************/
+static _Bool checkto(CONTYP *contact,char *rcptto)
+
+{
+#define OPEP "lvleml.c:checkto,"
+_Bool success;
+RCPTYP *neu;
+const char *detail;
+char *report;
+_Bool proceed;
+int phase;
+
+success=false;
+neu=(RCPTYP *)0;
+detail="Address will be processed";
+report=(char *)0;
+proceed=true;
+phase=0;
+while (proceed==true) {
+ (void) rou_dbglive(9,OPEP,"phase='%d' rcptto=<%s>",phase,rcptto);
+ switch (phase) {
+ case 0 : //do we have a mailfrom
+ if ((contact->mailfrom==(char *)0)||(strlen(contact->mailfrom)==0)) {
+ (void) eml_transmit(contact,true,"%d 5.6.0 Bad sequence of commands.",
+ BADSEQ);
+ phase=999; //no need to go further
+ }
+ break;
+ case 1 : //do we have an originator
+ if ((rcptto==(char *)0)||(strlen(rcptto)==0)) {
+ (void) eml_note(contact,rcptto,"%d 5.6.1 recipient not specified",BADPAR);
+ (void) eml_transmit(contact,true,"%d 5.6.1 recipient not specified",BADPAR);
+ phase=999; //no need to go further
+ }
+ break;
+ case 2 : //check rcpt format
+ if ((rcptto[0]!='<')||(rcptto[strlen(rcptto)-1]!='>')) {
+ (void) eml_note(contact,rcptto,"%d 5.6.2 '%s' bad Format error",
+ BADPAR,rcptto);
+ (void) eml_transmit(contact,true,"%d 5.6.2 '%s' bad Format error",
+ BADPAR,rcptto);
+ phase=999; //no need to go further
+ }
+ rcptto[strlen(rcptto)-1]='\000';
+ (void) memmove(rcptto,rcptto+1,strlen(rcptto));
+ break;
+ case 3 : //checking rcptto format
+ neu=eml_isemailok(rcptto,&report);
+ if (neu==(RCPTYP *)0) {
+ (void) eml_note(contact,rcptto,"%d 5.6.3 %s",NOTEML,report);
+ (void) eml_transmit(contact,true,"%d 5.6.3 %s",NOTEML,report);
+ report=rou_freestr(report);
+ phase=999; //no need to go further
+ }
+ break;
+ case 4 : //Do we have a domain MX
+ if (setlocdom(contact,neu)==false) {
+ (void) eml_note(contact,rcptto,"%d 5.6.4 %s (domain=%s)",
+ MISSMX,
+ "No valid MX found for recipient"
+ " domain name",
+ neu->domain);
+ (void) eml_transmit(contact,true,"%d 5.6.4 %s (domain=%s)",
+ MISSMX,
+ "No valid MX found for recipient"
+ " domain name",
+ neu->domain);
+ phase=999; //no need to go further
+ }
+ break;
+ case 5 : //if the local user acceptable
+ switch (neu->code) {
+ case 'L' : //local user/domain
+ if (is_user_good(contact,rcptto)==false)
+ phase=999;
+ break;
+ case 'R' : //remote user/domain
+ if (is_remote_good(contact,neu)==false)
+ phase=999;
+ break;
+ default :
+ (void) eml_transmit(contact,true," 5.6.5 %s (domain=%s,code='%c')",
+ FAILED,
+ "system error with domain status",
+ neu->domain,neu->code);
+ phase=999; //no need to go further
+ break;
+ }
+ break;
+ case 6 : //Storing rcpt to
+ if (eml_addrecipient(&(contact->recipients),neu)==false) {
+ detail="duplicate recipients will be consolidated";
+ neu=eml_freerecipient(neu);
+ }
+ break;
+ case 7 : //everything ok
+ (void) eml_note(contact,rcptto,"%d 5.6.7 %s <%s>",CMDOK,detail,rcptto);
+ (void) eml_transmit(contact,true,"%d 5.6.7 %s <%s>",CMDOK,detail,rcptto);
+ success=true;
+ break;
+ default : //SAFE guard
+ if (success==false)
+ neu=eml_freerecipient(neu);
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return success;
+#undef OPEP
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to reset the current session */
+/* */
+/************************************************/
+static _Bool doreset(CONTYP *contact,char *parameter)
+
+{
+#define LOCSEQ "2.1.0"
+
+(void) eml_transmit(contact,true,"%d-%s flushed session %s",
+ CMDOK,LOCSEQ,contact->session->sessid);
+(void) freesessid(contact);
+contact->numreset++;
+(void) getsessid(contact);
+contact->recipients=(RCPTYP **)rou_freelist((void **)(contact->recipients),
+ (genfree_t)eml_freerecipient);
+contact->mailfrom=rou_freestr(contact->mailfrom);
+(void) eml_transmit(contact,true,"%d %s opening new session %s",
+ CMDOK,LOCSEQ,contact->session->sessid);
+return true;
+
+#undef LOCSEQ
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send a confirmation ehlo on the */
+/* crypted link. */
+/* */
+/********************************************************/
+_Bool sendehlo(RMTTYP *rmt)
+
+{
+_Bool done;
+
+done=false;
+return done;
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send ehlo (or helo) to remote */
+/* MX server. */
+/* Return true if succesfull */
+/* */
+/********************************************************/
+static _Bool greetings_rmt(RMTTYP *rmt)
+
+{
+#define OPEP "lvleml.c:greetings_rmt,"
+
+_Bool done;
+int phase;
+_Bool proceed;
+
+done=false;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ int rspcode;
+
+ rspcode=ERRPROC;
+ switch (phase) {
+ case 0 : //Sending EHLO
+ rspcode=simple_smtp_command(rmt,"EHLO %s",rmt->orgdomain);
+ switch (rspcode) {
+ case CMDOK : //So fare, so good
+ break;
+ default : //Trouble
+ (void) rou_alert(0,"%s EHLO Remote <%s> unexpected answer code '%d'",
+ OPEP,rmt->curmx,rspcode);
+ phase++; //No STARTTLS available
+ break;
+ }
+ break;
+ case 1 : //Starting starttls
+ phase=999; //No need to go futher
+ rspcode=simple_smtp_command(rmt,"STARTTLS",rmt->orgdomain);
+ switch (rspcode) {
+ case SIGNON : //link is now encrypted
+ done=soc_starttls(rmt->socptr,false);
+ switch (done) {
+ case true : {
+ int level;
+
+ level=soc_get_sec_level(rmt->socptr);
+ (void) log_fprintlog(rmt->logptr,false,cry,"client",level);
+ (void) usleep(10000); //10 ms delay
+ rspcode=simple_smtp_command(rmt,"EHLO %s",rmt->orgdomain);
+ switch (rspcode) {
+ case CMDOK :
+ break;
+ default :
+ (void) log_fprintlog(rmt->logptr,false,"No server confirmation");
+ done=false;
+ break;
+ }
+ }
+ break;
+ case false :
+ (void) log_fprintlog(rmt->logptr,false,"Unable to set crypted link");
+ break;
+ }
+ phase=999; //link is now established
+ break;
+ default : //Trouble
+ (void) rou_alert(0,"%s Unable to establish crypted link with <%s>",
+ OPEP,rmt->curmx);
+ break;
+ }
+ break;
+ case 2 : //Sending HELO
+ rspcode=simple_smtp_command(rmt,"HELO %s",rmt->orgdomain);
+ switch (rspcode) {
+ case CMDOK : //So fare, so good
+ done=true;
+ phase=999;
+ break;
+ default : //Trouble
+ (void) rou_alert(0,"%s, HELO Remote <%s> unexpected answer code '%d'",
+ OPEP,rmt->curmx,rspcode);
+ break;
+ }
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return done;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to close the remote connection with MX*/
+/* */
+/********************************************************/
+static RMTTYP *close_mx(RMTTYP *rmt)
+
+{
+#define OPEP "lvleml.c:close_mx,"
+
+int phase;
+_Bool proceed;
+
+phase=0;
+proceed=(rmt!=(RMTTYP *)0);
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //need to disconnect
+ if (rmt->socptr!=(SOCPTR *)0) {
+ char **resp;
+ int rspcode;
+
+ resp=(char **)0;
+ rspcode=tcp_smtp_command(rmt,&resp,"QUIT");
+ switch (rspcode) {
+ case QUITOK : //Everything fine
+ break;
+ default :
+ (void) rou_alert(0,"%s Unexpected QUIT status='%d' (check code!)",
+ OPEP,rspcode);
+ break;
+ }
+ resp=(char **)rou_freelist((void **)resp,(genfree_t)rou_freestr);
+ rmt->socptr=soc_closefeedsock(rmt->socptr);
+ }
+ break;
+ case 1 : //free memory
+ rmt->mxs=dns_freemxlist(rmt->mxs);
+ rmt->orgdomain=rou_freestr(rmt->orgdomain);
+ rmt->dstdomain=rou_freestr(rmt->dstdomain);
+ (void) free(rmt);
+ rmt=(RMTTYP *)0;
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return rmt;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to connect to the remote SMTP server */
+/* */
+/********************************************************/
+static RMTTYP *connect_mx(LOGPTR *logptr,TRATYP *tra)
+
+{
+#define OPEP "lvleml.c:connect_to_mx,"
+
+_Bool done;
+char *orgdomain;
+char *dstdomain;
+MXTYP **mxs;
+RMTTYP *rmt;
+int phase;
+int proceed;
+
+done=false;
+orgdomain=strrchr(tra->sfrom,'@');
+dstdomain=strrchr(tra->rcptto,'@');
+mxs=(MXTYP **)0;
+rmt=(RMTTYP *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //preparing RMT record
+ if ((orgdomain==(char *)0)||(dstdomain==(char *)0)) {
+ char cmt[100];
+
+ (void) snprintf(cmt,sizeof(cmt),"from <%s> or rcpt <%s>, without domain",
+ tra->sfrom,tra->rcptto);
+ (void) log_fprintlog(rmt->logptr,false,cmt);
+ (void) rou_alert(0,"%s %s (Bug!)",OPEP,cmt);
+ phase=999;
+ }
+ break;
+ case 1 : //looking for MX list
+ orgdomain++;
+ dstdomain++;
+ mxs=dns_getmx(dstdomain);
+ if (mxs==(MXTYP **)0) {
+ (void) log_fprintlog(rmt->logptr,false,"NO MX found for domain <%s>",
+ dstdomain);
+ phase=999;
+ }
+ break;
+ case 2 : //creating rmt record
+ rmt=(RMTTYP *)calloc(1,sizeof(RMTTYP));
+ rmt->logptr=logptr;
+ rmt->mxs=mxs;
+ rmt->orgdomain=strdup(orgdomain);
+ rmt->dstdomain=strdup(dstdomain);
+ while (*mxs!=(MXTYP *)0) {
+ rmt->curmx=*mxs;
+ (void) rou_alert(0,"%s JMPDBG trying connect to <%s>",
+ OPEP,rmt->curmx->mxname);
+ rmt->socptr=soc_openfeedsock(pro_smtp,(char *)0,rmt->curmx->mxname,EMLPORT);
+ if (rmt->socptr!=(SOCPTR *)0) {
+ char cmt[100];
+
+ (void) snprintf(cmt,sizeof(cmt),"Now Connected to MX <%s>",
+ rmt->curmx->mxname);
+ (void) log_fprintlog(rmt->logptr,false,cmt);
+ break; //MX available found
+ }
+ mxs++;
+ }
+ if (rmt->socptr==(SOCPTR *)0) {
+ (void) rou_alert(0,"%s Found NO MX available for domain <%s>",
+ OPEP,dstdomain);
+ rmt=close_mx(rmt); //closing remote connection
+ phase=999; //No NX found!
+ }
+ break;
+ case 3 : //waiting MX signon
+ int res;
+
+ res=tcp_get_smtp_reply(rmt,WAITRMT,(char ***)0);
+ switch (res) {
+ case SIGNON : //everything fine
+ break;
+ default : //not getting the right signon
+ rmt=close_mx(rmt); //closing remote connection
+ phase=999; //No need to go further
+ break;
+ }
+ break;
+ case 4 :
+ if ((done=greetings_rmt(rmt))==false)
+ rmt=close_mx(rmt); //closing remote connection
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return rmt;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to reset the remote session */
+/* */
+/********************************************************/
+static _Bool reset_mx(RMTTYP *rmt)
+
+{
+#define OPEP "lvleml.c:reset_mx,"
+
+_Bool ok;
+int rspcode;
+char **resp;
+
+ok=false;
+resp=(char **)0;
+rspcode=tcp_smtp_command(rmt,&resp,"RSET");
+switch (rspcode) {
+ case CMDOK : //Everythin fine
+ ok=true;
+ break;
+ default :
+ (void) rou_alert(0,"%s Unexpected code='%d' (Code?)",OPEP,rspcode);
+ for (int i=0;resp[i]!=(char *)0;i++)
+ (void) rou_alert(0,"%s resp[%d]=<%s>",OPEP,i,resp[i]);
+ break;
+ }
+resp=(char **)rou_freelist((void **)resp,(genfree_t)rou_freestr);
+return ok;
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send the data to the remote server */
+/* */
+/********************************************************/
+static void senddata(RMTTYP *rmt,TRATYP **tosend)
+
+{
+#define OPEP "lvleml.c:senddata,"
+
+int rspcode;
+int sent;
+TIMESPEC start;
+char *sessid;
+char **resp;
+int phase;
+_Bool proceed;
+
+rspcode=0;
+sent=0;
+sessid=(*tosend)->sessid;
+resp=(char **)0;
+phase=0;
+proceed=true;
+(void) clock_gettime(CLOCK_REALTIME,&start);
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //Sendig data request
+ rspcode=simple_smtp_command(rmt,"DATA");
+ switch (rspcode) {
+ case DATAOK : //data accepted
+ break;
+ default : //Unexpected return code
+ phase=999; //Not accepting data
+ break;
+ }
+ break;
+ case 1 : //sending session data
+ sent=tcp_send_smtp_data(rmt,sessid);
+ if (sent<0)
+ phase=999; //No need to wait form response code
+ break;
+ case 2 : //send the text termination
+ rspcode=tcp_get_smtp_reply(rmt,WAITRMT,&resp);
+ break;
+ case 3 : //sending session data
+ const char *fmt;
+ unsigned int delta;
+
+ sent+=1023;
+ sent/=1024; //Sent now in KByes
+ fmt="Data stream Sent: %d Kbytes within %d.%03d seconds";
+ delta=rou_getdifftime(&start);
+ (void) log_fprintlog(rmt->logptr,false,fmt,sent,delta/1000,delta%1000);
+ switch (rspcode) {
+ case CMDOK :
+ const char *cmt;
+
+ cmt="Transmission completed successfully";
+ (void) log_fprintlog(rmt->logptr,false,cmt);
+ break;
+ case MALABRT : //Data rejected
+ break;
+ default : //Unexpected return code
+ break;
+ }
+ break;
+ case 4 : //Updating sending
+ TRATYP **dest;
+
+ dest=tosend;
+ while (*dest!=(TRATYP *)0) {
+ switch ((*dest)->sendcode) {
+ case CMDOK :
+ (void) eml_duptra_resp(*dest,resp);
+ if (rspcode==CMDOK) {
+ (*dest)->code='C'; //Data was sent properly
+ }
+ break;
+ case UKNUSER : //NO BREAK
+ case BADPAR :
+ break;
+ default :
+ (void) rou_alert(0,"%s sessid=<%s>, Unexpected code='%d' (Bug?)",
+ OPEP,sessid,rspcode);
+ break;
+ }
+ dest++;
+ }
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+resp=(char **)rou_freelist((void **)resp,(genfree_t)rou_freestr);
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send one email session to intended */
+/* recipient. */
+/* */
+/********************************************************/
+static void send_to_mx(RMTTYP *rmt,TRATYP **tosend)
+
+{
+#define OPEP "lvleml.c:send_to_mx,"
+
+int tobesend;
+char *sessid;
+TRATYP **dest;
+
+tobesend=0;
+sessid=(*tosend)->sessid;
+dest=tosend;
+while (*dest!=(TRATYP *)0) {
+ int rspcode;
+ char ***resp;
+
+ (void) eml_freetra_resp(*dest);
+ resp=&((*dest)->resp);
+ rspcode=tcp_smtp_command(rmt,resp,"RCPT TO: <%s>",(*dest)->rcptto);
+ switch (rspcode) {
+ case CMDOK : //originator accepted
+ tobesend++;
+ (*dest)->sendcode=rspcode;
+ break;
+ default : //Not accepted recipient
+ (void) rou_alert(0,"%s sessid=<%s>, unknwon code='%d' (Bug?)",
+ OPEP,sessid,rspcode);
+ //NO BREAK
+ case UKNUSER : //recipient is unknown
+ case NORELAY : //email no relayed
+ (*dest)->code='W'; //Need to send a Warning
+ (*dest)->sendcode=rspcode;
+ break;
+ }
+ dest++;
+ }
+if (tobesend>0)
+ (void) senddata(rmt,tosend);
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send the whole email transaction */
+/* */
+/********************************************************/
+static void sending_email(LOGPTR *logptr,TRATYP **tra)
+
+{
+#define OPEP "lvleml.c:sending_email,"
+
+time_t isnow;
+char *sessid;
+RMTTYP *rmt;
+TRATYP **tosend;
+int phase;
+_Bool proceed;
+
+isnow=time((time_t *)0);
+sessid=(char *)0;
+rmt=(RMTTYP *)0;
+tosend=(TRATYP **)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"%s JMPDBG phase='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //do we have a email request
+ if ((tra)==(TRATYP **)0) {
+ (void) rou_alert(0,"%s No email to send to remote! (Bug?)",OPEP);
+ phase=999; //all scanning done
+ }
+ break;
+ case 1 : //process completed?
+ if ((*tra)==(TRATYP *)0)
+ phase=999; //all scanning done
+ break;
+ case 2 : //do a remote reset if needed
+ if (rmt!=(RMTTYP *)0) {
+ if (reset_mx(rmt)==false) {
+ rmt=close_mx(rmt);
+ phase=999; //Trouble Trouble
+ }
+ }
+ break;
+ case 3 : //collecting email to be sent
+ sessid=(*tra)->sessid;
+ while (*tra!=(TRATYP *)0) {
+ if (strcmp((*tra)->sessid,sessid)!=0) {
+ sessid=(*tra)->sessid;
+ break;
+ }
+ if (((*tra)->date+(*tra)->delay)<=isnow) {
+ switch ((*tra)->code) {
+ case 'R' : //remote email (MX is remote)
+ (void) eml_add_delay(isnow,*tra);
+ tosend=(TRATYP **)rou_addlist((void **)tosend,(void *)(*tra));
+ break;
+ default : //Status is not to be send
+ (void) rou_alert(0,"%s Directive is not! remote email (Bug?)",OPEP);
+ break;
+ }
+ }
+ tra++;
+ }
+ break;
+ case 4 : //Checking if we have email to be sent
+ if (tosend==(TRATYP **)0)
+ phase=0; //lets continue to see other email
+ break;
+ case 5 : //is MX link already open??
+ if (rmt!=(RMTTYP *)0)
+ phase++; //No need to open MX link (again);
+ break;
+ case 6 : //Opening connection if not open
+ if ((rmt=connect_mx(logptr,*tosend))==(RMTTYP *)0) {
+ TRATYP **ptr;
+ char cmt[100];
+ char note[150];
+
+ ptr=tosend;
+ (void) snprintf(cmt,sizeof(cmt),"Unable to contact ANY MX to reach <%s>",
+ (*tosend)->rcptto);
+ (void) log_fprintlog(logptr,false,cmt);
+ (void) snprintf(note,sizeof(note),"%d %s",NOANSWR,cmt);
+ while (*ptr!=(TRATYP *)0) {
+ (void) eml_freetra_resp(*ptr);
+ (*ptr)->resp=(char **)rou_addlist((void **)(*ptr)->resp,
+ (void *)strdup(note));
+ ptr++;
+ }
+ (void) free(tosend);
+ phase=999; //No need to go further
+ }
+ break;
+ case 7 : { //sending originator
+ int rspcode;
+
+ rspcode=simple_smtp_command(rmt,"MAIL FROM: <%s>",(*tosend)->sfrom);
+ switch (rspcode) {
+ case CMDOK : //originator accepted
+ break;
+ default : //unexpected answer
+ (void) rou_alert(0,"%s JMPDBG unexpected response code='%d'",
+ OPEP,rspcode);
+ phase+=2; //not sending data
+ break;
+ }
+ break;
+ }
+ case 8 : //sending recipient list
+ (void) send_to_mx(rmt,tosend);
+ (void) free(tosend);
+ tosend=(TRATYP **)0;
+ phase=0; //Trying to send NEXT sequence of email to be sent
+ break;
+ default : //SAFE Guard
+ rmt=close_mx(rmt);
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to transmit a string to the remot peer*/
+/* */
+/********************************************************/
+PUBLIC void eml_transmit(CONTYP *contact,_Bool flush,const char *fmt,...)
+
+{
+va_list args;
+char *line;
+
+va_start(args,fmt);
+line=(char *)0;
+if (rou_vasprintf(&line,fmt,args)>0) {
+ (void) log_fprintlog(contact->logptr,true,"%s",line);
+ contact->transout=tcp_addline(contact->transout,line);
+ }
+if (flush==true) {
+ (void) tcp_write(contact->socptr,contact->transout);
+ contact->transout=rou_freestr(contact->transout);
+ }
+line=rou_freestr(line);
+va_end(args);
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* Procedure to report the contact ongoing */
+/* informationn. store this information */
+/* within the database. */
+/* */
+/************************************************/
+PUBLIC void eml_note(CONTYP *contact,char *rcpt,const char *fmt,...)
+
+{
+#define OPEP "lvleml.c:eml_status"
+
+va_list args;
+char **resp;
+char *report;
+ACTTYP action;
+
+va_start(args,fmt);
+resp=(char **)0;
+(void) rou_vasprintf(&report,fmt,args);
+resp=(char **)rou_addlist((void **)resp,(void *)report);
+(void) memset(&action,'\000',sizeof(ACTTYP));
+action.code='X';
+action.sessid=contact->session->sessid;
+action.reverse=contact->peername;
+action.remoteip=contact->peerip;
+if (contact->mailfrom!=(char *)0)
+ action.sfrom=contact->mailfrom;
+if (contact->session->hfrom!=(char *)0)
+ action.hfrom=contact->session->hfrom;
+if (contact->session->hsubject!=(char *)0)
+ action.hsubject=contact->session->hsubject;
+action.rcptto=rcpt;
+action.resp=resp;
+if (sql_mngact(contact->sqlptr,&action)==false)
+ (void) rou_alert(0,"%s, unable to store report within database (bug?",OPEP);
+resp=(char **)rou_freelist((void **)resp,(genfree_t)rou_freestr);
+va_end(args);
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to proceed with peer exchange */
+/* 5 return values: */
+/* 1 exiting via "quit" */
+/* 0 contact timeout */
+/* -1 signal received */
+/* -2 remote disconnected */
+/* -3 Multiple remote connection */
+/* -4 BUG! */
+/* */
+/********************************************************/
+PUBLIC int eml_docontact(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:eml_docontact"
+
+int status;
+int got;
+int penalty; //answer time penalty, in case of wrong auth
+_Bool proceed;
+
+status=1;
+got=0;
+penalty=1;
+proceed=true;
+(void) signon(contact);
+while (proceed==true) {
+ char *line;
+ CODTYP code;
+
+ line=(char *)0;
+ got=tcp_getline(contact->socptr,contact->delay,&line);
+ if (got<=0) { //timeout or trouble?
+ char str[100];
+
+ switch (got) {
+ case 0 : //timeout
+ (void) snprintf(str,sizeof(str),"No data from remote within %d sec",
+ contact->delay);
+ break;
+ case -1 : //signal received
+ (void) snprintf(str,sizeof(str),"Signal Received");
+ break;
+ case -2 : //contact lost
+ (void) snprintf(str,sizeof(str),"Lost link with remote");
+ break;
+ default :
+ (void) snprintf(str,sizeof(str),"Unexpected status='%d' (Bug?)",status);
+ status=-3;
+ break;
+ }
+ (void) setterminator(contact,str);
+ //(void) rou_alert(0,"%s exit status='%d'",OPEP,status);
+ break; //no need to go further
+
+ }
+ (void) log_fprintlog(contact->logptr,false,"%s",line);
+ code=eml_getcode(line);
+ switch (code) {
+ case c_data : //Peer request to transfer email corps.
+ proceed=getdata(contact);
+ break;
+ case c_helo : //HELO SMTP protocol
+ proceed=dohelo(contact,line);
+ break;
+ case c_ehlo : //EHLO SMTP protocol
+ proceed=doehlo(contact,line);
+ break;
+ case c_help : //HELP SMTP protocol
+ (void) eml_transmit(contact,true,"%d 2.0.1 see https://datatracker.ietf.org"
+ "/doc/html/rfc5321",
+ GOTHELP);
+ (void) sleep(1); //avoiding abuse
+ break;
+ case c_noop : //No Operation
+ (void) eml_transmit(contact,true,"%d 2.0.0 OK, %s",
+ CMDOK,contact->mainsesid);
+ break;
+ case c_quit : //QUIT SMTP protocol
+ contact->credit++; //clean disconnect
+ (void) setterminator(contact,"QUIT received");
+ (void) eml_transmit(contact,true,"%d 2.0.0 Bye, closing connection CNT=%s",
+ QUITOK,contact->mainsesid);
+ status=1; //every thing fine
+ proceed=false;
+ break;
+ case c_mail : //MAIL FROM: checking originator
+ proceed=checkfrom(contact,line);
+ break;
+#ifdef MODEDEBUG
+ case c_orgn : //Debug mode to override remote IP
+ proceed=set_orgn_rmtip(contact,line);
+ break;
+#endif
+ case c_auth : //Auth request
+ if (getauth(contact,line)==false)
+ proceed=false; //Authentication failed
+ break;
+ case c_rcpt : //Doing rpt scanning
+ if (checkto(contact,line)==false) {
+ (void) sleep(penalty); //relaxing bad guys
+ penalty*=2;
+ }
+ break;
+ case c_rset : //Doing session reset
+ proceed=doreset(contact,line);
+ break;
+ case c_starttls : //EHLO start encrypted link in server mode
+ (void) usleep(100000);
+ (void) soc_purge(contact->socptr,contact->peerip);
+ (void) eml_transmit(contact,true,"%d 2.0.0 Ready to start TLS",SIGNON);
+ switch (soc_starttls(contact->socptr,true)) {
+ case true : { //link now in TLS crypted mode (server mode)
+ int level;
+
+ level=soc_get_sec_level(contact->socptr);
+ (void) log_fprintlog(contact->logptr,false,cry,"server",level);
+ }
+ break;
+ case false : //unable to establish link
+ (void) setterminator(contact,"starttls not successful");
+ (void) eml_transmit(contact,true,"%d 5.3.3 command starttls not "
+ "successful",CMDBAD);
+ status=-1;
+ proceed=false;
+ break;
+ }
+ break;
+ case c_unknown : //unknown keyword
+ contact->credit-=2; //Trying to confuse server?
+ (void) rou_alert(0,"SMTP Command <%s> from [%s] is unknown (config?)",
+ line,contact->peerip);
+ (void) eml_transmit(contact,true,"%d-5.5.1 Unrecognized command, "
+ "see RFC 5321",CMDBAD);
+ (void) eml_transmit(contact,true,"%d-5.5.1 https://www.rfc-editor.org",
+ CMDBAD);
+ (void) eml_transmit(contact,true,"%d 5.5.1 session %s is still running",
+ CMDBAD,contact->mainsesid);
+ break;
+ default :
+ contact->credit-=10; //Trying to bug server
+ (void) rou_alert(0,"%s Unable to find entry for code='%d' (Bug?)",OPEP,code);
+ (void) eml_transmit(contact,true,"%d-5.5.1 Unrecognized command, "
+ "see RFC 5321",CMDBAD);
+ (void) eml_transmit(contact,true,"%d 2.0.0 Bug!, closing connection "
+ "Immediatly (%s)",
+ QUITOK,contact->mainsesid);
+ status=-1; //remote is a trouble maker
+ status=-3;
+ proceed=false;
+ break;
+ }
+ line=rou_freestr(line);
+ }
+return status;
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to wait for a remote client. */
+/* return all reference to the established contact.*/
+/* */
+/********************************************************/
+PUBLIC CONTYP *eml_getcontact(SOCPTR *socptr,int pos)
+
+{
+#define OPEP "lvleml.c:eml_getcontact"
+#define MXCARIN 200 //maximun number of char
+ //within carpile
+#define MXDELAY 300 //maximun waiting time 5 minutes standard delay
+
+CONTYP *contact;
+int phase;
+_Bool proceed;
+
+contact=(CONTYP *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ (void) rou_dbglive(9,OPEP,"phase='%d'",phase);
+ switch (phase){
+ case 0 : //check for binding
+ if (socptr==(SOCPTR *)0) {
+ (void) rou_alert(0,"%s socket pointer is NULL (Bug!?)",OPEP);
+ phase=999; //not going further
+ }
+ break;
+ case 1 : //connecting to database
+ contact=(CONTYP *)calloc(1,sizeof(CONTYP));
+ contact->sqlptr=sql_opensql();
+ contact->credit=0;
+ if (contact->sqlptr==(SQLPTR *)0) {
+ (void) rou_alert(0,"%s Unable to contact database",OPEP);
+ (void) sleep(2);//delay to avoid avalanche
+ (void) eml_dropcontact(contact);
+ contact=(CONTYP *)0;
+ phase=999; //no contact possible.
+ }
+ break;
+ case 2 : //loading the relayable IP list
+ contact->relayok=eml_load_relayed(getenv(RELAYS));
+ break;
+ case 3 : //waiting from contact
+ if ((contact->socptr=soc_accept(socptr,pos))==(SOCPTR *)0) {
+ (void) rou_alert(3,"%s Unable to open contact",OPEP);
+ contact=freecontact(contact);
+ phase=999; //no contact
+ }
+ break;
+ case 4 : //Preparing contact
+ contact->mainsesid=eml_getmainsesid();
+ contact->delay=MXDELAY;
+ contact->privilege=rel_plain; //Standard connection
+ if (debug>1)
+ contact->delay/=10; //30 sec in debug mode
+ (void) getsessid(contact);
+ contact->locname=soc_getaddrinfo(contact->socptr,true,true);
+ contact->locip=soc_getaddrinfo(contact->socptr,true,false);
+ if (contact->locip!=(char *)0) {
+ char *ptr;
+
+ //extracting service port number
+ if ((ptr=strrchr(contact->locip,'|'))!=(char *)0) {
+ *ptr='\000';
+ contact->locserv=strdup(ptr+1);
+ }
+ }
+ contact->peername=soc_getaddrinfo(contact->socptr,false,true);
+ contact->peerip=soc_getaddrinfo(contact->socptr,false,false);
+ contact->logptr=log_openlog(contact->mainsesid,(const char *)0);
+ contact->localafns=afn_getipnums(contact->locip);
+ (void) rou_alert(0,"Contact from peer <%s> to port <%s> started",
+ contact->peerip,contact->locserv);
+ break;
+ case 5 : //check contact validity
+ if ((contact->locname==(char *)0)||(contact->peerip==(char *)0)) {
+ (void) rou_alert(0,"%s Unable to establish contact entities",OPEP);
+ contact=freecontact(contact);
+ phase=999; //no identity
+ }
+ break;
+ case 6 : //checking if remote IP is relayable
+ if (afn_is_ip_relayable(contact->peerip,contact->relayok)==true) {
+ contact->privilege=rel_isrelay; //IP is relayable
+ contact->credit++;
+ }
+ break;
+ case 7 : //contact is good, then sending a signon
+ (void) prc_settitle("%s:%s, incoming contact from [%s] on [%s:%s]",
+ APPNAME,appname,contact->peerip,
+ contact->locname,contact->locserv);
+ (void) log_fprintlog(contact->logptr,true,"Start CNT=%s",contact->mainsesid);
+ (void) log_fprintlog(contact->logptr,false,"(Contact open from [%s] to "
+ "[%s:%s])",
+ contact->peerip,
+ contact->locip,
+ contact->locserv);
+ if (soc_iscrypted(contact->socptr)==true) {
+ int level;
+
+ level=soc_get_sec_level(contact->socptr);
+ (void) log_fprintlog(contact->logptr,false,cry,"server",level);
+ }
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return contact;
+#undef MXCARIN
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to wait for a remote client. */
+/* return the fee memory contact (NULL pointer) */
+/* */
+/********************************************************/
+PUBLIC CONTYP *eml_dropcontact(CONTYP *contact)
+
+{
+#define OPEP "lvleml.c:eml_dropcontact"
+
+SRVTYP *srv;
+int phase;
+_Bool proceed;
+
+srv=(SRVTYP *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase);
+ switch (phase){
+ case 0 : //check for binding
+ if (contact==(CONTYP *)0) {
+ (void) rou_alert(0,"%s Contact pointer is NULL (Bug!?)",OPEP);
+ phase=999; //not going further
+ }
+ break;
+ case 1 : //getting the remote server information
+ if (sql_mngremote(contact->sqlptr,sql_select,contact->peerip,&srv)==false) {
+ (void) rou_alert(0,"%s Unable to get remote [%s] data (Bug!?)",
+ OPEP,contact->peerip);
+ phase++; //No need to do update
+ }
+ break;
+ case 2 : //Updating remote server data
+ if (srv!=(SRVTYP *)0) { //Always
+ char *bank;
+
+ srv->credit+=contact->credit;
+ srv->update=time((time_t *)0);
+ if (sql_mngremote(contact->sqlptr,sql_update,contact->peerip,&srv)==false) {
+ (void) rou_alert(0,"%s Unable to UPDATE remote [%s] data (Bug!?)",
+ OPEP,contact->peerip);
+ }
+ bank=eml_showcredit(contact->peerip,contact->peername,
+ contact->credit,srv->credit);
+ (void) log_fprintlog(contact->logptr,true,"(%s)",bank);
+ bank=rou_freestr(bank);
+ srv=sql_freesrv(srv);
+ }
+ break;
+ case 3 : //properly closing remote contact
+ (void) rou_alert(0,"Contact from peer <%s> to port <%s> terminated",
+ contact->peerip,contact->locserv);
+ contact->socptr=soc_release(contact->socptr);
+ break;
+ case 4 : //freeing contact memory
+ contact=freecontact(contact);
+ break;
+ default : //SAFE guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+return contact;
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to generate transfile contents */
+/* return all reference to contact. */
+/* */
+/********************************************************/
+PUBLIC _Bool eml_mktransfile(CONTYP *contact,FILE *qfile)
+
+{
+#define OPEP "lvleml.c:eml_mktrans"
+
+_Bool status;
+
+status=true;
+if ((contact!=(CONTYP *)0)&&(contact->recipients!=(RCPTYP **)0)) {
+ RCPTYP **ptr;
+ TRATYP **tralist;
+ time_t isnow;
+
+ ptr=contact->recipients;
+ tralist=(TRATYP **)0;
+ isnow=time((time_t *)0);
+ while (*ptr!=(RCPTYP *)0) {
+ TRATYP *tra;
+ char data[300];
+
+ (void) snprintf(data,sizeof(data),"%s@%s",(*ptr)->userid,(*ptr)->domain);
+ tra=(TRATYP *)calloc(1,sizeof(TRATYP));
+ tra->code=(*ptr)->code;
+ tra->date=isnow;
+ tra->delay=0;
+ tra->remoteip=strdup(contact->peerip);
+ tra->reverse=strdup(contact->peername);
+ tra->sessid=strdup(contact->session->sessid);
+ tra->sfrom=strdup(contact->mailfrom);
+ tra->rcptto=strdup(data);
+ (void) strcpy(data,"email header, 'From:' missing");
+ if (contact->session->hfrom!=(char *)0)
+ (void) strncpy(data,contact->session->hfrom,sizeof(data)-1);
+ tra->hfrom=strdup(data);
+ (void) strcpy(data,"email header, 'Subject:' missing");
+ if (contact->session->hsubject!=(char *)0)
+ (void) strncpy(data,contact->session->hsubject,sizeof(data)-1);
+ tra->hsubject=strdup(data);
+ tralist=(TRATYP **)rou_addlist((void **)tralist,(void *)tra);
+ ptr++;
+ }
+ (void) eml_dump_list_tra(qfile,tralist);
+ (void) sql_update_tradb(contact->sqlptr,tralist);
+ tralist=(TRATYP **)rou_freelist((void **)tralist,(genfree_t)eml_freetra);
+ }
+return status;
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to store local email (MX local) within*/
+/* the serveur right directory. */
+/* */
+/********************************************************/
+PUBLIC void eml_local_email(TRATYP **tra)
+
+{
+#define OPEP "lvleml.c:eml_local_email,"
+
+time_t isnow;
+
+isnow=time((time_t *)0);
+while (*tra!=(TRATYP *)0) {
+ if (((*tra)->date+(*tra)->delay)>isnow)
+ continue;
+ (void) eml_add_delay(isnow,*tra);
+ switch ((*tra)->code) {
+ case 'L' : //local email (MX is local)
+ (*tra)->code='C';
+ if (eml_store_email(*tra)==false) {
+ (*tra)->code='L'; //Will try to deliver later one
+ (void) rou_alert(0,"%s Unable to deliver local email <%s> to <%s>",
+ OPEP,(*tra)->sessid,(*tra)->rcptto);
+ }
+ break;
+ default : //Unexpected local? email??
+ (void) rou_alert(0,"%s Directive is not! local email (Bug?)",OPEP);
+ (void) rou_alert(0,"%s TRA=<%cs %lu %04u %s %s %s",OPEP,
+ (*tra)->code,
+ (*tra)->date,
+ (*tra)->delay,
+ (*tra)->sessid,
+ (*tra)->sfrom,
+ (*tra)->rcptto);
+ break;
+ }
+ tra++;
+ }
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to send email to remote recipient */
+/* */
+/********************************************************/
+PUBLIC void eml_remote_email(TRATYP **tra)
+
+{
+#define OPEP "lvleml.c:eml_remote_email,"
+
+char *mainsesid;
+LOGPTR *logptr;
+long debut;
+long fin;
+int phase;
+_Bool proceed;
+
+mainsesid=(char *)0;
+logptr=(LOGPTR *)0;
+debug=0;
+fin=0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ switch (phase) {
+ case 0 : //Check if we have tra
+ if (tra==(TRATYP **)0) {
+ (void) rou_alert(0,"%s Transaction pointer is NULL (Bug?)",OPEP);
+ phase=999;
+ }
+ break;
+ case 1 : //checking if we have a session ID
+ if ((*tra)->sessid==(char *)0) {
+ (void) rou_alert(0,"%s Session ID is NULL (Bug?)",OPEP);
+ phase=999;
+ }
+ break;
+ case 2 : //extracting the main session number
+ char *ptr;
+ char cmt[100];
+
+ mainsesid=strdup((*tra)->sessid);
+ ptr=strrchr(mainsesid,'-');
+ if (ptr!=(char *)0)
+ *ptr='\000';
+ (void) snprintf(cmt,sizeof(cmt),"main-session-id=%s",mainsesid);
+ logptr=log_openlog(mainsesid,cmt);
+ mainsesid=rou_freestr(mainsesid);
+ break;
+ case 3 : //sending all email within transaction
+ (void) sending_email(logptr,tra);
+ break;
+ case 4 : //closing log linked to session
+ logptr=log_closelog(logptr,&debut,&fin);
+ break;
+ default : //SAFE Guard
+ proceed=false;
+ break;
+ }
+ phase++;
+ }
+
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to rebounce an email which was NOT */
+/* deliverable. */
+/* */
+/********************************************************/
+PUBLIC void eml_rebounce_email(TRATYP *tra)
+
+{
+char *tmp;
+
+(void) rou_alert(0,"JMPDG rebounce");
+tmp=tra->sfrom;
+tra->sfrom=tra->rcptto;
+tra->sfrom=tmp;
+tra->code='L';
+}
+
--- /dev/null
+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-redhat-linux/11/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/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-redhat-linux/11/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-redhat-linux/11/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/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/configuration-x86_64.h \
+ /usr/include/openssl/opensslv.h /usr/include/openssl/e_os2.h \
+ /usr/include/inttypes.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.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-redhat-linux/11/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/include/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Define all routine to manage SMTP high level */
+/* exchange. */
+/* */
+/********************************************************/
+#ifndef LVLEML
+#define LVLEML
+
+#include <stdio.h>
+
+#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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Module to handle all email incoming */
+/* */
+/********************************************************/
+#include <errno.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#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
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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<argc;i++) {
+ int iteration;
+ PROTYP proto;
+ char *ipnum;
+ char *port;
+ char *ptr;
+ char config[80];
+
+ (void) memset(config,'\000',sizeof(config));
+ (void) strncpy(config,argv[i],sizeof(config)-2);
+ ptr=config;
+ iteration=1;
+ proto=pro_smtp;
+ ipnum=DIP;
+ port=DPORT;
+ for (int j=0;j<3;j++) {
+ char *sofar;
+
+ if ((sofar=strchr(ptr,'|'))==(char *)0)
+ break;
+ *sofar='\000';
+ sofar++;
+ switch (j) {
+ case 0 :
+ if ((proto=soc_getprotocol(ptr))==pro_unknwn) {
+ (void) rou_alert(0,"%s, protocol unknown within config <%s>",
+ 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;i<iterations;i++) {
+ (void) prc_nozombie();
+ if (prc_checkprocess(childs[i])==true)
+ continue;
+ childs[i]=fork();
+ switch (childs[i]) {
+ case -1 : //trouble trouble to fork?
+ childs[i]=(pid_t)0;
+ (void) sleep(1); //Weathering the storme
+ break;
+ case 0 : //Child process itself
+ (void) free(childs);
+ (void) docontact(socptr,i+1);
+ (void) exit(0);
+ break;
+ default : //Main process relax
+ (void) usleep(10000);
+ break;
+ }
+ }
+ break;
+ case 3 : //Relax time
+ if (foreground==true)
+ phase=999; //foreground ->one 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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<nbrbind;i++) {
+ (void) prc_nozombie();
+ if (childs[i]==(pid_t)0) {
+ allbusy=false;
+ continue;
+ }
+ if (prc_checkprocess(childs[i])==false) {
+ childs[i]=(pid_t)0;
+ allbusy=false;
+ }
+ }
+ if (allbusy==true) { //all serveur up and running?
+ (void) sleep(RELAX); //yes! then relax
+ phase=0; //Lets check again
+ }
+ break;
+ case 3 : //starting one process only
+ if (foreground==true) {
+ (void) startwaiter(bindings[0]);
+ phase++; //no multiple fork
+ }
+ break;
+ case 4 : //starting/restarting all waiting process
+ for (int i=0;i<nbrbind;i++) {
+ if (childs[i]!=(pid_t)0)
+ continue;
+ childs[i]=fork();
+ switch (childs[i]) {
+ case -1 : //trouble trouble to fork?
+ (void) rou_alert(0,"%s Unable to fork smtp handler (error=<%s>)",
+ 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
+}
--- /dev/null
+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-redhat-linux/11/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/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/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-redhat-linux/11/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/configuration-x86_64.h \
+ /usr/include/openssl/opensslv.h /usr/include/openssl/e_os2.h \
+ /usr/include/inttypes.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.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-redhat-linux/11/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/include/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/************************************************/
+/* */
+/* Module to handle all incoming email */
+/* */
+/************************************************/
+#ifndef MODREC
+#define MODREC
+
+#include <stdbool.h>
+
+//procedure to receive email from outside
+extern void rec_handlesmtp(int argc,char *argv[]);
+
+#endif
--- /dev/null
+#define VERSION "0.19"
+#define RELEASE "1"
+#define BRANCH "dvl"
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Sub kevel procedure to manage IP number. */
+/* */
+/********************************************************/
+#include <ifaddrs.h>
+#include <malloc.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "subafn.h"
+
+#define AFT sizeof(struct in6_addr)
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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 (num<AFT)
+ (void) memset(afnnum->ip+num,'\000',AFT-num);
+ }
+return afnnum;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
--- /dev/null
+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-redhat-linux/11/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/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-redhat-linux/11/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/stdio_lim.h /usr/include/bits/floatn.h \
+ /usr/include/bits/floatn-common.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/************************************************/
+/* */
+/* Define all routine to manage all */
+/* procedure to manage IP number conversion*/
+/* */
+/************************************************/
+#ifndef SUBAFN
+#define SUBAFN
+
+#include <netdb.h>
+
+//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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Define all routine to manage language string */
+/* conversion. */
+/* */
+/********************************************************/
+#include <ctype.h>
+#include <stdbool.h>
+#include <string.h>
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
+#include <openssl/evp.h>
+
+#include "subcnv.h"
+
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;i<taille;i++) {
+ char convert[5];
+
+ (void) snprintf(convert,sizeof(convert),"%02hhx",str[i]);
+ (void) strcat(hexa,convert);
+ }
+ }
+return hexa;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* Procedure to generate a random string with a */
+/* specific lenght. */
+/* */
+/********************************************************/
+PUBLIC char *cnv_getrndstr(size_t length)
+
+{
+char charset[] = "0123456789"
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+char *rndstr;
+
+rndstr=(char *)0;
+if (length>0) {
+ rndstr=(char *)calloc(length+1,sizeof(char));
+ for (size_t t=0;t<length;t++) {
+ size_t index;
+
+ index=rand()%sizeof(charset);
+ rndstr[t]=charset[index];
+ }
+ }
+return rndstr;
+}
--- /dev/null
+subcnv.o subcnv.d : subcnv.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/lib/gcc/x86_64-redhat-linux/11/include/stdbool.h \
+ /usr/include/string.h /usr/include/bits/libc-header-start.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/stddef.h \
+ /usr/include/strings.h /usr/include/openssl/bio.h \
+ /usr/include/openssl/macros.h /usr/include/openssl/opensslconf.h \
+ /usr/include/openssl/configuration.h \
+ /usr/include/openssl/configuration-x86_64.h \
+ /usr/include/openssl/opensslv.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/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/struct_mutex.h \
+ /usr/include/bits/struct_rwlock.h /usr/include/inttypes.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.h \
+ /usr/include/bits/stdint-uintn.h /usr/include/stdio.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/stdio_lim.h /usr/include/bits/floatn.h \
+ /usr/include/bits/floatn-common.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/openssl/safestack.h /usr/include/openssl/stack.h \
+ /usr/include/openssl/types.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/include/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/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 subcnv.h
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/************************************************/
+/* */
+/* Define all routine to manage language */
+/* string conversion. */
+/* */
+/************************************************/
+#ifndef SUBCNV
+#define SUBCNV
+
+//base64 char 0 coding
+#define IOBNULL "\\0"
+
+//Procedure to convert a plain ASCII B64 sequence
+//to a plain ASCII sequence
+extern char *cnv_getb64(char *b64);
+
+//Procedure to convert a plain ASCII sequence
+//to an ASCII B64 sequence
+extern char *cnv_setb64(const char *str);
+
+//Procedure to convert a string of character as an HEXA string
+extern char *cnv_tohexa(const char *str,int taille);
+
+//procedure to generate a random string
+extern char *cnv_getrndstr(size_t length);
+
+#endif
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Module for low level subroutine */
+/* */
+/********************************************************/
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <dirent.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#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;
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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));
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* Procedure to transform the local system time in */
+/* ASCII time stamp. */
+/* Stored in STATIC memory area. */
+/* */
+/********************************************************/
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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);
+ }
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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);
+ }
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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);
+ }
+ }
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
--- /dev/null
+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-redhat-linux/11/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-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/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-redhat-linux/11/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/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-redhat-linux/11/include/stdbool.h numver.h
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/************************************************/
+/* */
+/* Low level subroutine declaration */
+/* */
+/************************************************/
+#ifndef SUBROU
+#define SUBROU
+
+#include <linux/types.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <time.h>
+
+
+#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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Implement all procedure to use digest-md5 */
+/* authentication exchange. */
+/* */
+/********************************************************/
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "subrou.h"
+#include "subcnv.h"
+#include "unidig.h"
+
+#define ALGO "md5-sess"
+#define MAXBUF 2000
+#define CHARSET "utf-8"
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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';
+ }
+ }
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+ }
+ }
+ }
+ }
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;i<sizeof(MD5TYP);i++) {
+ (void) memcpy(tmp,hexa+(i*2),2);
+ if (sscanf(tmp,"%hhx",&(travail[i]))!=1) {
+ ok=false; //Wrong hexa decimal number
+ break;
+ }
+ }
+ if (ok==true) {
+ plain=calloc(sizeof(MD5TYP),sizeof(char));
+ (void) memmove(plain,travail,sizeof(MD5TYP));
+ }
+ }
+return plain;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* Procedure to generate a unique DIGEST-M5 */
+/* challenge as an B64 string. */
+/* */
+/********************************************************/
+PUBLIC char *dig_getchallenge()
+
+{
+#define OPEP "unidig.c:dig_getchallenge,"
+
+static char *comp[]={
+ "realm=\"%s\"", //the LOCAL realm
+ ",nonce=\"%s\"",
+ ",qop=%s",
+ ",algorithm=%s",
+ ",charset=%s",
+ (char*)0
+ };
+
+char *challenge;
+
+challenge=(char *)calloc(MAXBUF,sizeof(char));
+for (int num=0;comp[num]!=(char *)0;num++) {
+ char loc[MAXBUF/2];
+
+ (void) memset(loc,'\000',sizeof(loc));
+ switch (num) {
+ case 0 : //realm
+ (void) snprintf(loc,sizeof(loc),comp[num],rou_getrealm());
+ break;
+ case 1 : { //nonce
+ char *nonce;
+ char *b64;
+
+ nonce=cnv_getrndstr(30);
+ b64=cnv_setb64(nonce);
+ (void) snprintf(loc,sizeof(loc),comp[num],b64);
+ b64=rou_freestr(b64);
+ nonce=rou_freestr(nonce);
+ }
+ break;
+ case 2 : //qop
+ (void) snprintf(loc,sizeof(loc),comp[num],"auth");
+ break;
+ case 3 : //algorithm
+ (void) snprintf(loc,sizeof(loc),comp[num],ALGO);
+ break;
+ case 4 : //charset
+ (void) snprintf(loc,sizeof(loc),comp[num],CHARSET);
+ break;
+ default : //none expect field BUG!
+ (void) rou_alert(0,"%s field[%d]=%s not treated (BUG!)",OPEP,num,comp[num]);
+ challenge=rou_freestr(challenge);
+ break;
+ }
+ if (strlen(loc)>0)
+ (void) strcat(challenge,loc);
+ }
+return challenge;
+
+#undef OPEP
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
--- /dev/null
+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/configuration-x86_64.h \
+ /usr/include/openssl/opensslv.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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-redhat-linux/11/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/stdio_lim.h /usr/include/bits/floatn.h \
+ /usr/include/bits/floatn-common.h /usr/include/openssl/types.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/struct_mutex.h \
+ /usr/include/bits/struct_rwlock.h /usr/include/inttypes.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.h \
+ /usr/include/bits/stdint-uintn.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/include/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-redhat-linux/11/include/stdbool.h subcnv.h unidig.h
--- /dev/null
+// 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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Implement all routine to manage SMTP low level */
+/* exchange. */
+/* */
+/********************************************************/
+#include <arpa/inet.h>
+#include <errno.h>
+#include <malloc.h>
+#include <resolv.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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;
+
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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)&&(cp<eom)) {
+ if ((rc=dn_expand(msg,eom,cp,(char *)buf,sizeof(buf)-1))<0)
+ break;
+ cp +=rc+QFIXEDSZ;
+ }
+while((answer-->0)&&(cp<eom)) {
+ if ((rc=dn_expand(msg,eom,cp,(char *)buf,sizeof(buf)-1))<0) {
+ break;
+ }
+ if (rc>0) {
+ 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 (collected<dlen) {
+ u_int taille;
+
+ (void) memset(buf,'\000',sizeof(buf));
+ taille=((u_int)(txtptr[0]))&0X0FF;
+ txtptr++;
+ (void) snprintf(buf,sizeof(buf),"%.*s",taille,txtptr);
+ dynbuf=(char *)realloc(dynbuf,strlen(dynbuf)+strlen(buf)+5);
+ (void) strcat(dynbuf,buf);
+ collected+=taille+1;
+ txtptr+=taille;
+ }
+ list=(char **)rou_addlist((void **)list,(void *)dynbuf);
+ break;
+ case T_A : {
+ char str[INET_ADDRSTRLEN];
+
+ (void) inet_ntop(AF_INET,cp,str,INET_ADDRSTRLEN);
+ list=(char **)rou_addlist((void **)list,(void *)strdup(str));
+ }
+ break;
+ case T_AAAA :
+ (void) rou_alert(0,"%s Unexpected T_AAAA field",OPEP);
+ break;
+ case T_PTR :
+ if ((rc=dn_expand(msg,eom,cp,(char *)buf,sizeof(buf)-1))>0) {
+ 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
--- /dev/null
+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-redhat-linux/11/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/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-redhat-linux/11/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/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-redhat-linux/11/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.h \
+ /usr/include/arpa/nameser_compat.h /usr/include/bits/types/res_state.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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
--- /dev/null
+// 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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Implement all routine to manage SMTP low level */
+/* exchange. */
+/* */
+/********************************************************/
+#include <arpa/inet.h>
+#include <sys/file.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+
+#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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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);
+ }
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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)<sizeof(fullname))) {
+ (void) strcat(fullname,".");
+ (void) strcat(fullname,ext);
+ }
+if ((qfile=fopen(fullname,"r+"))==(FILE *)0) {
+ (void) rou_alert(0,"%s Unable to open file <%s> (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;
+}
--- /dev/null
+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-redhat-linux/11/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/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-redhat-linux/11/include/stdbool.h \
+ /usr/include/stdio.h /usr/include/bits/libc-header-start.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Define all routine to manage SMTP low level */
+/* exchange. */
+/* */
+/********************************************************/
+#ifndef UNIEML
+#define UNIEML
+
+#include <stdio.h>
+
+#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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Low level subroutine implementation */
+/* to handle POSTGRES SQL request */
+/* */
+/********************************************************/
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <mysql/mysql.h>
+#include <sys/types.h>
+
+#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
+
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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<numfields;i++) {
+ if (strcmp(fields[i].name,fieldname)==0) {
+ position=i;
+ break;
+ }
+ }
+ if (position<0)
+ (void) rou_alert(0,"%s field '%s' unknown (Bug?)",OPEP,fieldname);
+ else {
+ register MYSQL_ROW row;
+
+ (void) mysql_data_seek((MYSQL_RES *)rs,tuple);
+ if ((row=mysql_fetch_row((MYSQL_RES *)rs))!=(MYSQL_ROW)0)
+ got=row[position];
+ }
+ }
+#endif
+return got;
+#undef OPEP
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* Procedure to extract data from the database. */
+/* Return POSRES status pointer (can be NULL is not*/
+/* successfull. */
+/* */
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* procedure to retrieve specific field in specific*/
+/* row, accessed with the column number. */
+/* */
+/********************************************************/
+PUBLIC char *mar_getfield(MARRES *rs,int tuple,int position)
+
+{
+register char *got;
+
+got=(char *)0;
+#ifdef DB_MYSQL
+ {
+ MYSQL_ROW row;
+
+ (void) mysql_data_seek((MYSQL_RES *)rs,tuple);
+ if ((row=mysql_fetch_row((MYSQL_RES *)rs))!=(MYSQL_ROW)0) {
+ got=row[position];
+ }
+ }
+#endif
+return got;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* Procedure to extract data from the database. */
+/* Return POSRES status pointer (can be NULL is not*/
+/* successfull. */
+/* */
+/********************************************************/
+PUBLIC MARRES *mar_gettupple(MARPTR *marptr,char *command)
+
+{
+#define OPEP "unimar.c:mar_gettupple"
+
+register MARRES *marres;
+
+marres=(MARRES *)0;
+#ifdef DB_MYSQL
+ {
+ MYSQL_RES *mysstatut;
+ register MYSQL *ms;
+
+ mysstatut=(MYSQL_RES *)0;
+ ms=(MYSQL *)marptr;
+ if (mysql_query(ms,command)==0) {
+ if ((mysstatut=mysql_store_result(ms))==(MYSQL_RES *)0)
+ (void) rou_alert(3,"%s result empty for cmd=<%s>",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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
--- /dev/null
+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-redhat-linux/11/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-redhat-linux/11/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/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/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/mysql/mariadb_com.h \
+ /usr/include/mysql/mariadb_version.h \
+ /usr/include/mysql/mariadb_version-x86_64.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-redhat-linux/11/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
--- /dev/null
+// 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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Low level subroutine declaration */
+/* to handle an argv list and extract */
+/* parameters. */
+/* */
+/********************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;i<params->argc;i++) {
+ params->argv[i]=strdup(argv[optind+i]);
+ }
+ }
+return params;
+}
--- /dev/null
+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-redhat-linux/11/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/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/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-redhat-linux/11/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Low level subroutine declaration */
+/* to handle an argv list and extract */
+/* parameters. */
+/* */
+/********************************************************/
+#ifndef UNIPAR
+#define UNIPAR
+
+#include <stdbool.h>
+
+//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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Low level subroutine implementation */
+/* to handle POSTGRES SQL request */
+/* */
+/********************************************************/
+#include <libpq-fe.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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
+
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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<max;i++,p++,dstr++) {
+ switch (*dstr) {
+ case '\\' :
+ case '\'' :
+ taille++;
+ if ((newclean=(char *)realloc(cleanstr,taille))!=(char *)0) {
+ cleanstr=newclean;
+ cleanstr=(char *)realloc(cleanstr,taille);
+ cleanstr[p]=*dstr;
+ }
+ p++;
+ break;
+ default :
+ break;
+ }
+ cleanstr[p]=*dstr;
+ }
+ cleanstr[p]='\000';
+ }
+ }
+(void) strcat(cleanstr,"'");
+return cleanstr;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* Procedure to return a dynamicaly allocated */
+/* char * with an POSTGRESQL date computation */
+/* sequence */
+/* */
+/********************************************************/
+PUBLIC char *pos_caldate(char *expression,int second)
+
+{
+char *seq;
+
+seq=(char *)0;
+(void) rou_asprintf(&seq,"(%s + interval '%d sec')",expression,second);
+return seq;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* Procedure to establish a link with the */
+/* postgresq SQL server. */
+/* */
+/********************************************************/
+POSPTR *pos_opensql(const char *host,const char *sqlport,const char *dbname)
+
+{
+#define OPEP "unipos.c:pos_opensql,"
+POSPTR *posptr;
+
+posptr=(POSPTR *)0;
+#ifdef DB_POSTGRESQL
+ {
+ char *z; //parameter null
+ PGconn *pf;
+
+ z=(char *)0;
+ pf=PQsetdbLogin(host,sqlport,z,z,dbname,z,z);
+ // Check if the connection is successful
+ if (PQstatus(pf)!=CONNECTION_OK) {
+ (void) fprintf(stderr,"%s Connection to database '%s' failed, cause '%s'\n",
+ OPEP,dbname,PQerrorMessage(pf));
+ (void) PQfinish(pf);
+ pf=(PGconn *)0;
+ }
+ posptr=(POSPTR *)pf;
+ }
+#else
+ (void) fprintf(stderr,"%s not compiled to be used with postgresql\n",OPEP);
+#endif
+return (POSPTR *)posptr;
+#undef OPEP
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* Procedure to close the link with the designated */
+/* postgresql SQL server. */
+/* */
+/********************************************************/
+POSPTR *pos_closesql(POSPTR *posptr)
+
+{
+#define OPEP "unipos.c:pos_closesql,"
+
+#ifdef DB_POSTGRESQL
+ {
+ PGconn *pf;
+
+ pf=(PGconn *)posptr;
+ if (pf==(PGconn *)0) {
+ (void) fprintf(stderr,"%s Database link already closedi (Bug?)\n",OPEP);
+ (void) PQfinish(pf);
+ }
+ else {
+ (void) PQfinish((PGconn *)pf);
+ pf=(PGconn *)0;
+ }
+ posptr=(POSPTR *)pf;
+ }
+#else
+ (void) fprintf(stderr,"%s not compiled to be used with postgresql\n",OPEP);
+#endif
+return posptr;
+
+#undef OPEP
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* Procedure to return a unix time in acsii */
+/* format (data-base compatible). */
+/* */
+/********************************************************/
+PUBLIC const char *pos_fromunixtime(time_t timestamp)
+
+{
+#define TSTAMP "%Y-%m-%d %H:%M:%S"
+
+static char unixdate[50];
+
+(void) memset(unixdate,'\000',sizeof(unixdate));
+
+#ifdef DB_POSTGRESQL
+ {
+ struct tm *tminfo;
+
+ tminfo=localtime(×tamp);
+ (void) strftime(unixdate,sizeof(unixdate),TSTAMP,tminfo);
+ }
+#endif
+
+return unixdate;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* Procedure to return a unix time_t from an ASCII*/
+/* string (data-base compatible). */
+/* */
+/********************************************************/
+PUBLIC time_t pos_tounixtime(const char *date)
+
+{
+#define OPEP "unipos.c:pos_tounixtime,"
+
+time_t datetime;
+
+datetime=(time_t)0;
+#ifdef DB_POSTGRESQL
+ {
+ if (date!=(char *)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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* procedure to drop/free all result information */
+/* */
+/********************************************************/
+PUBLIC POSRES *pos_dropresult(POSRES *rs)
+
+{
+#ifdef DB_POSTGRESQL
+(void) PQclear(rs);
+#endif
+return (POSRES *)0;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
--- /dev/null
+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-redhat-linux/11/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/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/pg_config_ext-x86_64.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/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-redhat-linux/11/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
--- /dev/null
+// 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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Process management implementation module. */
+/* */
+/********************************************************/
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#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
+
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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<num;i++) {
+ (void) prc_nozombie();
+ if (childs[i]==(pid_t)0)
+ continue;
+ if (prc_checkprocess(childs[i])==false) {
+ childs[i]=(pid_t)0;
+ continue;
+ }
+ remain++;
+ (void) kill(childs[i],SIGTERM);
+ }
+ if (remain==0)
+ break;
+ (void) sleep(1);
+ maxretry--;
+ }
+return remain;
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to set/unset a lock */
+/* return true if successful, */
+/* false otherwise. */
+/* */
+/********************************************************/
+PUBLIC _Bool prc_locking(const char *lockname,int lock,int tentative)
+
+{
+#define OPEP "uniprc.c:lck_locking,"
+
+_Bool done;
+char *fullname;
+struct stat bufstat;
+int phase;
+_Bool proceed;
+
+done=false;
+fullname=(char *)0;
+phase=0;
+proceed=true;
+while (proceed==true) {
+ //(void) rou_alert(0,"%s pahse='%d'",OPEP,phase);
+ switch (phase) {
+ case 0 : //setting lock filename
+ if (lockname==(const char *)0) {
+ (void) rou_alert(9,"%s lockname is missing (bug?)",OPEP);
+ phase=999; //big trouble, No need to go further
+ }
+ break;
+ case 1 : //creating the lock directory if needed
+ DIR *dir;
+
+ fullname=rou_apppath(DIRLOCK);
+ if ((dir=opendir(fullname))==(DIR *)0) {
+ if (rou_do_mkpdir(fullname)==false) {
+ (void) rou_alert(9,"Unable to create <%s> 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+ }
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* */
+/* 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;i<argc;i++) {
+ lastend=argv[i]+strlen(argv[i]);
+ argv[i]=(char *)0;
+ }
+ }
+if (env!=(char **)0) {
+ int i;
+
+ environ=(char **)0;
+ for (i=0;env[i]!=(char *)0;i++) {
+ char *valeur;
+
+ lastend=env[i]+strlen(env[i]);
+ valeur=strdup(env[i]);
+ (void) putenv(valeur);
+ }
+ }
+title->max=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);
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
--- /dev/null
+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-redhat-linux/11/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/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/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-redhat-linux/11/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/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-redhat-linux/11/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/************************************************/
+/* */
+/* Unit level process management */
+/* declaration */
+/* */
+/************************************************/
+#ifndef UNIPRC
+#define UNIPRC
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Module for signal handling level */
+/* */
+/********************************************************/
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/signalfd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#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
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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<NUMINTR;i++) {
+ if (olds[i]==(struct sigaction *)0)
+ olds[i]=calloc(1,sizeof(struct sigaction));
+ }
+ (void) sigaction(SIGUSR2,newsa,olds[0]);
+ (void) sigaction(SIGUSR1,newsa,olds[1]);
+ (void) sigaction(SIGINT,newsa,olds[2]);
+ (void) sigaction(SIGTERM,newsa,olds[3]);
+ (void) sigaction(SIGQUIT,newsa,olds[4]);
+ (void) sigaction(SIGHUP,newsa,olds[5]);
+ (void) sigaction(SIGALRM,newsa,olds[6]);
+ (void) sigaction(SIGCHLD,newsa,olds[7]);
+ (void) sigaction(SIGPIPE,newsa,olds[8]);
+ (void) free(newsa);
+ if ((sfd=signalfd(-1, &mask, 0))<0) {
+ (void) rou_alert(0,"%s Unable to set signalfd (error=<%s>)",
+ 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<NUMINTR;i++) {
+ if (olds[i]!=(struct sigaction *)0)
+ (void) free(olds[i]);
+ olds[i]=(struct sigaction *)0;
+ }
+ }
+alldone=onoff;
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to "open/close" module and do */
+/* homework purpose */
+/* return zero if everything right */
+/* */
+/********************************************************/
+PUBLIC int sig_modeunisig(_Bool mode)
+
+{
+#define OPEP "unisig.c:sig_modeunisig"
+
+int status;
+
+status=0;
+if (mode!=modopen) {
+ switch ((int)mode) {
+ case true :
+ (void) rou_modesubrou(mode);
+ (void) trapsigsegv(mode,gotsigsegv);
+ break;
+ case false :
+ (void) trapsigsegv(mode,gotsigsegv);
+ (void) rou_modesubrou(mode);
+ break;
+ default :
+ (void) fprintf(stderr,"Calling %s with wrong mode='%d' (Bug?!):",
+ OPEP,(int)mode);
+ status=-1;
+ break;
+ }
+ modopen=mode;
+ }
+return status;
+#undef OPEP
+}
--- /dev/null
+unisig.o unisig.d : unisig.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/sys/wait.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-redhat-linux/11/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/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/sys/signalfd.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h /usr/include/bits/signalfd.h \
+ /usr/include/stdlib.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/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-redhat-linux/11/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/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 unisig.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/************************************************/
+/* */
+/* Unit level signal management */
+/* declaration */
+/* */
+/************************************************/
+#ifndef UNISIG
+#define UNISIG
+
+#include <stdbool.h>
+#include <signal.h>
+
+#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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Module for low level SQL subroutine */
+/* */
+/********************************************************/
+#include <ctype.h>
+#include <errno.h>
+#include <iconv.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "subrou.h"
+#include "unisql.h"
+
+#define DLANG "UTF-8"
+
+/*
+\f
+*/
+/************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/************************************************/
+/* */
+/* 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<l;i++) {
+ register char car;
+
+ car=key[i];
+ switch (car) {
+ case '@' :
+ case '.' :
+ continue;
+ break;
+ default :
+ if (isalnum((int)car)!=0)
+ continue;
+ break;
+ }
+ isok=false;
+ (void) rou_alert(0,"%s search key <%s> not accepted, '%c' is not "
+ "an acceptable char",OPEP,key,car);
+ break; //no need to check further
+ }
+ }
+return isok;
+
+#undef OPEP
+}
--- /dev/null
+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-redhat-linux/11/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/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-redhat-linux/11/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/************************************************/
+/* */
+/* Low level SQL subroutine declaration */
+/* */
+/************************************************/
+#ifndef UNISQL
+#define UNISQL
+
+#include <sys/types.h>
+
+#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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Implement all routine to manage SMTP low level */
+/* exchange. */
+/* */
+/********************************************************/
+#include <openssl/asn1.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <sys/socket.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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 (sent<tosend)
+ proceed=true;
+ break;
+ }
+ }
+ }
+return sent;
+#undef OPEP
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
+/* Procedure to read up to maxread character from */
+/* an tls channel and store into a buffer. */
+/* return the number of char read, or -1 if */
+/* trouble. */
+/* */
+/********************************************************/
+PUBLIC int tls_read(TLSTYP *tls,char *buffer,int maxread)
+
+{
+#define OPEP "unitls.c:tls_read"
+
+int got;
+
+got=-1;
+if (tls!=(TLSTYP *)0) {
+ int status;
+
+ status=0;
+ got=SSL_read(tls->ssl,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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
--- /dev/null
+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/configuration-x86_64.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-redhat-linux/11/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/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/struct_mutex.h \
+ /usr/include/bits/struct_rwlock.h /usr/include/inttypes.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/wchar.h \
+ /usr/include/bits/stdint-uintn.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-redhat-linux/11/include/limits.h \
+ /usr/lib/gcc/x86_64-redhat-linux/11/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/include/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-redhat-linux/11/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
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Define all routine to manage transport secure */
+/* layer. */
+/* */
+/********************************************************/
+#ifndef UNIUTL
+#define UNIUTL
+
+#include <stdbool.h>
+#include <openssl/ssl.h>
+
+#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
--- /dev/null
+#! /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
+
+
+
--- /dev/null
+#!/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
+
+
+
--- /dev/null
+#!/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
+
+
+
--- /dev/null
+#!/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
+
+
+
--- /dev/null
+#!/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
+
+
+
--- /dev/null
+#-----------------------------------------------------------------------------
+%{?!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(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
--- /dev/null
+#! /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
--- /dev/null
+#! /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";
--- /dev/null
+#--------------------------------------------------------------------
+#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
+#--------------------------------------------------------------------
--- /dev/null
+
+//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
--- /dev/null
+
+#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');
+//==============================================================
--- /dev/null
+/********************************************************/
+/* */
+/* 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
--- /dev/null
+
+/********************************************************/
+/* */
+/* 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 */
+/* */
+/********************************************************/
+
--- /dev/null
+#! /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
+
+
--- /dev/null
+#! /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
--- /dev/null
+#! /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
+
--- /dev/null
+#! /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 <<!EOT
+#$APPNAME START
+#Done by the $APPNAME first start (do_httpd.sh)
+
+<VirtualHost *:80>
+ 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
+</VirtualHost>
+
+#-----------------------------------------------------------------
+#Listening on TLS port
+Listen 443
+
+SSLSessionCache "shmcb:logs/ssl_scache(512000)"
+SSLSessionCacheTimeout 300
+
+#-----------------------------------------------------------------
+<VirtualHost *:443>
+ ServerName `hostname`
+ ServerAlias $APPNAME.$domain
+ ServerAlias localhost.localdomain
+ ServerAdmin root@$domain
+ DocumentRoot /var/www/$APPNAME
+ Alias reg-icons /var/www/$APPNAME/reg-icons
+ <Directory /var/www/$APPNAME>
+ Options MultiViews FollowSymlinks ExecCGI
+ AllowOverride AuthConfig FileInfo Indexes Limit Options
+ Require all granted
+ </Directory>
+ #----------------------------------------------
+ #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
+</VirtualHost>
+
+#$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
+
--- /dev/null
+#! /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
--- /dev/null
+#! /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
--- /dev/null
+#! /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
--- /dev/null
+#! /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;
+#---------------------------------------------------------------
--- /dev/null
+#-------------------------------------------
+#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"
+#-------------------------------------------
+
--- /dev/null
+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
--- /dev/null
+#-----------------------------------------
+#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
+
--- /dev/null
+#----------------------------
+#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 ->
--- /dev/null
+#--------------------------------------------------------------------
+#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
+#--------------------------------------------------------------------
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Validation program to check */
+/* MD5TYP/hexadecimal sequence */
+/* */
+/* Usage: */
+/* chkhexa an MD5 heaxdecimal number. */
+/* */
+/********************************************************/
+#include <errno.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "subcnv.h"
+#include "unidig.h"
+
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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<argc;i++) {
+ _Bool ok;
+ MD5TYP *cnv;
+
+ ok=false;
+ if ((cnv=dig_get_plain_md5(argv[i]))!=(MD5TYP *)0) {
+ char *isgood;
+
+ isgood=cnv_tohexa((char *)cnv,sizeof(MD5TYP));
+ if (isgood!=(char *)0) {
+ if (strcmp(argv[i],isgood)==0)
+ ok=true;
+ (void) free(isgood);
+ }
+ (void) free(cnv);
+ }
+ if (ok==true)
+ (void) fprintf(stdout,"GOOD MD5 HASH");
+ else
+ (void) fprintf(stdout,"WRONG MD5 HASH");
+ (void) fprintf(stdout," <%s>\n",argv[i]);
+ }
+return status;
+}
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+/********************************************************/
+/* */
+/* Validation program to check DIGEST-MD5 Exchange */
+/* */
+/* Usage: */
+/* digmd5 secret_pass base64_string */
+/* */
+/********************************************************/
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "subcnv.h"
+#include "subrou.h"
+#include "unidig.h"
+#include "unipar.h"
+#include "uniprc.h"
+
+#define DIGMD5 "digmd5" //application name
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* 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);
+}
--- /dev/null
+#! /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
--- /dev/null
+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
+
--- /dev/null
+// 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 => `<span class="highlight">${m}</span>`);
+ return `<td>${val}</td>`;
+ });
+ tr.innerHTML = cells.join("");
+ tbody.appendChild(tr);
+ }
+}
+
+// Load initial
+refresh();
+
--- /dev/null
+// 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=>`<span class="highlight">${m}</span>`);
+ return `<td>${val}</td>`;
+ });
+ tr.innerHTML=cells.join("");
+ tbody.appendChild(tr);
+ }
+}
+
+// Load initial
+refresh();
--- /dev/null
+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 = "<p class='custom-password-message'>$msg</p>";
+ ?>
+<style>
+ .custom-password-message {
+ background-color: #ff9999; /* Custom background color */
+ color: #990000; /* Custom text color */
+ padding: 10px; /* Custom padding */
+ border: 1px solid #cc0000; /* Custom border */
+ margin-bottom: 20px; /* Custom margin */
+ }
+</style>
+<?php
+
+ return $msg . $form;
+}
+
--- /dev/null
+<?php
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+//==============================================================
+//
+// To do data access basic function
+//
+//==============================================================
+include_once "subrou.php";
+include_once "unienv.php";
+
+class devsql {
+ public $connection = null;
+ private string $OPEP="devsql.php:class_devsql";
+
+ // this function is called everytime this class is instantiated
+ // connecting to database
+ public function __construct($dbtype,$dbhost,$dbname,$dbuser) {
+ try {
+ $this->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;
+}
+
+?>
--- /dev/null
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+
+//==============================================================
+//all system functions
+//==============================================================
+
--- /dev/null
+<?php
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+
+//==============================================================
+//
+// Display management function
+//
+//==============================================================
+include_once "unienv.php";
+
+//==============================================================
+//
+// To display header screeen part
+//
+//==============================================================
+function topper($isadmin,$logname,$pageref)
+
+{
+global $userlang;
+global $dislang;
+
+$entete=getenv("APPNAME");
+$sellang = <<<EOT
+<select id="first-choice" onchange="updateTranslations()">
+<option selected="selected">$dislang</option>
+<option value="en">en</option>
+<option value="fr">fr</option>
+</select>
+EOT;
+$click1="";
+$click2="";
+$click3="";
+$admcolor="black";
+if ($isadmin==true)
+ $admcolor="red";
+switch ($pageref) {
+ case "lvllog" :
+ $sellang="";
+ break;
+ case "lvlmai" :
+ $entete="<span class=\"translatable\" trkey=\"Email management\">Email management</span>";
+ $out="<span class=\"translatable\" trkey=\"Logout\">Logout</span>";
+ if ($isadmin==true) {
+ $remotes="<span class=\"translatable\" trkey=\"SMTP servers\">SMTP servers</span>";
+ $users="<span class=\"translatable\" trkey=\"Users management\">Users management</span>";
+ $click1="<a href='/lvlrmt.php'>$remotes</a>";
+ $click2="<a href='/lvlusr.php'>$users</a>";
+ }
+ $click3="<a href='/lvllog.php'>$out</a>";
+ break;
+ case "lvlusr" :
+ $entete="<span class=\"translatable\" trkey=\"Users management\">Users management</span>";
+ //$entete=gettranslate($userlang,"User Management");
+ $main="<span class=\"translatable\" trkey=\"Email management\">Email management</span>";
+ $out="<span class=\"translatable\" trkey=\"Logout\">Logout</span>";
+ $click2="<a href='/lvlmai.php'>$main</a>";
+ $click3="<a href='/lvllog.php'>$out</a>";
+ break;
+ case "lvlrmt" :
+ $entete="<span class=\"translatable\" trkey=\"SMTP servers\">SMTP servers</span>";
+ $main="<span class=\"translatable\" trkey=\"Email management\">Email management</span>";
+ $out="<span class=\"translatable\" trkey=\"Logout\">Logout</span>";
+ $click2="<a href='/lvlmai.php'>$main</a>";
+ $click3="<a href='/lvllog.php'>$out</a>";
+ break;
+ default :
+ $color="red";
+ $data="???";
+ break;
+ }
+
+$STR = <<<EOT
+<CENTER><STRONG><FONT SIZE=+2>
+<Table WIDTH="100%">
+<TR>
+<TD align="left">
+<a href='/lvlmai.php'>
+<IMG src="reg-icons/Wwalczyszyn-Android-Style-Mail.96.png" ALT="mailbox">
+</a>
+</TD>
+<TD align="right">
+$entete
+</TD>
+<TR>
+</TABLE>
+</FONT></STRONG></CENTER>
+<table cellpadding="0" cellspacing="0" width="100%" border="0">
+<tr>
+ <td width="50%">
+ $sellang
+ <FONT COLOR=$admcolor>$logname</FONT>
+ </td>
+ <td width="50%">
+ <table cellpadding="0" cellspacing="0" width="100%" border="0">
+ <tr>
+ <td width="33%">
+ <p align="center"><strong>
+ $click1
+ </strong></p>
+ </td>
+ <td width="33%">
+ <p align="center"><strong>
+ $click2
+ </strong></p>
+ </td>
+ <td width="33%">
+ <p align="center"><strong>
+ $click3
+ </strong></p>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+</table>
+<hr width="100%" size="8" color="black" noshade>
+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 = <<<EOT
+
+<hr width="100%" size="8" color="black" noshade>
+<TABLE WIDTH=100% BORDER=0 CELLPADDING=0 CELLSPACING=0>
+<TR>
+<TD width="30%" align="left" valign="top" class="smalltxt10">
+Version: $m_release-$sql, ($pageref)
+</TD>
+<TD width="40%" align="center" valign="top" class="smalltxt10">
+$copyright
+</TD>
+<TD width="30%" align="right" valign="top" class="smalltxt10">
+$today
+</TD>
+</TR>
+</TABLE>
+<hr width="100%" size="8" color="black" noshade>
+
+EOT;
+
+return $STR;
+}
+
+//==============================================================
+//
+// To generate the HTML starter
+//
+//==============================================================
+function starthtml()
+
+{
+$theme="light";
+$curtime=time(); //Loading time stamp
+
+$STR = <<<EOT
+<!DOCTYPE html>
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<TITLE>Mailleur WEB Interface</TITLE>
+<link rel="stylesheet" href="theme.css?v=$curtime">
+</HEAD>
+<BODY data-theme={$theme}>
+EOT;
+
+return $STR;
+}
+
+//==============================================================
+//
+// To generate the HTML end
+//
+//==============================================================
+function endhtml()
+
+{
+$curtime=time(); //Loading time stamp
+
+$STR = <<<EOT
+<script defer src="translations.js?v={$curtime}"></script>
+<script defer src="directives.js?v={$curtime}"></script>
+<script defer src="coloration.js?v={$curtime}"></script>
+<script defer src="selectajax.js?v={$curtime}"></script>
+</BODY>
+</HTML>
+EOT;
+
+return $STR;
+}
+
+?>
--- /dev/null
+<?php
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+//==============================================================
+//
+// To access data within the database
+//
+//==============================================================
+include_once "subrou.php";
+include_once "devsql.php";
+
+class probe {
+ protected $db; // devsql database instance
+ private string $table; // table name
+
+ private ?string $where = null; // WHERE conditions
+
+ private ?string $order = null; // ORDER BY clause
+ private ?int $limit = null; // LIMIT for pagination
+ private int $offset = 0; // OFFSET for pagination, internal only
+ private ?string $columns = null; // request specific colunn(s)
+ private string $OPEP="gessql.php:class_probe";
+
+ /**
+ * Constructor
+ **/
+ public function __construct(string $table,int $limit,int $offset) {
+ $this->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>");
+}
+
+?>
--- /dev/null
+lvllog.php
\ No newline at end of file
--- /dev/null
+<?php
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+//==============================================================
+//
+// login screen management
+//
+//==============================================================
+include_once "subrou.php";
+include_once "unienv.php";
+include_once "gesdis.php";
+include_once "gessql.php";
+
+//==============================================================
+//
+// To display the login screen
+//
+//==============================================================
+function login()
+
+{
+$STR = <<<EOT
+
+<table border="0" align="center" width="60%" cellpadding="0" cellspacing="0">
+ <tr>
+ <td align="center">
+ <FONT SIZE=+2><STRONG>
+ <span class="translatable" trkey="Authentication">Authentication</span>
+ </STRONG></FONT>
+ </td>
+ </tr>
+ <tr>
+ <td align="center" bgcolor="#000000">
+ <table width="100%" cellpadding="0" cellspacing="1" border="0">
+ <tr>
+ <td bgcolor="#FFFFFF" align="right">
+ <form method="post"
+ action="lvllog.php"
+ enctype="application/x-www-form-urlencoded"
+ name="login">
+ <table align="center" border="0" cellspacing="5" cellpadding="0">
+ <tr>
+ <td align="left" nowrap="nowrap"><span class="translatable" trkey="Email">Email</span><span>:</span></td>
+ <td>
+ <input tabindex="1" type="text" name="email" size="40" onchange="" />
+ <select id="first-choice" onchange="updateTranslations()">
+ <option value="en">English</option>
+ <option value="fr">Francais</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" nowrap="nowrap"><span class="translatable" trkey="Password">Password</span><span>:</span></td>
+ <td>
+ <input tabindex="2" type="password" name="passwd" size="40" id="myInput" />
+ <input type="checkbox" onclick="showpass()">
+ <span class="translatable" trkey="Show" >Show</span>
+ </td>
+ </tr>
+ </table>
+
+ <table width="100%" cellpadding="0" cellspacing="1" border="0">
+ <tr>
+ <td align="center" colspan="2">
+ <input type="hidden" name="action" value="login" />
+ <table>
+ <tr>
+ <td align="center">
+ <input tabindex="3" type="submit" name="loginbutton" value="Login"
+ class="translatable" trkey="Login" />
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </form>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+<br>
+<br>
+
+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 = <<<EOT
+$start
+$top
+$login
+$footer
+$stop
+EOT;
+
+return $STR;
+}
+
+if ($_SERVER["REQUEST_METHOD"] == "POST") {
+ $pass=$_POST["passwd"];
+ $logname=$_POST["email"];
+ $dbsql=sql_connect();
+ $isok=sql_checkpassword($dbsql,$logname,$pass);
+ sql_close($dbsql);
+ switch ($isok) {
+ case false : //trouble report
+ echo "<script>";
+ echo "alert('wrong username or password. Please try again.');";
+ echo "</script>";
+ break;
+ default :
+ header('Location: lvlmai.php');
+ break;
+ }
+ }
+
+//display main screen
+echo body();
+?>
+
+
+
--- /dev/null
+<?php
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab :
+//==============================================================
+//
+// Main screen management
+//
+//==============================================================
+
+/* ============================================================
+ * AJAX MODE (JSON only)
+ * ============================================================ */
+if (isset($_POST['columns'])) {
+
+ // (temporaire, pour test)
+ header('Content-Type: application/json; charset=utf-8');
+
+ echo json_encode([
+ 'rows' => [], // 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 .=
+ '<option value="' . htmlspecialchars($value, ENT_QUOTES) . '"'
+ . ' class="translatable"'
+ . ' trkey="' . htmlspecialchars($trkey, ENT_QUOTES) . '"'
+ . $selected
+ . '>'
+ . htmlspecialchars($trkey)
+ . '</option>';
+}
+error_log($optionsHtml);
+
+$dsearchHtml = htmlspecialchars($dsearch,ENT_QUOTES|ENT_SUBSTITUTE);
+
+$debut=$offset+1;
+$STR = <<<EOT
+<TABLE WIDTH="100%" BORDER="0" CellSpacing="0">
+<TR>
+<TD align=left>
+<FORM action="{$myfilename}.php" method="post">
+<input type="hidden" name="dsearch" value="$dsearch"/>
+<input type="hidden" name="offset" value="$offset"/>
+<input type="hidden" name="limit" value="$limit"/>
+<button name="scanner" value="gofirst">
+<FONT SIZE=+3>
+⇤
+</FONT>
+</Button>
+<button name="scanner" value="goprevious">
+<FONT SIZE=+3>
+←
+</FONT>
+</Button>
+<button name="scanner" value="gonext">
+<FONT SIZE=+3>
+→
+</FONT>
+</Button>
+<button name="scanner" value="golast">
+<FONT SIZE=+3>
+⇥
+</FONT>
+</Button>
+<FONT SIZE=+2>$debut/$numrec</FONT>
+</FORM>
+</TD>
+<TD align=left>
+<FORM id="searchForm" action="{$myfilename}.php" method="post">
+<FONT SIZE=+1>
+ <span class="translatable" trkey="Search">Search</span>
+ <input type="text" id="searchInput" value="{$dsearchHtml}" name="dsearch" size=20 style="font-size: 100%;">
+ <input type="submit" style="display:none"/>
+</FONT>
+</FORM>
+</TD>
+<TD align=right>
+<FORM method="post">
+<input type="hidden" name="dsearch" value="$dsearch"/>
+<input type="hidden" name="offset" value="$offset"/>
+<input type="hidden" name="limit" value="$limit"/>
+<select id="limitSelect" name="limit" style="font-size: 130%;" onchange='if (this.value!=0) {this.form.submit();}'>
+<option selected="selected">$limit</option>
+<option value=20>20</option>
+<option value=40>40</option>
+<option value=80>80</option>
+<option value=100>100</option>
+</SELECT>
+</FORM>
+</TD>
+</TR>
+</TABLE>
+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 .= "<TR bgcolor=\"$bgcolor\">\r\n";
+ $line .= "<TD align=center>$count</TD>\r\n";
+ $line .= "<TD align=center>$status</TD>\r\n";
+ $line .= "<TD align=left>$date</TD>\r\n";
+ $line .= "<TD align=left>$remoteip</TD>\r\n";
+ $line .= "<TD align=left>$reverse</TD>\r\n";
+ $line .= "<TD align=left>$smtpfrom<BR><FONT SIZE=-1>$emailfrom</FONT></TD>\r\n";
+ $line .= "<TD align=left>$recipient</TD>\r\n";
+ $line .= "<TD align=left>$subject</TD>\r\n";
+ $line .= "</TR>\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 = <<<EOT
+
+$start
+$top
+<CENTER>
+$tblheader
+<table class="table-userlist" WIDTH="100%" BORDER="1" CellSpacing="0">
+<THEAD id="headerRow">
+<TR>
+<TH align=center>Num</TH>
+<TH align=center class="filter-col" trkey="Status">
+<span class="translatable">Status</span>
+</TH>
+<TH align=center class="filter-col" trkey="Date">
+<span class="translatable">Date</span>
+</TH>
+<TH align=center class="filter-col" trkey="IP">
+<span>IP</span>
+</TH>
+<TH align=center class="filter-col" trkey="Reverse IP">
+<span class="translatable">Reverse IP</span>
+</TH>
+<TH align=center class="filter-col" trkey="Originator">
+<span class="translatable">Originator</span>
+</TH>
+<TH align=center class="filter-col" trkey="Recipient">
+<span class="translatable">Recipient</span>
+</TH>
+<TH align=center class="filter-col" trkey="Subject">
+<span class="translatable">Subject</span>
+</TH>
+</TR>
+</THEAD>
+<TBODY id="bodyRows">
+$line
+</TBODY>
+</Table>
+$tblfooter
+</CENTER>
+<BR>
+$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();
+?>
+
--- /dev/null
+<?php
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+//==============================================================
+//
+// remote server management screen
+//
+//==============================================================
+include_once "subrou.php";
+include_once "unienv.php";
+include_once "gesdis.php";
+include_once "gessql.php";
+
+function tblheader(string $remoteip,int $numrec,int $offset,int $limit)
+
+{
+global $userlang;
+
+$debut=$offset+1;
+
+$STR = <<<EOT
+<TABLE WIDTH="100%" BORDER="0" CellSpacing="0">
+<TR>
+<TD align=left>
+<FORM action="lvlrmt.php" method="post">
+<input type="hidden" name="remoteip" value="$remoteip"/>
+<input type="hidden" name="offset" value="$offset"/>
+<input type="hidden" name="limit" value="$limit"/>
+<button name="scanner" value="gofirst">
+<FONT SIZE=+3>
+⇤
+</FONT>
+</Button>
+<button name="scanner" value="goprevious">
+<FONT SIZE=+3>
+←
+</FONT>
+</Button>
+<button name="scanner" value="gonext">
+<FONT SIZE=+3>
+→
+</FONT>
+</Button>
+<button name="scanner" value="golast">
+<FONT SIZE=+3>
+⇥
+</FONT>
+</Button>
+<FONT SIZE=+2>$debut/$numrec</FONT>
+</FORM>
+</TD>
+<TD align=left>
+<FORM action="lvlrmt.php" method="post">
+<FONT SIZE=+1>
+<span class="translatable" trkey="Search">Search</span>
+<input type="text" value="$remoteip" name="remoteip" size=20 style="font-size: 100%;">
+<input type="submit" style="display:none"/>
+</FONT>
+</FORM>
+</TD>
+<TD align=right>
+<FORM method="post">
+<input type="hidden" name="remoteip" value="$remoteip"/>
+<input type="hidden" name="offset" value="$offset"/>
+<input type="hidden" name="limit" value="$limit"/>
+<select name="limit" style="font-size: 130%;" onchange='if (this.value!=0) {this.form.submit();}'>
+<option selected="selected">$limit</option>
+<option value=20>20</option>
+<option value=40>40</option>
+<option value=80>80</option>
+<option value=100>100</option>
+</SELECT>
+</FORM>
+</TD>
+</TR>
+</TABLE>
+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."<TR>\r\n";
+ $line=$line."<TD><FONT SIZE=-1>$count </FONT>\r\n";
+ $line=$line."<INPUT TYPE=IMAGE SRC=\"/reg-icons/folder.gif\" alt=\"ouvrir le dossier\" title=\"ouvrir le dossier\">\r\n";
+ $line=$line." $ip\r\n";
+ $line=$line."</TD>\r\n";
+ $line=$line."<TD align=center>$reverse</TD>\r\n";
+ $line=$line."<TD align=center>$last</TD>\r\n";
+ $line=$line."<TD align=center>$credit</TD>\r\n";
+ $line=$line."</TR>";
+ }
+//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 = <<<EOT
+$start
+$top
+<style type="text/css">
+.table-userlist tr:nth-child(odd)
+ {
+ background-color: #66ff99; /*light green */
+ color: black ;
+ }
+
+.table-userlist tr:nth-child(even)
+ {
+ background-color: white;
+ color: black ;
+ }
+</style>
+
+<CENTER>
+$tblheader
+<table class="table-userlist" WIDTH="100%" BORDER="1" CellSpacing="0">
+<TR>
+<TH align=center>IP</TH>
+<TH align=center>Reverse</TH>
+<TH align=center>lastemail</TH>
+<TH align=center>credit</TH>
+</TR>
+$line
+</Table>
+$tblfooter
+</CENTER>
+<BR>
+<BR>
+$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();
+?>
+
+
+
--- /dev/null
+<?php
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+//==============================================================
+//
+// Main screen management
+//
+//==============================================================
+include_once "subrou.php";
+include_once "unienv.php";
+include_once "gesdis.php";
+include_once "gessql.php";
+
+function tblheader(string $username,int $numrec,int $offset,int $limit)
+
+{
+global $userlang;
+
+$debut=$offset+1;
+
+$STR = <<<EOT
+<TABLE WIDTH="100%" BORDER="0" CellSpacing="0">
+<TR>
+<TD align=left>
+<FORM action="lvlusr.php" method="post">
+<input type="hidden" name="username" value="$username"/>
+<input type="hidden" name="offset" value="$offset"/>
+<input type="hidden" name="limit" value="$limit"/>
+<button name="scanner" value="gofirst">
+<FONT SIZE=+3>
+⇤
+</FONT>
+</Button>
+<button name="scanner" value="goprevious">
+<FONT SIZE=+3>
+←
+</FONT>
+</Button>
+<button name="scanner" value="gonext">
+<FONT SIZE=+3>
+→
+</FONT>
+</Button>
+<button name="scanner" value="golast">
+<FONT SIZE=+3>
+⇥
+</FONT>
+</Button>
+<FONT SIZE=+2>$debut/$numrec</FONT>
+</FORM>
+</TD>
+<TD align=left>
+<FORM action="lvlusr.php" method="post">
+<FONT SIZE=+1>
+<span class="translatable" trkey="Search">Search</span>
+<input type="text" value="$username" name="username" size=20 style="font-size: 100%;">
+<input type="submit" style="display:none"/>
+</FONT>
+</FORM>
+</TD>
+<TD align=right>
+<FORM method="post">
+<input type="hidden" name="username" value="$username"/>
+<input type="hidden" name="offset" value="$offset"/>
+<input type="hidden" name="limit" value="$limit"/>
+<select name="limit" style="font-size: 130%;" onchange='if (this.value!=0) {this.form.submit();}'>
+<option selected="selected">$limit</option>
+<option value=20>20</option>
+<option value=40>40</option>
+<option value=80>80</option>
+<option value=100>100</option>
+</SELECT>
+</FORM>
+</TD>
+</TR>
+</TABLE>
+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."<TR>\r\n";
+ $line=$line."<TD><FONT SIZE=-1>$count </FONT>\r\n";
+ $line=$line."<INPUT TYPE=IMAGE SRC=\"/reg-icons/folder.gif\" alt=\"ouvrir le dossier\" title=\"ouvrir le dossier\">\r\n";
+ $line=$line." $name\r\n";
+ $line=$line."</TD>\r\n";
+ $line=$line."<TD align=center>$last</TD>\r\n";
+ $line=$line."<TD align=center>$max</TD>\r\n";
+ $line=$line."<TD align=center>$lock</TD>\r\n";
+ $line=$line."</TR>";
+ }
+//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 = <<<EOT
+$start
+$top
+<style type="text/css">
+.table-userlist tr:nth-child(odd)
+ {
+ background-color: #66ff99; /*light green */
+ color: black ;
+ }
+
+.table-userlist tr:nth-child(even)
+ {
+ background-color: white;
+ color: black ;
+ }
+</style>
+
+<CENTER>
+<table WIDTH="100%" BORDER="0" CellSpacing="0">
+$tblheader
+<table class="table-userlist" WIDTH="100%" BORDER="1" CellSpacing="0">
+<TR>
+<TH align=center>Email</TH>
+<TH align=center>lastemail</TH>
+<TH align=center>mxspace</TH>
+<TH align=center>locked</TH>
+</TR>
+$line
+</Table>
+$tblfooter
+</CENTER>
+<BR>
+<BR>
+$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();
+?>
+
+
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8" name="viewport" content="width=device-width, initial-scale=1">
+<style>
+/* Style all input fields */
+input {
+ width: 100%;
+ padding: 12px;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ box-sizing: border-box;
+ margin-top: 6px;
+ margin-bottom: 16px;
+}
+
+/* Style the submit button */
+input[type=submit] {
+ background-color: #04AA6D;
+ color: white;
+}
+
+/* Style the container for inputs */
+.container {
+ background-color: #f1f1f1;
+ padding: 20px;
+}
+
+/* The message box is shown when the user clicks on the password field */
+#message {
+ display:none;
+ background: #f1f1f1;
+ color: #000;
+ position: relative;
+ padding: 20px;
+ margin-top: 10px;
+}
+
+#message p {
+ padding: 10px 35px;
+ font-size: 18px;
+}
+
+/* Add a green text color and a checkmark when the requirements are right */
+.valid {
+ color: green;
+}
+
+.valid:before {
+ position: relative;
+ left: -35px;
+ content: "✔";
+}
+
+/* Add a red text color and an "x" when the requirements are wrong */
+.invalid {
+ color: red;
+}
+
+.invalid:before {
+ position: relative;
+ left: -35px;
+ content: "✖";
+}
+</style>
+</head>
+<body>
+
+<h3>Password Validation</h3>
+<p>Try to submit the form.</p>
+
+<div class="container">
+ <form action="/action_page.php">
+ <label for="usrname">Username</label>
+ <input type="text" id="usrname" name="usrname" required>
+
+ <label for="psw">Password</label>
+ <input type="password" id="psw" name="psw" pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}" title="Must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters" required>
+
+ <input type="submit" value="Submit">
+ </form>
+</div>
+
+<div id="message">
+ <h3>Password must contain the following:</h3>
+ <p id="letter" class="invalid">A <b>lowercase</b> letter</p>
+ <p id="capital" class="invalid">A <b>capital (uppercase)</b> letter</p>
+ <p id="number" class="invalid">A <b>number</b></p>
+ <p id="length" class="invalid">Minimum <b>8 characters</b></p>
+</div>
+
+<script>
+var myInput = document.getElementById("psw");
+var letter = document.getElementById("letter");
+var capital = document.getElementById("capital");
+var number = document.getElementById("number");
+var length = document.getElementById("length");
+
+// When the user clicks on the password field, show the message box
+myInput.onfocus = function() {
+ document.getElementById("message").style.display = "block";
+}
+
+// When the user clicks outside of the password field, hide the message box
+myInput.onblur = function() {
+ document.getElementById("message").style.display = "none";
+}
+
+// When the user starts to type something inside the password field
+myInput.onkeyup = function() {
+ // Validate lowercase letters
+ var lowerCaseLetters = /[a-z]/g;
+ if(myInput.value.match(lowerCaseLetters)) {
+ letter.classList.remove("invalid");
+ letter.classList.add("valid");
+ } else {
+ letter.classList.remove("valid");
+ letter.classList.add("invalid");
+ }
+
+ // Validate capital letters
+ var upperCaseLetters = /[A-Z]/g;
+ if(myInput.value.match(upperCaseLetters)) {
+ capital.classList.remove("invalid");
+ capital.classList.add("valid");
+ } else {
+ capital.classList.remove("valid");
+ capital.classList.add("invalid");
+ }
+
+ // Validate numbers
+ var numbers = /[0-9]/g;
+ if(myInput.value.match(numbers)) {
+ number.classList.remove("invalid");
+ number.classList.add("valid");
+ } else {
+ number.classList.remove("valid");
+ number.classList.add("invalid");
+ }
+
+ // Validate length
+ if(myInput.value.length >= 8) {
+ length.classList.remove("invalid");
+ length.classList.add("valid");
+ } else {
+ length.classList.remove("valid");
+ length.classList.add("invalid");
+ }
+}
+</script>
+
+</body>
+</html>
--- /dev/null
+<?php
+//Information about application PHP data
+
+//release information
+$m_version=VERSION;
+$m_release=NEXTREL;
+$m_branch=BRANCH;
+$m_release=MAILREL;
+
+//constant
+$copyright="© 2025 GPL_V3 (info@safe.ca)"
+
+?>
--- /dev/null
+<?php
+//Information about application PHP data
+
+//release information
+$m_version="0.19";
+$m_release="1";
+$m_branch="dvl";
+$m_release="0.19-1-dvl";
+
+//constant
+$copyright="© 2025 GPL_V3 (info@safe.ca)"
+
+?>
--- /dev/null
+<?php
+$fields = ["Nom", "Email", "Âge"];
+$data = [
+ ["Alice", "alice@example.com", 25],
+ ["Bob", "bob@example.com", 30],
+ ["Charlie", "charlie@example.com", 22],
+];
+?>
+<!DOCTYPE html>
+<html lang="fr">
+<head>
+<meta charset="UTF-8">
+<title>Tableau filtrable "super débile écoeurant"</title>
+<style>
+table { border-collapse: collapse; width: 60%; margin-top: 10px; }
+th, td { border: 1px solid #000; padding: 6px 12px; text-align: left; cursor: pointer; transition: background-color 0.3s; }
+th.selected { background-color: #ffd700; color: #000; }
+td span.highlight { background-color: #ff4; font-weight: bold; }
+input { width: 60%; padding: 6px; font-size: 16px; }
+</style>
+</head>
+<body>
+
+<h2>Recherche filtrable “Super, débile, écoeurante” 😎</h2>
+
+<input type="text" id="searchInput" placeholder="Tapez pour filtrer...">
+
+<table id="myTable">
+ <thead>
+ <tr>
+ <?php foreach($fields as $field): ?>
+ <th><?= htmlspecialchars($field) ?></th>
+ <?php endforeach; ?>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach($data as $row): ?>
+ <tr>
+ <?php foreach($row as $cell): ?>
+ <td><?= htmlspecialchars($cell) ?></td>
+ <?php endforeach; ?>
+ </tr>
+ <?php endforeach; ?>
+ </tbody>
+</table>
+
+<script>
+// --- Setup ---
+const input = document.getElementById('searchInput');
+const table = document.getElementById('myTable');
+const rows = table.tBodies[0].rows;
+const headers = table.tHead.rows[0].cells;
+let activeCols = new Set([0]); // colonne(s) active(s) par défaut
+
+// --- Gestion du clic sur les en-têtes ---
+for (let i = 0; i < headers.length; i++) {
+ headers[i].addEventListener('click', () => {
+ if (activeCols.has(i)) {
+ activeCols.delete(i);
+ headers[i].classList.remove('selected');
+ } else {
+ activeCols.add(i);
+ headers[i].classList.add('selected');
+ }
+ filterTable();
+ });
+}
+
+// --- Fonction de filtrage et highlight ---
+input.addEventListener('input', filterTable);
+
+function filterTable() {
+ const query = input.value.toLowerCase();
+
+ for (let row of rows) {
+ let match = false;
+ for (let i = 0; i < row.cells.length; i++) {
+ const cell = row.cells[i];
+ const text = cell.textContent;
+
+ if (activeCols.has(i) && text.toLowerCase().includes(query) && query !== "") {
+ // highlight
+ const regex = new RegExp(`(${escapeRegExp(query)})`, 'gi');
+ cell.innerHTML = text.replace(regex, '<span class="highlight">$1</span>');
+ match = true;
+ } else {
+ // reset
+ cell.textContent = text;
+ }
+ }
+ row.style.display = match || query === "" ? '' : 'none';
+ }
+}
+
+// --- Fonction helper pour regex ---
+function escapeRegExp(string) {
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+}
+
+// --- Initialisation visuelle ---
+for (let i of activeCols) headers[i].classList.add('selected');
+</script>
+
+</body>
+</html>
+
--- /dev/null
+<?php
+$fields = ["Nom", "Email", "Âge"];
+$data = [
+ ["Alice", "alice@example.com", 25],
+ ["Bob", "bob@example.com", 30],
+ ["Charlie", "charlie@example.com", 22],
+];
+?>
+<!DOCTYPE html>
+<html lang="fr">
+<head>
+<meta charset="UTF-8">
+<title>Tableau Filtrable Ultime 😎</title>
+<style>
+body { font-family: sans-serif; }
+table { border-collapse: collapse; width: 60%; margin-top: 10px; }
+th, td { border: 1px solid #000; padding: 6px 12px; text-align: left; cursor: pointer; transition: background-color 0.3s, transform 0.2s; }
+th.selected { background-color: #ff9800; color: #fff; }
+td span.highlight { font-weight: bold; transition: background-color 0.3s; }
+input { width: 60%; padding: 6px; font-size: 16px; margin-bottom: 10px; }
+
+/* Confetti effect */
+.confetti { position: absolute; width: 6px; height: 6px; background-color: red; animation: confetti-fall 1s linear forwards; z-index: 1000; border-radius: 50%; }
+@keyframes confetti-fall { 0% { transform: translateY(0) rotate(0deg); opacity: 1; } 100% { transform: translateY(100px) rotate(360deg); opacity: 0; } }
+</style>
+</head>
+<body>
+
+<h2>Recherche “Ultime, Écoeurante, Joyeuse” 😎</h2>
+<input type="text" id="searchInput" placeholder="Tapez pour filtrer...">
+
+<table id="myTable">
+ <thead>
+ <tr>
+ <?php foreach($fields as $field): ?>
+ <th><?= htmlspecialchars($field) ?></th>
+ <?php endforeach; ?>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach($data as $row): ?>
+ <tr>
+ <?php foreach($row as $cell): ?>
+ <td><?= htmlspecialchars($cell) ?></td>
+ <?php endforeach; ?>
+ </tr>
+ <?php endforeach; ?>
+ </tbody>
+</table>
+
+<script>
+const input = document.getElementById('searchInput');
+const table = document.getElementById('myTable');
+const rows = table.tBodies[0].rows;
+const headers = table.tHead.rows[0].cells;
+
+// Colonne active par défaut
+let activeCols = new Set([0]);
+
+// Palette dynamique pour highlight par colonne
+const colors = ["#ffeb3b","#8bc34a","#03a9f4","#e91e63","#9c27b0"];
+
+// --- clic sur en-tête pour sélectionner/désélectionner colonnes ---
+for (let i = 0; i < headers.length; i++) {
+ headers[i].addEventListener('click', () => {
+ if (activeCols.has(i)) {
+ activeCols.delete(i);
+ headers[i].classList.remove('selected');
+ } else {
+ activeCols.add(i);
+ headers[i].classList.add('selected');
+ }
+ filterTable();
+ });
+}
+
+// --- filtrage et highlight ---
+input.addEventListener('input', filterTable);
+
+function filterTable() {
+ const query = input.value.toLowerCase();
+
+ for (let row of rows) {
+ let match = false;
+ for (let i = 0; i < row.cells.length; i++) {
+ const cell = row.cells[i];
+ const text = cell.textContent;
+
+ if (activeCols.has(i) && text.toLowerCase().includes(query) && query !== "") {
+ const regex = new RegExp(`(${escapeRegExp(query)})`, 'gi');
+ cell.innerHTML = text.replace(regex, `<span class="highlight" style="background-color:${colors[i % colors.length]}">$1</span>`);
+ match = true;
+ } else {
+ cell.textContent = text;
+ }
+ }
+ row.style.display = match || query === "" ? '' : 'none';
+ if (match && query !== "") {
+ triggerConfetti(row);
+ row.style.transform = "scale(1.02)";
+ setTimeout(()=>row.style.transform="scale(1)",200);
+ }
+ }
+}
+
+// --- helper regex ---
+function escapeRegExp(string) {
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+}
+
+// --- confetti ---
+function triggerConfetti(row) {
+ for (let i=0;i<5;i++){
+ const conf = document.createElement('div');
+ conf.className = 'confetti';
+ conf.style.left = (row.getBoundingClientRect().left + Math.random()*row.offsetWidth) + 'px';
+ conf.style.top = (row.getBoundingClientRect().top + window.scrollY) + 'px';
+ conf.style.backgroundColor = colors[Math.floor(Math.random()*colors.length)];
+ document.body.appendChild(conf);
+ setTimeout(()=>conf.remove(),1000);
+ }
+}
+
+// --- initialisation ---
+for (let i of activeCols) headers[i].classList.add('selected');
+</script>
+
+</body>
+</html>
+
--- /dev/null
+<?php
+// ----------------------
+// Fichier PHP principal
+// ----------------------
+
+// Données du tableau
+$fields = ["Nom", "Email", "Âge"];
+$data = [
+ ["Alice", "alice@example.com", 25],
+ ["Bob", "bob@example.com", 30],
+ ["Charlie", "charlie@example.com", 22],
+];
+
+// Génération du HTML des en-têtes
+function generateTableHeader(array $fields): string {
+ $html = '';
+ foreach ($fields as $field) {
+ $html .= "<th>" . htmlspecialchars($field) . "</th>";
+ }
+ return $html;
+}
+
+// Génération du HTML du corps
+function generateTableBody(array $data): string {
+ $html = '';
+ foreach ($data as $row) {
+ $html .= "<tr>";
+ foreach ($row as $cell) {
+ $html .= "<td>" . htmlspecialchars($cell) . "</td>";
+ }
+ $html .= "</tr>";
+ }
+ return $html;
+}
+
+// Injection des contenus dans des variables
+$tableHeaderHTML = generateTableHeader($fields);
+$tableBodyHTML = generateTableBody($data);
+?>
+
+<!DOCTYPE html>
+<html lang="fr">
+<head>
+<meta charset="UTF-8">
+<title>Tableau filtrable Super</title>
+<style>
+table { border-collapse: collapse; width: 50%; margin-top: 10px; }
+th, td { border: 1px solid #000; padding: 4px 8px; text-align: left; cursor: pointer; }
+th.selected { background-color: #cce5ff; }
+td span.highlight { background-color: #ffeb3b; font-weight: bold; }
+input.filter-input { width: 50%; padding: 4px; margin-bottom: 8px; font-size: 14px; }
+</style>
+</head>
+<body>
+
+<h2>Tableau filtrable “Super”</h2>
+
+<input type="text" class="filter-input" placeholder="Tapez pour filtrer...">
+
+<table class="filter-table">
+ <thead>
+ <tr><?= $tableHeaderHTML ?></tr>
+ </thead>
+ <tbody>
+ <?= $tableBodyHTML ?>
+ </tbody>
+</table>
+
+<script>
+// Classe générique pour filtrer un tableau avec multi-colonnes
+class TableFilter {
+ constructor(tableElement, inputElement) {
+ this.table = tableElement;
+ this.input = inputElement;
+ this.rows = tableElement.tBodies[0].rows;
+ this.headers = tableElement.tHead.rows[0].cells;
+ this.activeCols = new Set([0]); // colonne(s) active(s) par défaut
+
+ this.init();
+ }
+
+ init() {
+ for (let i = 0; i < this.headers.length; i++) {
+ this.headers[i].addEventListener('click', () => {
+ // toggle colonne active
+ if (this.activeCols.has(i)) {
+ this.activeCols.delete(i);
+ this.headers[i].classList.remove('selected');
+ } else {
+ this.activeCols.add(i);
+ this.headers[i].classList.add('selected');
+ }
+ this.filter();
+ });
+ }
+
+ this.input.addEventListener('input', () => this.filter());
+
+ // Initialisation visuelle
+ for (let i of this.activeCols) this.headers[i].classList.add('selected');
+ }
+
+ filter() {
+ const query = this.input.value.toLowerCase();
+
+ for (let row of this.rows) {
+ let match = false;
+
+ for (let i = 0; i < row.cells.length; i++) {
+ const cell = row.cells[i];
+ const text = cell.textContent;
+
+ if (this.activeCols.has(i) && query && text.toLowerCase().includes(query)) {
+ const regex = new RegExp(`(${this.escapeRegExp(query)})`, 'gi');
+ cell.innerHTML = text.replace(regex, '<span class="highlight">$1</span>');
+ match = true;
+ } else {
+ cell.textContent = text; // reset highlight
+ }
+ }
+
+ // Affichage : au moins une colonne correspond
+ row.style.display = match || query === "" ? '' : 'none';
+ }
+ }
+
+ escapeRegExp(string) {
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+ }
+}
+
+// Instanciation générique pour tous les tableaux
+document.querySelectorAll('.filter-table').forEach(table => {
+ const input = document.querySelector('.filter-input');
+ new TableFilter(table, input);
+});
+</script>
+
+</body>
+</html>
+
--- /dev/null
+<?php
+/* =======================================================
+ Super-DB One-File avec pagination SQL et multi-colonnes
+ Layout corrigé : [Lang] seule ligne, [Recherche][Pagination] sur ligne suivante
+ ======================================================= */
+class TableFilter
+{
+ private PDO $pdo;
+ private string $table;
+ private array $columns;
+
+ public function __construct(PDO $pdo, string $table, array $columns)
+ {
+ $this->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];
+?>
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Bigre Super-DB Paginated JMP</title>
+<style>
+.table-filter-row { display:flex; gap:8px; align-items:center; margin-bottom:6px; flex-wrap: wrap; }
+#langSelect-row { display:block; margin-bottom:12px; } /* isole Lang sur sa propre ligne */
+table{border-collapse:collapse;width:100%;}
+th,td{padding:6px;border:1px solid #888;}
+.filter-col{cursor:pointer;color:#003;background:#f7f7ff;}
+.filter-col.active{background:#cce;}
+</style>
+</head>
+<body>
+
+<!-- Ligne 1 : Langue -->
+<div id="langSelect-row">
+ <select id="langSelect" onchange="window.location='?lang='+this.value;">
+ <option value="en" <?= $lang==="en"?"selected":"" ?>>English</option>
+ <option value="fr" <?= $lang==="fr"?"selected":"" ?>>Français</option>
+ </select>
+</div>
+
+<!-- Ligne 2 : Recherche + Pagination -->
+<div class="table-filter-row">
+ <input type="text" id="searchInput" placeholder="Type to filter…">
+ <select id="limitSelect">
+ <?php foreach([5,10,20,40,80] as $n): ?>
+ <option value="<?= $n ?>" <?= $n===20?"selected":"" ?>><?= $n ?></option>
+ <?php endforeach; ?>
+ </select>
+</div>
+
+<!-- Tableau -->
+<table id="dataTable">
+ <thead>
+ <tr>
+ <?php foreach($L as $i=>$label): ?>
+ <th class="filter-col" data-col="<?= $colKeys[$i] ?>"><?= htmlspecialchars($label) ?></th>
+ <?php endforeach; ?>
+ </tr>
+ </thead>
+ <tbody></tbody>
+</table>
+
+<script>
+let columns=[];
+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.dataset.col;
+ 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(){
+ const form = new FormData();
+ form.append("search", searchInput.value);
+ form.append("limit", limitSelect.value);
+ columns.forEach(c=>form.append("columns[]",c));
+
+ fetch("", {method:"POST", body:form})
+ .then(r=>r.json())
+ .then(json=>renderTable(json));
+}
+
+// Remplissage tableau
+function renderTable(rows){
+ const tbody=document.querySelector("#dataTable tbody");
+ tbody.innerHTML="";
+ for(const row of rows){
+ const tr=document.createElement("tr");
+ tr.innerHTML=`<td>${row.remoteip}</td><td>${row.reverse}</td><td>${row.creation}</td>`;
+ tbody.appendChild(tr);
+ }
+}
+
+// Load initial
+refresh();
+</script>
+
+</body>
+</html>
+
--- /dev/null
+<?php
+/* =======================================================
+ Super-DB One-File corrigé : affichage NULL explicite
+ ======================================================= */
+class TableFilter
+{
+ private PDO $pdo;
+ private string $table;
+ private array $columns;
+
+ public function __construct(PDO $pdo, string $table, array $columns)
+ {
+ $this->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];
+?>
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Super-DB Paginated Highlight</title>
+<style>
+.table-filter-row { display:flex; gap:8px; align-items:center; margin-bottom:6px; flex-wrap: wrap; }
+#langSelect-row { display:block; margin-bottom:12px; }
+table{border-collapse:collapse;width:100%;}
+th,td{padding:6px;border:1px solid #888;}
+.filter-col{cursor:pointer;color:#003;background:#f7f7ff;}
+.filter-col.active{background:#cce;}
+.highlight{background:#ff9;color:#000;}
+</style>
+</head>
+<body>
+
+<!-- Ligne 1 : Langue -->
+<div id="langSelect-row">
+ <select id="langSelect" onchange="window.location='?lang='+this.value;">
+ <option value="en" <?= $lang==="en"?"selected":"" ?>>English</option>
+ <option value="fr" <?= $lang==="fr"?"selected":"" ?>>Français</option>
+ </select>
+</div>
+
+<!-- Ligne 2 : Recherche + Pagination -->
+<div class="table-filter-row">
+ <input type="text" id="searchInput" placeholder="Type to filter…">
+ <select id="limitSelect">
+ <?php foreach([5,10,20,40,80] as $n): ?>
+ <option value="<?= $n ?>" <?= $n===20?"selected":"" ?>><?= $n ?></option>
+ <?php endforeach; ?>
+ </select>
+</div>
+
+<!-- Tableau -->
+<table id="dataTable">
+ <thead>
+ <tr>
+ <?php foreach($L as $i=>$label): ?>
+ <th class="filter-col" data-col="<?= $colKeys[$i] ?>"><?= htmlspecialchars($label) ?></th>
+ <?php endforeach; ?>
+ </tr>
+ </thead>
+ <tbody></tbody>
+</table>
+
+<script>
+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.dataset.col;
+ 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=>`<span class="highlight">${m}</span>`);
+ return `<td>${val}</td>`;
+ });
+ tr.innerHTML=cells.join("");
+ tbody.appendChild(tr);
+ }
+}
+
+// Load initial
+refresh();
+</script>
+
+</body>
+</html>
+
--- /dev/null
+<?php
+/* =======================================================
+ TableFilter.php -->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);
+ }
+}
+
--- /dev/null
+<?php
+//==============================================================
+//
+// To manage language
+//
+//==============================================================
+include_once "subrou.php";
+
+
+//list of available word
+
+enum lng {
+ case en; //English default language
+ case fr; //French
+ case un; //Unknown language (english)
+ }
+
+$userlang=lng::en;
+
+function gettranslate(lng $lang,$mot)
+
+{
+
+$mot=$mot."_X";
+return $mot;
+}
+?>
--- /dev/null
+<?php
+//==============================================================
+//
+// To manage all access to MariaDB database
+//
+//==============================================================
+
+//==============================================================
+// To connect to a local/remote MYSQL database
+//==============================================================
+function mar_connect($dbhost,$dbusr,$dbname,$dbport)
+
+{
+$OPEP="unimar.php, mar_connect";
+
+$conn=mysqli_connect($dbhost,$dbusr,'',$dbname,$dbport);
+if (mysqli_connect_error()) {
+ }
+return $conn;
+}
+
+
+//==============================================================
+// To disconnect from a local/remote MYSQL database
+//==============================================================
+function mar_close($conn)
+
+{
+$OPEP="unimar.php, mar_close";
+
+mysqli_close($conn);
+return 0;
+}
+?>
--- /dev/null
+<?php
+// vim: smarttab tabstop=8 shiftwidth=2 expandtab
+//==============================================================
+//
+// To manage all access to Postgresql database
+//
+//==============================================================
+
+class pgsql {
+ private $connection = null;
+ // this function is called everytime this class is instantiated
+
+ public function __construct() {
+ $this->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;
+}
+?>
+
--- /dev/null
+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));
+ });
+});
+
--- /dev/null
+/**
+ * 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);
+
--- /dev/null
+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());
+
--- /dev/null
+<?php
+//==============================================================
+//
+// To manage very low level function
+//
+//==============================================================
+//gobal variables.
+$debug=0; //default debug level
+$logname=NULL; //authenticated user name
+$isadmin=0; //authenticated user with admin level
+
+//==============================================================
+// Open a syslog channel
+//==============================================================
+function rou_openlog()
+
+{
+openlog("Mailleur (PHP)",LOG_PID,LOG_DAEMON);
+}
+
+//==============================================================
+// close a syslog channel
+//==============================================================
+
+function rou_closelog()
+
+{
+closelog();
+}
+//==============================================================
+// log data on syslog channel
+//==============================================================
+function rou_alert($dbglvl,$report)
+
+{
+global $debug;
+
+if ($debug>=$dbglvl)
+ syslog(LOG_INFO,"dbg=$debug, $report");
+}
+
+rou_openlog();
+?>
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+// 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 = `<i>${key}</i>`; // 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();
+//==============================================================
--- /dev/null
+<?php
+
+//==============================================================
+//
+// To load environment variable
+//
+//==============================================================
+function loadenv()
+
+{
+$env_file_path="/etc/mailleur/mailleur.conf";
+$phase=0;
+$proceed=true;
+while ($proceed==true) {
+ rou_alert(2,"unienv.c:loadenv JMPDBG phase='$phase'");
+ switch ($phase) {
+ case 0 : //checking if file exist
+ if(!is_file($env_file_path)){
+ throw new ErrorException("File <".$env_file_path."> 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();
+?>