diff -uN qmail-1.03/ANTISPAM qmail-ldap/ANTISPAM --- qmail-1.03/ANTISPAM Thu Jan 1 01:00:00 1970 +++ qmail-ldap/ANTISPAM Thu Apr 29 09:48:08 1999 @@ -0,0 +1,55 @@ +The antispam patch included adds some features qmail's SMTP daemon: + +It is an update by Lindsay Haisley of Rask Lambertsen's excellent +antispam patch for qmail v1.01, based on Lionel Widdifield's patch. + + Envelope address filtering. + --------------------------- + +qmail-smtpd will read the DENYMAIL environment variable to determine how to +handle sender addresses: + +DENYMAIL set to anything +The address will be rejected if + - it doesn't contain a '@'. + - it contains a bang path without a host name ("user!@domain"). + - the domain part has no '.' in it. + - the top level domain has fewer than 2 or more than 3 characters in it. + +DENYMAIL set to DNSCHECK +The address will be rejected if + - there are no MX or A records in the DNS for the domain part (= you can't + send a reply). Note that in case of temporary DNS errors, the address will + be rejected with a temporary error code so the remote MTA will try again + later. + +DENYMAIL set to NOBOUNCE +Bounces (envelope sender empty or "#@[]") will be rejected. + +DENYMAIL set to SPAM +All addresses will be rejected. + +The patch extends the syntax of control/badmailfrom. In addition to the + + user@domain + @domain + +syntax, you can also use + + user@ + +to reject all sender addresses witha user part of "user". + +The patch allows the use of a new control file, control/badrcptto. This file +lists recipient addresses that should be rejected. You can use + + user@domain + +and + + @domain + +to specify invalid addresses. This can be useful if a spammer sends lots of +messages to a nonexistant user from an invalid address, as otherwise, +postmaster will get lots of double bounces. + diff -uN qmail-1.03/FILES qmail-ldap/FILES --- qmail-1.03/FILES Mon Jun 15 12:53:16 1998 +++ qmail-ldap/FILES Tue Sep 4 00:19:34 2001 @@ -431,3 +431,47 @@ tcp-environ.5 constmap.h constmap.c +QLDAPINSTALL +base64.c +base64.h +check.c +check.h +checkpassword.c +digest.c +digest_md4.c +digest_md4.h +digest_md5.c +digest_md5.h +digest_rmd160.c +digest_rmd160.h +digest_sha1.c +digest_sha1.h +endian.c +qmail-reply.c +qmail-quotawarn.c +ANTISPAM +qmail-ldap.h +QLDAPNEWS +maildir++.h +maildir++.c +auth_imap.c +auth_pop.c +auth_mod.h +qldap-debug.h +qldap-debug.c +qldap-errno.h +qldap-ldaplib.c +qldap-ldaplib.h +qldap-mdm.c +qldap-mdm.h +qldap-errno.c +qmail-ldaplookup.c +QLDAPTODO +QLDAPPICTURE +TLS.readme +dirmaker +popfetch.pl +qldap-profile.c +qldap-profile.h +output.h +output.c diff -uN qmail-1.03/Makefile qmail-ldap/Makefile --- qmail-1.03/Makefile Mon Jun 15 12:53:16 1998 +++ qmail-ldap/Makefile Sun Sep 30 14:58:57 2001 @@ -1,8 +1,76 @@ +# Edit this few lines to configure your ldap stuff and checkpassword + +# to enable some additional for qmail-ldap stuff put it on the LDAPFLAGS line +# -DLDAP_ESCAPE_BUG should be added as long as the ldap servers have +# problems with the escapeing of LDAP filters (fixed with OpenLDAP 1.2.7) +# -DQLDAP_CLUSTER for enabling cluster support +# to enable the dash_ext patch for extended mail addresses add +# -DDASH_EXT to the LDAPFLAGS +# to use cleartext passwords (a bad idea on production systems) add +# -DCLEARTEXTPASSWD to the LDAPFLAGS +#LDAPFLAGS=-DQLDAP_CLUSTER + +# Perhaps you have different ldap libraries, change them here +LDAPLIBS=-L/usr/local/lib -lldap -llber +# and change the location of the include files here +LDAPINCLUDES=-I/usr/local/include +# on Slowaris you need -lresolv and probably a LD_RUN_PATH added like this: +#LDAPLIBS=-L/opt/OpenLDAP/lib -lldap -llber -lresolv -R/opt/OpenLDAP/lib +# for example on my Linux box I use: +#LDAPLIBS=-L/opt/OpenLDAP/lib -lldap -llber +# if you need a special include-directory for ldap headers enable this +#LDAPINCLUDES=-I/opt/OpenLDAP/include + +# TLS (SMTP encryption) in qmail-smtpd and qmail-remote, see TLS.readme +# You need OpenSSL for this +# TLS enable +#TLSON=-DTLS +# Path to OpenSSL includes +#TLSINCLUDES=-I/usr/local/include +# Path to OpenSSL libraries +#TLSLIBS=-L/usr/local/lib -lssl -lcrypto +# Path to OpenSSL binary +#OPENSSLBIN=/usr/local/bin/openssl + +# to make the Netscape download progress bar work with qmail-pop3d +# uncomment the next line (allready done) +MNW=-DMAKE_NETSCAPE_WORK + +# to enable the auto-maildir-make feature uncomment the next line +#MDIRMAKE=-DAUTOMAILDIRMAKE + +# to enable the auto-homedir-make feature uncomment the next line +#HDIRMAKE=-DAUTOHOMEDIRMAKE + +# on most systems we need this to make checkpassword +SHADOWLIBS=-lcrypt +# OpenBSD Systems seems to have no libcrypt, so comment the line out if you +# get linking problems +# To use shadow passwords under some Linux OS, uncomment the next two lines. +#SHADOWLIBS=-lcrypt -lshadow +#SHADOWOPTS=-DPW_SHADOW +# To use shadow passwords under Solaris, uncomment the SHADOWOPTS line. + +# to enable the possibility to log and debug imap and pop uncoment the +# next line +#DEBUG=-DDEBUG +# WARNING: you need a NONE DEBUG auth_* to run with inetd + +# for profiling ... +#INCTAI=../libtai-0.60 +#LIBTAI=../libtai-0.60 + +# Just for me, make from time to time a backup +BACKUPPATH=/backup/qmail-backup/qmail-ldap.`date "+%Y%m%d-%H%M"`.tar +# STOP editing HERE !!! + # Don't edit Makefile! Use conf-* for configuration. SHELL=/bin/sh -default: it +default: it qldap + +qldap: qmail-quotawarn qmail-reply auth_pop auth_imap digest qmail-ldaplookup addresses.0: \ addresses.5 @@ -20,6 +88,47 @@ compile alloc_re.c alloc.h byte.h ./compile alloc_re.c +auth_imap.o: \ +compile auth_imap.c error.h qldap-errno.h readwrite.h stralloc.h env.h \ +str.h timeoutread.h auth_mod.h qldap-mdm.h exit.h qldap-debug.h + ./compile $(LDAPFLAGS) $(HDIRMAKE) $(DEBUG) auth_imap.c + +auth_imap: \ +load auth_imap.o checkpassword.o check.o control.o getln.a qldap-debug.o \ +fs.a open.a stralloc.a alloc.a substdio.a error.a env.a auto_qmail.o \ +str.a base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \ +dns.o timeoutconn.o ndelay.a ipalloc.o dns.lib socket.lib qldap-ldaplib.o \ +timeoutread.o qldap-mdm.o wait.a sig.a prot.o qldap-errno.o output.o \ +constmap.o case.a + ./load auth_imap checkpassword.o check.o control.o qldap-ldaplib.o \ + qldap-debug.o output.o auto_qmail.o dns.o timeoutconn.o timeoutread.o \ + ip.o base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \ + ipalloc.o constmap.o case.a getln.a open.a env.a stralloc.a alloc.a \ + substdio.a str.a qldap-mdm.o wait.a qldap-errno.o error.a fs.a \ + ndelay.a sig.a prot.o $(LDAPLIBS) $(SHADOWLIBS) \ + `cat dns.lib` `cat socket.lib` + +auth_pop.o: \ +compile auth_pop.c error.h qldap-errno.h readwrite.h stralloc.h env.h \ +str.h timeoutread.h auth_mod.h qldap-mdm.h exit.h fmt.h sig.h wait.h \ +scan.h alloc.h qldap-debug.h + ./compile $(LDAPFLAGS) $(HDIRMAKE) $(DEBUG) auth_pop.c + +auth_pop: \ +load auth_pop.o checkpassword.o check.o control.o getln.a qldap-debug.o \ +fs.a open.a stralloc.a alloc.a substdio.a error.a env.a auto_qmail.o \ +str.a base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \ +dns.o timeoutconn.o ndelay.a ipalloc.o dns.lib socket.lib qldap-ldaplib.o \ +timeoutread.o qldap-mdm.o wait.a prot.o qldap-errno.o output.o \ +constmap.o case.a + ./load auth_pop checkpassword.o check.o control.o qldap-ldaplib.o \ + qldap-debug.o output.o auto_qmail.o dns.o timeoutconn.o timeoutread.o \ + ip.o base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \ + ipalloc.o constmap.o case.a getln.a open.a env.a stralloc.a alloc.a \ + substdio.a str.a qldap-mdm.o wait.a qldap-errno.o error.a fs.a \ + ndelay.a prot.o $(LDAPLIBS) $(SHADOWLIBS) \ + `cat dns.lib` `cat socket.lib` + auto-ccld.sh: \ conf-cc conf-ld warn-auto.sh ( cat warn-auto.sh; \ @@ -136,6 +245,10 @@ compile auto_usera.c ./compile auto_usera.c +base64.o: \ +compile base64.c base64.h str.h + ./compile $(LDAPFLAGS) base64.c + binm1: \ binm1.sh conf-qmail cat binm1.sh \ @@ -280,9 +393,20 @@ ./compile cdbmss.c check: \ -it man +it man qldap ./instcheck +check.o: \ +compile check.c check.h str.h str_len.c + ./compile $(LDAPFLAGS) check.c + +checkpassword.o: \ +compile checkpassword.c qmail-ldap.h stralloc.h auth_mod.h qldap-ldaplib.h \ +qldap-errno.h readwrite.h error.h str.h open.h substdio.h getln.h select.h \ +digest_md4.h digest_md5.h digest_rmd160.h digest_sha1.h dns.h \ +ipalloc.h timeoutconn.h byte.h scan.h fmt.h alloc.h qldap-debug.h + ./compile $(LDAPFLAGS) $(SHADOWOPTS) $(LDAPINCLUDES) $(DEBUG) checkpassword.c + chkshsgr: \ load chkshsgr.o ./load chkshsgr @@ -386,6 +510,33 @@ compile datetime_un.c datetime.h ./compile datetime_un.c +digest: \ +load digest.o digest_md4.o digest_md5.o digest_rmd160.o \ +digest_sha1.o base64.o stralloc.a str.a alloc.a error.a + ./load digest digest_md4.o digest_md5.o digest_rmd160.o \ + digest_sha1.o base64.o stralloc.a str.a alloc.a error.a + +digest.o: \ +compile digest.c uint32.h + ./compile $(LDAPFLAGS) digest.c + +digest_md4.o: \ +compile endian digest_md4.c digest_md4.h uint32.h base64.h byte.h + ./compile $(LDAPFLAGS) `./endian` digest_md4.c + +digest_md5.o: \ +compile endian digest_md5.c digest_md5.h uint32.h base64.h byte.h \ +stralloc.h str.h + ./compile $(LDAPFLAGS) `./endian` digest_md5.c + +digest_rmd160.o: \ +compile endian digest_rmd160.c digest_rmd160.h uint32.h base64.h byte.h + ./compile $(LDAPFLAGS) `./endian` digest_rmd160.c + +digest_sha1.o: \ +compile endian digest_sha1.c digest_sha1.h uint32.h base64.h byte.h + ./compile $(LDAPFLAGS) `./endian` digest_sha1.c + direntry.h: \ compile trydrent.c direntry.h1 direntry.h2 ( ./compile trydrent.c >/dev/null 2>&1 \ @@ -404,7 +555,7 @@ dns.o: \ compile dns.c ip.h ipalloc.h ip.h gen_alloc.h fmt.h alloc.h str.h \ stralloc.h gen_alloc.h dns.h case.h - ./compile dns.c + ./compile ${TLSON} dns.c dnscname: \ load dnscname.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ @@ -432,7 +583,7 @@ dnsfq.o: \ compile dnsfq.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \ dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h exit.h - ./compile dnsfq.c + ./compile ${TLSON} dnsfq.c dnsip: \ load dnsip.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ @@ -444,7 +595,7 @@ dnsip.o: \ compile dnsip.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \ dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h exit.h - ./compile dnsip.c + ./compile ${TLSON} dnsip.c dnsmxip: \ load dnsmxip.o dns.o dnsdoe.o ip.o ipalloc.o now.o stralloc.a alloc.a \ @@ -457,7 +608,7 @@ compile dnsmxip.c substdio.h subfd.h substdio.h stralloc.h \ gen_alloc.h fmt.h dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h \ now.h datetime.h exit.h - ./compile dnsmxip.c + ./compile ${TLSON} dnsmxip.c dnsptr: \ load dnsptr.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ @@ -492,6 +643,14 @@ > elq chmod 755 elq +endian: \ +load endian.o + ./load endian + +endian.o: \ +compile endian.c + ./compile $(LDAPFLAGS) endian.c + env.a: \ makelib env.o envread.o ./makelib env.a env.o envread.o @@ -703,7 +862,7 @@ hier.o: \ compile hier.c auto_qmail.h auto_split.h auto_uids.h fmt.h fifo.h - ./compile hier.c + ./compile $(LDAPFLAGS) $(DEBUG) hier.c home: \ home.sh conf-qmail @@ -755,7 +914,7 @@ install-big.o: \ compile install-big.c auto_qmail.h auto_split.h auto_uids.h fmt.h \ fifo.h - ./compile install-big.c + ./compile $(LDAPFLAGS) $(DEBUG) install-big.c install.o: \ compile install.c substdio.h strerr.h error.h open.h readwrite.h \ @@ -779,12 +938,12 @@ ipalloc.o: \ compile ipalloc.c alloc.h gen_allocdefs.h ip.h ipalloc.h ip.h \ gen_alloc.h - ./compile ipalloc.c + ./compile ${TLSON} ipalloc.c ipme.o: \ compile ipme.c hassalen.h byte.h ip.h ipalloc.h ip.h gen_alloc.h \ stralloc.h gen_alloc.h ipme.h ip.h ipalloc.h - ./compile ipme.c + ./compile ${TLSON} ipme.c ipmeprint: \ load ipmeprint.o ipme.o ip.o ipalloc.o stralloc.a alloc.a substdio.a \ @@ -795,7 +954,7 @@ ipmeprint.o: \ compile ipmeprint.c subfd.h substdio.h substdio.h ip.h ipme.h ip.h \ ipalloc.h ip.h gen_alloc.h exit.h - ./compile ipmeprint.c + ./compile ${TLSON} ipmeprint.c it: \ qmail-local qmail-lspawn qmail-getpw qmail-remote qmail-rspawn \ @@ -806,9 +965,9 @@ qmail-smtpd sendmail tcp-env qmail-newmrh config config-fast dnscname \ dnsptr dnsip dnsmxip dnsfq hostname ipmeprint qreceipt qsmhook qbiff \ forward preline condredirect bouncesaying except maildirmake \ -maildir2mbox maildirwatch qail elq pinq idedit install-big install \ -instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \ -binm3 binm3+df +maildir2mbox maildirwatch qail elq pinq idedit install-big \ +install instcheck home home+df proc proc+df binm1 \ +binm1+df binm2 binm2+df binm3 binm3+df load: \ make-load warn-auto.sh systype @@ -841,6 +1000,12 @@ strerr.h ./compile maildir.c +maildir++.o: \ +compile maildir++.c maildir++.h readwrite.h stralloc.h error.h str.h \ +open.h substdio.h getln.h error.h strerr.h fmt.h scan.h now.h seek.h \ +sig.h direntry.h + ./compile maildir++.c + maildir2mbox: \ load maildir2mbox.o maildir.o prioq.o now.o myctime.o gfrom.o lock.a \ getln.a env.a open.a strerr.a stralloc.a alloc.a substdio.a error.a \ @@ -992,6 +1157,11 @@ compile open_write.c open.h ./compile open_write.c +output.o: \ +compile output.c output.h stralloc.h substdio.h fmt.h str.h scan.h \ +readwrite.h + ./compile output.c + pinq: \ warn-auto.sh pinq.sh conf-qmail conf-break conf-split cat warn-auto.sh pinq.sh \ @@ -1074,6 +1244,30 @@ substdio.h open.h byte.h str.h headerbody.h hfield.h env.h exit.h ./compile qbiff.c +qldap-debug.o: \ +compile qldap-debug.c output.h stralloc.h substdio.h fmt.h str.h readwrite.h \ +error.h qldap-errno.h env.h scan.h qldap-debug.h + ./compile $(LDAPFLAGS) $(DEBUG) qldap-debug.c + +qldap-errno.o: \ +compile qldap-errno.c qldap-errno.h error.h + ./compile $(LDAPFLAGS) qldap-errno.c + +qldap-ldaplib.o: \ +compile qmail-ldap.h qldap-errno.h qldap-ldaplib.h alloc.h stralloc.h \ +error.h control.h auto_qmail.h str.h qldap-ldaplib.c byte.h fmt.h qldap-debug.h + ./compile $(LDAPFLAGS) $(LDAPINCLUDES) $(DEBUG) qldap-ldaplib.c + +qldap-mdm.o: \ +compile qldap-mdm.c qldap-errno.h wait.h + ./compile $(LDAPFLAGS) $(HDIRMAKE) $(MDIRMAKE) $(DEBUG) qldap-mdm.c + +profile: qldap-profile.o + +qldap-profile.o: \ +compile qldap-profile.c qldap-profile.h qldap-debug.h + ./compile ${INCTAI} $(DEBUG) qldap-profile.c + qmail-clean: \ load qmail-clean.o fmtqfn.o now.o getln.a sig.a stralloc.a alloc.a \ substdio.a error.a str.a fs.a auto_qmail.o auto_split.o @@ -1171,15 +1365,16 @@ > qmail-limits.7 qmail-local: \ -load qmail-local.o qmail.o quote.o now.o gfrom.o myctime.o \ +load qmail-local.o qmail.o quote.o now.o gfrom.o myctime.o qldap-mdm.o \ slurpclose.o case.a getln.a getopt.a sig.a open.a seek.a lock.a fd.a \ wait.a env.a stralloc.a alloc.a strerr.a substdio.a error.a str.a \ -fs.a datetime.a auto_qmail.o auto_patrn.o socket.lib - ./load qmail-local qmail.o quote.o now.o gfrom.o myctime.o \ - slurpclose.o case.a getln.a getopt.a sig.a open.a seek.a \ - lock.a fd.a wait.a env.a stralloc.a alloc.a strerr.a \ - substdio.a error.a str.a fs.a datetime.a auto_qmail.o \ - auto_patrn.o `cat socket.lib` +fs.a datetime.a auto_qmail.o auto_patrn.o control.o socket.lib \ +maildir++.o qldap-errno.o + ./load qmail-local qmail.o quote.o maildir++.o now.o gfrom.o myctime.o \ + qldap-mdm.o slurpclose.o case.a getln.a getopt.a sig.a open.a seek.a \ + lock.a fd.a wait.a env.a stralloc.a alloc.a strerr.a substdio.a \ + qldap-errno.o error.a str.a fs.a datetime.a auto_qmail.o \ + auto_patrn.o `cat socket.lib` qmail-local.0: \ qmail-local.8 @@ -1188,23 +1383,46 @@ qmail-local.o: \ compile qmail-local.c readwrite.h sig.h env.h byte.h exit.h fork.h \ open.h wait.h lock.h seek.h substdio.h getln.h strerr.h subfd.h \ -substdio.h sgetopt.h subgetopt.h alloc.h error.h stralloc.h \ -gen_alloc.h fmt.h str.h now.h datetime.h case.h quote.h qmail.h \ -substdio.h slurpclose.h myctime.h gfrom.h auto_patrn.h - ./compile qmail-local.c +substdio.h sgetopt.h subgetopt.h alloc.h error.h stralloc.h case.h \ +gen_alloc.h fmt.h str.h now.h datetime.h qmail-ldap.h quote.h qmail.h \ +substdio.h slurpclose.h myctime.h gfrom.h auto_patrn.h auto_qmail.h \ +qldap-errno.h qldap-mdm.h + ./compile $(LDAPFLAGS) $(MDIRMAKE) $(HDIRMAKE) qmail-local.c qmail-log.0: \ qmail-log.5 nroff -man qmail-log.5 > qmail-log.0 +qmail-ldaplookup: \ +load qmail-ldaplookup.o stralloc.a error.a qldap-ldaplib.o qldap-debug.o \ +qldap-errno.o str.a alloc.a check.o control.o env.a fs.a open.a \ +base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \ +auto_qmail.o getln.a substdio.a strerr.a output.o getopt.a auto_break.o \ +constmap.o case.a + ./load qmail-ldaplookup qldap-ldaplib.o control.o error.a \ + getln.a stralloc.a qldap-debug.o output.o qldap-errno.o check.o fs.a \ + base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \ + open.a env.a getopt.a strerr.a constmap.o substdio.a str.a alloc.a \ + case.a auto_qmail.o auto_break.o $(LDAPLIBS) $(SHADOWLIBS) + +qmail-ldaplookup.o: \ +compile qmail-ldaplookup.c qmail-ldap.h qldap-errno.h stralloc.h \ +alloc.h error.h str.h qldap-debug.h qldap-ldaplib.h check.h substdio.h \ +fmt.h scan.h readwrite.h byte.h getln.h digest_md4.h auto_qmail.h \ +digest_md5.h digest_rmd160.h digest_sha1.h open.h uint32.h auto_break.h + ./compile $(LDAPFLAGS) $(SHADOWOPTS) $(DEBUG) qmail-ldaplookup.c + qmail-lspawn: \ -load qmail-lspawn.o spawn.o prot.o slurpclose.o coe.o sig.a wait.a \ -case.a cdb.a fd.a open.a stralloc.a alloc.a substdio.a error.a str.a \ -fs.a auto_qmail.o auto_uids.o auto_spawn.o - ./load qmail-lspawn spawn.o prot.o slurpclose.o coe.o \ - sig.a wait.a case.a cdb.a fd.a open.a stralloc.a alloc.a \ - substdio.a error.a str.a fs.a auto_qmail.o auto_uids.o \ - auto_spawn.o +load qmail-lspawn.o spawn.o prot.o slurpclose.o coe.o control.o check.o \ +sig.a strerr.a getln.a wait.a case.a cdb.a fd.a open.a stralloc.a \ +alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_uids.o \ +auto_spawn.o auto_usera.o env.a qldap-ldaplib.o qldap-debug.o \ +qldap-errno.o seek.a output.o auto_break.o constmap.o + ./load qmail-lspawn spawn.o prot.o slurpclose.o coe.o control.o \ + check.o qldap-ldaplib.o qldap-debug.o output.o sig.a strerr.a constmap.o \ + getln.a wait.a case.a cdb.a fd.a seek.a open.a env.a stralloc.a alloc.a \ + substdio.a str.a qldap-errno.o error.a fs.a auto_qmail.o \ + auto_uids.o auto_usera.o auto_spawn.o auto_break.o $(LDAPLIBS) qmail-lspawn.0: \ qmail-lspawn.8 @@ -1213,8 +1431,10 @@ qmail-lspawn.o: \ compile qmail-lspawn.c fd.h wait.h prot.h substdio.h stralloc.h \ gen_alloc.h scan.h exit.h fork.h error.h cdb.h uint32.h case.h \ -slurpclose.h auto_qmail.h auto_uids.h qlx.h - ./compile qmail-lspawn.c +slurpclose.h auto_qmail.h auto_uids.h qlx.h qmail-ldap.h check.h \ +qldap-ldaplib.h qldap-errno.h qldap-debug.h env.h auto_usera.h \ +auto_uids.h fmt.h sig.h seek.h auto_break.h + ./compile $(LDAPFLAGS) $(HDIRMAKE) $(LDAPINCLUDES) $(DEBUG) qmail-lspawn.c qmail-newmrh: \ load qmail-newmrh.o cdbmss.o getln.a open.a cdbmake.a seek.a case.a \ @@ -1268,12 +1488,13 @@ qmail-pop3d: \ load qmail-pop3d.o commands.o case.a timeoutread.o timeoutwrite.o \ -maildir.o prioq.o now.o env.a strerr.a sig.a open.a getln.a \ -stralloc.a alloc.a substdio.a error.a str.a fs.a socket.lib - ./load qmail-pop3d commands.o case.a timeoutread.o \ +maildir.o prioq.o now.o env.a strerr.a sig.a open.a getln.a str.a \ +stralloc.a alloc.a substdio.a error.a fs.a socket.lib maildir++.o \ +seek.a + ./load qmail-pop3d commands.o maildir++.o case.a timeoutread.o \ timeoutwrite.o maildir.o prioq.o now.o env.a strerr.a sig.a \ open.a getln.a stralloc.a alloc.a substdio.a error.a str.a \ - fs.a `cat socket.lib` + fs.a seek.a `cat socket.lib` qmail-pop3d.0: \ qmail-pop3d.8 @@ -1283,8 +1504,8 @@ compile qmail-pop3d.c commands.h sig.h getln.h stralloc.h gen_alloc.h \ substdio.h alloc.h open.h prioq.h datetime.h gen_alloc.h scan.h fmt.h \ str.h exit.h maildir.h strerr.h readwrite.h timeoutread.h \ -timeoutwrite.h - ./compile qmail-pop3d.c +timeoutwrite.h maildir++.h + ./compile $(LDAPFLAGS) $(MNW) $(MDIRMAKE) qmail-pop3d.c qmail-popup: \ load qmail-popup.o commands.o timeoutread.o timeoutwrite.o now.o \ @@ -1302,7 +1523,7 @@ compile qmail-popup.c commands.h fd.h sig.h stralloc.h gen_alloc.h \ substdio.h alloc.h wait.h str.h byte.h now.h datetime.h fmt.h exit.h \ readwrite.h timeoutread.h timeoutwrite.h - ./compile qmail-popup.c + ./compile $(DEBUG) qmail-popup.c qmail-pw2u: \ load qmail-pw2u.o constmap.o control.o open.a getln.a case.a getopt.a \ @@ -1338,7 +1559,7 @@ ./load qmail-qmqpc slurpclose.o timeoutread.o \ timeoutwrite.o timeoutconn.o ip.o control.o auto_qmail.o \ sig.a ndelay.a open.a getln.a substdio.a stralloc.a alloc.a \ - error.a str.a fs.a `cat socket.lib` + error.a fs.a dns.o str.a ipalloc.o `cat dns.lib` `cat socket.lib` qmail-qmqpc.0: \ qmail-qmqpc.8 @@ -1348,7 +1569,7 @@ compile qmail-qmqpc.c substdio.h getln.h readwrite.h exit.h \ stralloc.h gen_alloc.h slurpclose.h error.h sig.h ip.h timeoutconn.h \ timeoutread.h timeoutwrite.h auto_qmail.h control.h fmt.h - ./compile qmail-qmqpc.c + ./compile $(LDAPFLAGS) qmail-qmqpc.c qmail-qmqpd: \ load qmail-qmqpd.o received.o now.o date822fmt.o qmail.o auto_qmail.o \ @@ -1437,6 +1658,21 @@ auto_qmail.h auto_uids.h date822fmt.h fmtqfn.h ./compile qmail-queue.c +qmail-quotawarn: \ +load qmail-quotawarn.o newfield.o now.o date822fmt.o case.a fd.a wait.a \ +open.a myctime.o case.a getln.a sig.a open.a seek.a lock.a datetime.a \ +env.a stralloc.a alloc.a strerr.a substdio.a error.a str.a fs.a + ./load qmail-quotawarn newfield.o now.o date822fmt.o case.a \ + fd.a wait.a open.a myctime.o case.a getln.a sig.a open.a seek.a \ + lock.a datetime.a env.a stralloc.a alloc.a strerr.a substdio.a \ + error.a str.a fs.a + +qmail-quotawarn.o: \ +compile qmail-quotawarn.c readwrite.h sig.h byte.h case.h datetime.h \ +env.h error.h exit.h newfield.h open.h seek.h str.h strerr.h stralloc.h \ +substdio.h wait.h qmail-ldap.h + ./compile qmail-quotawarn.c + qmail-remote: \ load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \ timeoutconn.o tcpto.o now.o dns.o ip.o ipalloc.o ipme.o quote.o \ @@ -1446,7 +1682,7 @@ timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \ ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \ lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \ - str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib` + str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib` ${TLSLIBS} qmail-remote.0: \ qmail-remote.8 @@ -1458,7 +1694,20 @@ alloc.h quote.h ip.h ipalloc.h ip.h gen_alloc.h ipme.h ip.h ipalloc.h \ gen_alloc.h gen_allocdefs.h str.h now.h datetime.h exit.h constmap.h \ tcpto.h readwrite.h timeoutconn.h timeoutread.h timeoutwrite.h - ./compile qmail-remote.c + ./compile ${TLSON} ${TLSINCLUDES} qmail-remote.c + +qmail-reply: \ +load qmail-reply.o case.a getln.a sig.a open.a seek.a env.a fd.a \ +wait.a stralloc.a alloc.a strerr.a substdio.a error.a str.a auto_qmail.o + ./load qmail-reply case.a getln.a sig.a open.a seek.a env.a \ + fd.a wait.a stralloc.a alloc.a strerr.a substdio.a error.a \ + str.a auto_qmail.o + +qmail-reply.o: \ +compile qmail-reply.c case.h env.h error.h exit.h getln.h qlx.h \ +readwrite.h seek.h sig.h str.h strerr.h stralloc.h substdio.h \ +wait.h auto_qmail.h qmail-ldap.h + ./compile $(LDAPFLAGS) qmail-reply.c qmail-rspawn: \ load qmail-rspawn.o spawn.o tcpto_clean.o now.o coe.o sig.a open.a \ @@ -1509,7 +1758,7 @@ scan.h case.h auto_qmail.h trigger.h newfield.h stralloc.h quote.h \ qmail.h substdio.h qsutil.h prioq.h datetime.h gen_alloc.h constmap.h \ fmtqfn.h readsubdir.h direntry.h - ./compile qmail-send.c + ./compile $(LDAPFLAGS) qmail-send.c qmail-showctl: \ load qmail-showctl.o auto_uids.o control.o open.a getln.a stralloc.a \ @@ -1536,13 +1785,13 @@ timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \ date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \ open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \ -fs.a auto_qmail.o socket.lib +fs.a auto_qmail.o dns.lib socket.lib ./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \ timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \ received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \ datetime.a getln.a open.a sig.a case.a env.a stralloc.a \ - alloc.a substdio.a error.a str.a fs.a auto_qmail.o `cat \ - socket.lib` + alloc.a substdio.a error.a fs.a auto_qmail.o dns.o str.a \ + `cat dns.lib` `cat socket.lib` ${TLSLIBS} qmail-smtpd.0: \ qmail-smtpd.8 @@ -1554,7 +1803,7 @@ error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h \ substdio.h str.h fmt.h scan.h byte.h case.h env.h now.h datetime.h \ exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h - ./compile qmail-smtpd.c + ./compile ${TLSON} ${TLSINCLUDES} qmail-smtpd.c qmail-start: \ load qmail-start.o prot.o fd.a auto_uids.o @@ -1743,7 +1992,7 @@ ./compile sendmail.c setup: \ -it man +it man qldap ./install sgetopt.o: \ @@ -1895,7 +2144,7 @@ stralloc.h gen_alloc.h select.h exit.h coe.h open.h error.h \ auto_qmail.h auto_uids.h auto_spawn.h ./chkspawn - ./compile spawn.c + ./compile $(DEBUG) spawn.c splogger: \ load splogger.o substdio.a error.a str.a fs.a syslog.lib socket.lib @@ -2139,3 +2388,24 @@ wait_pid.o: \ compile wait_pid.c error.h haswaitp.h ./compile wait_pid.c + +cert: + ${OPENSSLBIN} req -new -x509 -nodes \ + -out `head -1 conf-qmail`/control/cert.pem -days 366 \ + -keyout `head -1 conf-qmail`/control/cert.pem + chmod 640 `head -1 conf-qmail`/control/cert.pem + chown qmaild:qmail `head -1 conf-qmail`/control/cert.pem + +cert-req: + ${OPENSSLBIN} req -new -nodes \ + -out req.pem \ + -keyout `head -1 conf-qmail`/control/cert.pem + chmod 640 `head -1 conf-qmail`/control/cert.pem + chown qmaild:qmail `head -1 conf-qmail`/control/cert.pem + @echo + @echo "Send req.pem to your CA to obtain signed_req.pem, and do:" + @echo "cat signed_req.pem >> `head -1 conf-qmail`/control/cert.pem" + +backup: \ +clean + tar cf $(BACKUPPATH) . diff -uN qmail-1.03/QLDAPINSTALL qmail-ldap/QLDAPINSTALL --- qmail-1.03/QLDAPINSTALL Thu Jan 1 01:00:00 1970 +++ qmail-ldap/QLDAPINSTALL Sun Sep 30 14:58:57 2001 @@ -0,0 +1,789 @@ +QMAIL_LDAP by Andre Oppermann , +Claudio Jeker and Boris Lutz +(c) 1998,1999,2000,2001 Internet Business Solutions Ltd. + +This LDAP patches for qmail come with NO WARRANTY. + +These patches are under the BSD license. + +RELEASE: current ($Date: 2001/09/29 21:48:32 $) + +TOC: + INSTALL how to install the patch + CONFIG FILES all about the extra config file + DEFAULT LDAP FIELDS all about the fields in ldap + EXAMPLES example ldif and slapd.conf + MAILINGLIST, BUGS & PROBLEMS How to help us helping you + +TODO: + + see QLDAPTODO + +NEWS: + + see QLDAPNEWS + +IMPORTANT NEWS: + + new commandline options for qmail-ldaplookup + + variation of Henning Brauer's dash_ext patch. See Section 5.3 and + have a look at the QLDAPNEWS. + + new logging facilities for qmail-lspawn and auth_* + + new control file ldapclusterhosts. See Section CONFIG FILES. + +================================================================================ + +INSTALL: + +1. Make sure you have fairly good knowledge of qmail and LDAP + READ THEIR FAQs. PLEASE. + +2. Read this document. THIS IS IMPORTANT, this is no + ./configure; make; make install software. + +3. You need the following compiled and installed + - OpenLDAP 1.2.x/2.x or higher (others might also work) + or + - Netscape LDAP sdk (tested libldapssl30 on Solaris 2.6) + and + - OpenSSL 0.9.4 or higher if you want TLS SMTP encrytion + + If you have problems with OpenLDAP look into their FAQ. The same for + Netscape and OpenSSL. + You NEED knowledge of LDAP so READ their FAQ and/or man pages. + +4. Apply the qmail-ldap patches to a clean qmail-1.03 source tree + normaly "cd qmail-1.03_source_tree; patch -p1 < location_of_patch" + works ;-). There seems to be a problem with the original patch utility + on Solaris based systems, use the gnu patch utility instead. + A pre-compiled binary should be available at http://www.sunfreeware.com/ + or on many mirrors around the world. + +5. Edit the conf-* files and the top of the Makefile (only the top ;-) ) + You can set/change: + - LDAPFLAGS=-DQLDAP_CLUSTER (turns the cluster support on) + + -DLDAP_ESCAPE_BUG (see NOTE) + + -DCLEARTEXTPASSWD (for cleartext passwords in ldap, bad idea) + -DDASH_EXT (turn on dash_ext support see 5.3) + NOTE: at the moment -DLDAP_ESCAPE_BUG is not defined, this should be + added if your ldap server has problems with the escapeing of + LDAP filters (fixed as of OpenLDAP 1.2.8 and higher) + + - LDAPLIBS: the libraries you need for ldap, e.g. -lldap -llber + NOTE: on Solaris Systems you probably need also -lnsl -lsocket + newer OpenLDAP libs my need also -lresolv (DNS support). + It is also good to set the ld runpath with the -R switch + for more info ld(1) or gcc(1). + - LDAPINCLUDES: perhaps you need a special include-path for ldap + + - MNW=-DMAKE_NETSCAPE_WORK (turns on the patch that fixes the problem + with the Netscape download progress bar and qmail-pop3d) + + - MDIRMAKE=-DAUTOMAILDIRMAKE (turns the auto-MAILdir-make-patch on) + - HDIRMAKE=-DAUTOHOMEDIRMAKE (compiles the auto-HOMEdir-make-patch + into the release, you need the ~control/dirmaker file to turn the + patch on, see CONFIG FILES) + + - SHADOWLIBS=-lcrypt is needed on most systems (except my OpenBSD box :-) ) + SHADOWLIBS=-lcrypt -lshadow , SHADOWOPTS=-DPW_SHADOW are needed on some + Systems (Solaris, Linux) for local password lookups + (just like the original djb-checkpassword) + - DEBUG=-DDEBUG (compiles debugging into the auth modules and qmail-ldap, + see also 10.) + - TLS* stuff for TLS (SMTP encryption) mostly self explaining + +5.1 Have a look at qmail-ldap.h, perhaps you want to change something there. + LDAP_CATCH_ALL: used for catching mails for a specific domain. + Also used for extension nameing with DASH_EXT. + QUOTA_WARNING_LEVEL: triger level for quotawarning in percent. + *ID_{MAX,MIN}: upper and lower limit for uid's and gid's. + RESTRICT_PROG: restrict delivery programm pathes to non special shell + characters. See also next section 5.2 + ALIASDEVNULL: replacement for the std. aliasempty for user with + neither homeDirectory nor mailMessageStore defined. + QLDAP_TIMEOUT: Default ldap search timeout. In seconds. + LDAP_*: Names of the ldap fields used for lookups. + DOTMODE_*: Names for the different dot modes. + MODE_*: Names for the different delivery modes. + ISACTIVE_*: Names for the account status. + +5.2 Have a look at check.c if you want to change the ldap field check behaviour + In the standart patch we check for this (in regexp form): + user: [a-zA-Z0-9@_.][a-zA-Z0-9@_.-]* (for the LDAP_UID field) + path: [a-zA-Z0-9@_./:=][a-zA-Z0-9@_.-/:=]* + (for LDAP_MAILSTORE and LDAP_HOMEDIR) + prog: [a-zA-Z0-9@_./:=\\\t\n "'+,][a-zA-Z0-9@_.-/:=\\\t\n "'+,]* + (for LDAP_PROGRAM with RESTRICT_PROG on) + NOTE: have a look at QLDAPNEWS for more info + +5.3 Note on DASH_EXT: + Finally we added a variation of Henning Brauer's dash-ext patch. The main + difference is the way it handels the extensions. + Example lookup scheme: + aaaa-bbbb-cccc@domain.tld + aaaa-bbbb-CATCHALL@domain.tld + aaaa-CATCHALL@domain.tld + CATCHALL@domain.tld + where CATCHALL is replaced with the value of LDAP_CATCH_ALL defined + in qmail-ldap.h. If CATCHALL is set to "default" instead of the standart + "catchall" it is allmost stock qmails behaviour. + +6. Compile and install the stuff (it's the same as in standard qmail + install -> HINT: read the INSTALL and the FAQ file!!! :) ). + Now everything should be installed with correct permissions. + +6.1 If using TLS you can use 'make cert' or 'make cert-req' to create TLS + certificates + +7. Create the LDAP user database and start the LDAP server + See qmail.schema for definition of all fields for OpenLDAP 2.x + +8. Create the proper ~control/ldap* files for qmail-ldap + At least ldapserver and ldapbasedn must exist (and also 'me') + +9. Test and Enjoy! + +10. Debugging: as said befor you can compile qmail-lspawn and the auth modules + with a flexible debugging facility (option DEBUG). + The debug output gets logged through splogger or your favorite logging tool + connected to stderr for tcpserver-pop/imap chain. + To turn on debugging you need only to define the LOGLEVEL environment + variable (e.g. with env, env LOGLEVEL=3 qmail-start ...) + There are these LOGLEVEL: + LOGLEVEL=1 -> Errors + LOGLEVEL=2 -> Warnings + LOGLEVEL=4 -> Info + LOGLEVEL=8 -> Info^2 + LOGLEVEL=16 -> Debug + LOGLEVEL=32 -> Debug^2 + LOGLEVEL=64 -> LDAP Debug + LOGLEVEL=128 -> LDAP Debug^2 + LOGLEVEL=256 -> PASSWD, this level is normaly off because it shows + critical data (unencrypted and crypted passwords). To + turn it on edit checkpassword.c and increase the level + for init_debug(). + + WARNING: on production machines don't use levels higher 3 or you will get + incredible huge logfiles. + NOTE: too high debuglevels are reduced to the maximum allowed debug level + if the level parameter in init_debug() is smaler. + The LOGLEVEL is compare with a bit mask, so that + LOGLEVEL=3 will report warnings and errors but LOGLEVEL=2 will + only report warnings. + With the new log support the environment variable is LOGLEVEL but + the old DEBUGLEVEL is still supported. + The new log support will no longer add the log output to bounce + messages. + +11. NOTE ABOUT POP/IMAP services + The stock qmail recomends that you use a program by the name 'checkpassword' + to do the authentication, like this: + + pop3 stream tcp nowait root \ + /var/qmail/bin/qmail-popup qmail-popup \ + YOURHOST /bin/checkpassword /var/qmail/bin/qmail-pop3d Maildir + + With the use of the LDAP patch, this have been slightly altered. We now use + a program by the name 'auth_pop' instead... Something like this (replacement + inetd.conf line): + + pop3 stream tcp nowait root \ + /var/qmail/bin/qmail-popup qmail-popup \ + YOURHOST /var/qmail/bin/auth_pop /var/qmail/bin/qmail-pop3d Maildir + + + Same goes for the command 'auth_imap' if your IMAP server can use an + external program for authentication. auth_imap was designed for + courier-IMAP and should work with it out of the box. + There is also a auth_ldap modul in courier-imap that should work too. + You can get courier-imap from http://www.inter7.com + + auth_pop and auth_imap are part of this patch and will be installed with the + other qmail programs. + +================================================================================ + +CONFIG FILES: + +~control/ldapserver + + Space separated list of Hostnames or IP addresses of LDAP servers. + An additional port can be supplied with the host:port notation. + Required + Example: ldap.nrg4u.com ldap2.nrg4u.com ldap3.nrg4u.com:1234 + +~control/ldapbasedn + + The base DN from where the search in the LDAP tree begins + Normaly required + Default: NULL + Example: o=Internet Pipeline, c=CH + Note: Referrals are ignored + +~control/ldapobjectclass + + The ldap objectclass the search will be limited to + Default: NULL, will search all objectclasses + Example: qmailUser + Note: Can specify more than one, must then be written in ldap search syntax + +~control/ldaplogin + + Username for the LDAP server connection + Default: NULL + Example: cn=qmail-ldap, o=Internet Pipeline, c=CH + Note: The user must have enough rights to lookup all user information + +~control/ldappassword + + Password for the LDAP server connection + Default: NULL + Note: The password is in clear text. The file should be owned by root and + mode (600) rw-------. + +~control/ldaplocaldelivery + + To lookup the local passwd file if the LDAP lookup finds no match. This + affects qmail-lspawn and auth_* if the LDAP lookup returns nothing. + Default: enabled + Example: 1 + Note: boolean, use 0 (zero) or 1 (one) + +~control/ldaprebind + + Use the possibility of rebinding to the ldap-server to compare pop3 + and imap passwords. So you can make your acl more restrictive. + Default: disabled + Example: 1 + Note: boolean, use 0 (zero) or 1 (one) + +~control/ldapcluster + + Turn clustering on and off. Needs a qmail-ldap compiled with + -DQLDAP_CLUSTER or nothing will happen. Also don't forget to set up + qmail-qmqpd on all servers in the cluster. + Default: disabled + Example: 1 + Note: boolean, use 0 (zero) or 1 (one) + ATTN: the control files me, rcpthosts and locals have to be set carfully + or you will have big problems. + +~control/ldapclusterhosts + + ldapclusterhosts contains a number of hostnames (FQDM) to check togehter + with ~control/me when clustering is on. This file is useful if you want to + run multiple instances of qmail-ldap on one machine. + Default: none + Example: customersmtp.nrg4u.com + Note: multiline + +~control/ldapdefaultquota + + The default amount of disk space the user can use until all further messages + get bounced back to the sender. There are two possible limits, size (a byte + count 'S') and count (a file count 'C') + Default: unlimited + Example: 1000000S,1000C (max 1000000 bytes size and max 1000 Mails) + Note: is overridden by mailQuota, make sure to have set ~control/quotowarning + otherwise you will not get quota warning messages + +~control/ldapdefaultdotmode + + The default interpretation of .qmail files + Default: ldaponly + Example: both + Values: both, dotonly, ldaponly, ldapwithprog, none + Note: Works only for deliveries based on LDAP lookups. + Local mails use dotonly like in normal qmail. + +~control/ldapmessagestore + + The default prefix for path's in mailMessageStore without trailing / + Default: NULL + Example: /maildisk + Note: Used in virtual users environments + +~control/ldapuid + + The default UID used in virtual users environments. This value will be + used for ldap entries with no LDAP_QMAILUID (see below) field + Default: NULL + Example: 1010 + Note: should be a real UID, must be above 100 + +~control/ldapgid + + The default GID used in virtual users environments. This value will be + used for ldap entries with no LDAP_QMAILGID (see below) field + Default: NULL + Example: 1010 + Note: should be a real GID, must be above 100 + +~control/ldaptimeout + + The time the ldap search waits for a response from the ldap server + Default: 30 seconds + Example: 60 + Note: in seconds, if it gets no response within this time it will + continue either with the next specified ldap server or it will + defer the delivery and try again later. + +~control/custombouncetext + + Additional custom text in bounce messages, e.g. for providing contact + information of your ISP or messages in your language + Default: NULL + Example: You can contact us at (555) 555 5555 + Note: Multiline + +~control/quotawarning + + Custom text in quota warning message, e.g. for providing contact information + of your ISP + Default: NULL + Example: You can contact us at (555) 555 5555 + Note: Multiline. Needs to be present to make qmail-quotawarn work. + +~control/tarpitcount + + Tarpitcount is the number of RCPT TOs you accept before you start tarpitting + Default: 0 (which means no tarpitting) + Example: 5 + Note: You can override tarpitcount by setting TARPITCOUNT in qmail-smtpd's + environment (with tcpserver). + +~control/tarpitdelay + + Tarpitdelay is the number of seconds of delay to introduce after each + subsequent RCPT TO. + Default: 5 + Example: 10 + Note: You can override tarpitdelay by setting TARPITDELAY in qmail-smtpd's + environment (with tcpserver). + +~control/maxrcptcount + + Maxrcptcount is the maximum number of RCPT TOs you accept before permanently + rejecting this delivery attempt. + Default: 0 (which means no maxrcptcount) + Example: 5 + Note: You can override maxrcptcount by setting MAXRCPTCOUNT in qmail-smtpd's + environment (with tcpserver). + +~control/relaymailfrom + + This file contains envelope sender addresses that are allowed to relay through + this server. + Default: none + Example: user@domain or @domain + Note: Use with care, the envelope senders address can easily be spoofed and + then you are an open relay again. It is better to use a scheme like + POP before SMTP. + +~control/rbllist + + Rbllist contains a number of RBL's to check for the given senders IP address. + Default: none + Example: blackholes.mail-abuse.org + Example: dialups.mail-abuse.org + Example: relays.mail-abuse.org + Example: spamsources.orbs.org + Note: Multiline. To activate RBL checks you have to set RBL in qmail-smtpd's + environment (with tcpserver). + +~control/rblonlyheader + + Rblonlyheader causes qmail-smtpd not to reject the message but to add a + line with it's findings to the mail header. + Default: none + Example: 1 + Note: Add's a "X-RBL: IP[] is listed by RBL[]" header to the message for + later filtering. Can also be activated if you set RBLONLYHEADER in + qmail-smtpd's environment (with tcpserver). + +~control/badrcptto + + This file contains local recipient addresses that are rejected. + Default: none + Example: user@domain or @domain + Note: This can be useful if a spammer sends lots of messages to a + nonexistant user from an invalid address as otherwise postmaster + will get lots of double bounces. + +~control/dirmaker + + Absolute path to your program/script that creates missing homedirs + Default: none (off) + Example: /var/qmail/bin/create_homedir + Note: the script is executeded after the setuid/gid, it isn't running + under root for security reasons. + The command is executed with execve not system + (so mkdir --mode=700 -p does not work!) use a shell script. + $1 is the homedir-path and $2 is aliasempty. + Possible very simple shell script: + + -cut- + #!/bin/sh + mkdir -m 700 -p $1 + #EOF + -cut- + +~control/ldapusername + NO LONGER USED, PLEASE REMOVE THE FILE + +~control/ldappasswdappend + NO LONGER USED, PLEASE REMOVE THE FILE + Now the auth modules extract the Maildir out of the .qmail file, but only + on local (/etc/passwd) lookups. + +================================================================================ + +Environment variables with control files (see control file for description): + + TARPITCOUNT + TARPITDELAY + MAXRCPTCOUNT + RBL + RBLONLYHEADER + +Environment variables *without* control file: + +DENYMAIL + + Heavy sanity checking of the envelope sender address + Default: none + Affects: qmail-smtpd + Example: DNSCHECK + Note: The following variables are supported: + SPAM -> refuse all mail + NOBOUNCE -> refuse null mail from + DNSCHECK -> validate that envelope senders domain has an MX or A record + plus check for other invalid envelope sender constructs + +LOGLEVEL + + Level of log verbosity in qmail-smtpd + Default: none + Affects: qmail-smtpd + Example: 3 + Note: integer value from 0-3, everything will be logged through tcpserver + +LOGLEVEL or DEBUGLEVEL + + Level of log verbosity in qmail-lspawn, auth_* + Default: none (0) + LEVELS: + LOGLEVEL=1 -> Errors + LOGLEVEL=2 -> Warnings + LOGLEVEL=4 -> Info + LOGLEVEL=8 -> Info^2 + LOGLEVEL=16 -> Debug + LOGLEVEL=32 -> Debug^2 + LOGLEVEL=64 -> LDAP Debug + LOGLEVEL=128 -> LDAP Debug^2 + LOGLEVEL=256 -> PASSWD, this level is normaly off because it shows + critical data (unencrypted and crypted passwords). To + turn it on edit checkpassword.c and increase the level + for init_debug(). + WARNING: on production machines don't use levels higher 3 or you will get + incredible huge logfiles. + NOTE: too high debuglevels are reduced to the maximum allowed debug level + if the level parameter in init_debug() is smaler. + The LOGLEVEL is compare with a bit mask, so that + LOGLEVEL=3 will report warnings and errors but LOGLEVEL=2 will + only report warnings. + Both names are supported with LOGLEVEL having the higher priority. + +================================================================================ + +DEFAULT LDAP PARAMETER FIELDS: +NOTE: keywords have to match exactly, so pay attention. + All fieldnames and keywords can be changed at compile time. + Just have a look at qmail-ldap.h. + +LDAP_MAIL (default: "mail") + + The users email address + Required + Example: jdoe@foo.bar + + +LDAP_MAILALTERNATE (default: "mailAlternateAddress") + + Secondary (alias) mailaddresses for the same user + Example: jd@foo.bar + Note: multifield + + +LDAP_UID (default: "uid") + + The username for POP3 and IMAP delivery + Required + Example: jdoe + Note: this name will also be set as $USER for qmail-local and program delivery. + + +LDAP_QMAILUID (default: "qmailUID") + + UID of the user on the mailsystem + Example: 1010 + Note: Can be omitted in a virtual users environment + but only if it is defined via the control file ~control/ldapuid + +LDAP_QMAILGID (default: "qmailGID") + + GID of the user on the mailsystem + Example: 1010 + Note: Can be omitted in a virtual users environment + but only if it is defined via the control file ~control/ldapgid + + +LDAP_PASSWD (default: "userPassword") + + The password for POP3/IMAP authentication + Example: {MD5}uSI59Zyfa5lapBLGfJrD+g== + Note: Can be encrypted with {SHA}, {MD4}, {MD5}, {RMD160}, {NS-MTA-MD5}, + {crypt} crypt (without {crypt} prefix) or cleartext (only if compiled + with -DCLEARTEXTPASSWD (a bad idea on production systems)). + If you rebind to the ldapserver don't use {NS-MTA-MD5}, {RMD160} and + probably {MD4}. These algorithms are sometimes not supported by the + ldap servers, so check with their documentation. + To generate passwords you can use the included tool 'digest'. + + +LDAP_MAILSTORE (default: "mailMessageStore") +and +LDAP_HOMEDIR (default: "homeDirectory") + + Path to the maildir/mbox on the mail system is extracted from those fields. + If LDAP_HOMEDIR is found this field is used as $HOME, using aliasempty or + mailMessagestore if defined as default delivery method. + If only LDAP_MAILSTORE is defined this will be used as $HOME and aliasempty + as default delivery method. + If neither LDAP_MAILSTORE nor LDAP_HOMEDIR is defined, ~alias (qmails alias + user homedir) will be used as $HOME and ALIASDEVNULL (defined in qmail-ldap.h) + as default delivery method. Also the delivery mode is set to ldap only and + forward only (LDAP_DOTMODE and LDAP_MODE). + Example: /home/jdoe/ + Note: LDAP_MAILSTORE can be written relative in a virtual users environment + ldapmailstore will be prefixed to make the path absolute. + For more info have a look at the QLDAPNEWS file. + If you use "homeDirectory" in an incompatible way then redefine it in + qldap-ldap.h to something not used, like "noHomeDirectory". + + +LDAP_QUOTA (default: "mailQuota") + + The amount of space the user can use until all further messages get bounced. + There are two possible limits, size (a byte count) and count (a file count). + The mailQuota is a string of the form figures type (S or C) and a ',' + separating multiple entries. + Example: 1000000S,1000C (max 1000000 bytes size and max 1000 Mails) + Note: overrides ldapdefaultquota, the old format (only a number representing + the amount of bytes allowed) is still supported + + +LDAP_FORWARDS (default: "mailForwardingAddress") + + Address(es) to forward all incoming messages for this user to. + Example: jdoe@new.place + Note: multifield + + +LDAP_PROGRAM (default: "deliveryProgramPath") + + Program to execute for all incoming mails. Gets the message as input on stdin. + Example: /usr/bin/program -c -s + Note: multifield. The same as |/usr/bin/program -c -s in .qmail + Works only with qmailDotMode set to ldapwithprog or both. + With ldaponly set deliveryProgramPath is silently ignored. + Before using it have a look at QLDAPNEWS, qmail-ldap.h, check.c and + see also 5.2. + + +LDAP_MODE (default: "deliveryMode") + + multi field entries of these keywords + - normal: resets to the normal .qmail behavior + (Maildir/box delivery only if no forwards or programs are executed) + - forwardonly: is equal to set the execute bit of .qmail + so only forwards are allowed + - nombox: ignore all maildir/mbox deliveries + - localdelivery: forces maildir/mbox delivery (into $HOME/$ALIASEMPTY) + - reply: send also an auto_reply mail with text from mailReplyText + - echo: something very strange, just echo the message (nothing else) + Default: no QMAILMODE is eq to QMAILMODE=normal other stuff is ignored (with + warning) + Note: echo exits immediatly after the "echoing" (only useful for testing + purposes). reply is executed directly and does not interfere with + the other settings. + "normal", "nombox", "localdelivery" and "forwardonly" are set one after + the other (i.e. "nombox,localdelivery,normal" resets to a "normal" + delivery). + There are some strange behavior when localdelivery and nombox or + forwardonly are set, so handle them with care. + + +LDAP_REPLYTEXT (default: "mailReplyText") + + A reply text for every incoming message (multiline) + Example: I'm on vacation until next monday + Example2: multiline base64 + SGkgcW1haWwtbGRhcCBmYW5zLAoKaWYgSSBjb3VsZCBJIHdvdWxkIGJlIGlu + IHRoZSBtb3VudGFpbnMgc2tpaW5nIGJ1dCBJJ20gYXQgaG9tZQp3cml0aW5n + IHRoaXMgbWVzc2FnZSBmb3IgdGhlIFFMREFQSU5TVEFMTCBmaWxlLgpUbyBi + ZSBob25lc3QsIHRoZXJlIGlzIG5vdCBlbm91Z2ggc25vdyBhcm91bmQgdG8g + ZW5qb3kgc2tpaW5nLgoKdGhhbmtzIGZvciByZWFkaW5nIHRoZSBRTERBUElO + U1RBTEwgZmlsZQoKLS0KOndxIENsYXVkaW8K + Note: used only if deliveryMode is set to reply. + To use multiline text in ldap it has to be base64 in ldif. + GUI tools like GQ are doing this correct, ldapadd can handle base64 + inputs or a path to a file containing the reply text (man ldapadd). + + +LDAP_DOTMODE (default: "qmailDotMode") + + The default interpretation of .qmail files + Values: both, dotonly, ldaponly, ldapwithprog, none (just Maildir/box delivery) + Default: set by file ~control/ldapdefaultdotmode + Note: Works only for deliveries based on LDAP lookups, + overrides ~control/ldapdefaultdotmode. + + +LDAP_MAILHOST (default: "mailHost") + + On which qmail server the messagestore of this user is located + Example: qmail3.nrg4u.com + Note: Must be the same as the ~control/me hostname on the homeserver + of the user. + + +LDAP_ISACTIVE (default: "accountStatus") + + The status of a user account. + Values: active (no restrictions), + nopop (only mail delivery but no pop access), + disabled (bounce incoming messages) + deleted (bounce incoming messages and mark for deletion, + see LDAP_PURGE) + Default: no accountStatus is equal to active. + + +LDAP_PURGE (default: "qmailAccountPurge") + + If accountStatus set to 'deleted', the earliest date when the mailMessageStore + including all remaining content will be deleted from the filesystem. + Values: date and time in seconds since Jan. 1, 1970 (the epoch) + Default: not set + Note: This deletion has to be done by an external helper program, for example + periodically run from cron. A sample script is included under the name + qmailAccountPurge.sh. Handle automatic deletions with care! + + +LDAP_QMAILUSER (default: "qmailUser") + NO LONGER USED, REMOVE IT SOMEWHEN FROM YOUR DATABASE + Replaced by LDAP_UID + +================================================================================ + +EXAMPLE QLDAP LDIF FILE: + +dn: cn=Andre Oppermann, o=Internet Pipeline, c=CH +cn: Andre Oppermann +sn: Oppermann +objectClass: top +objectClass: person +objectClass: inetOrgPerson +objectClass: qmailUser +mail: opi@opi.flirtbox.ch +mailHost: opi.flirtbox.ch +mailMessageStore: /usr/home/opi/Maildir/ +mailQuota: 1000000S,100C +qmailUID: 1001 +qmailGID: 1001 +uid: opi +userPassword: {MD5}b28a87511da157f147ed4766b0474a8a + +================================================================================ + +EXAMPLE SLAPD.CONF FILE: + +include /usr/local/etc/ldap/slapd.at.conf +include /usr/local/etc/ldap/slapd.oc.conf +schemacheck on +#referral ldap://ldap.itd.umich.edu + +####################################################################### +# ldbm database definitions +####################################################################### + +database ldbm +suffix "o=Internet Pipeline, c=CH" +directory /var/qmail/users +rootdn "cn=root, o=Internet Pipeline, c=CH" +rootpw secret +index objectclass,mail,mailAlternateAddress,uid +index default none + +================================================================================ + +ADD THIS SCHEMA TO SLAPD.OC.CONF (for OpenLDAP 1.2.x) + +objectclass qmailUser + requires + objectclass, + mail, + uid + allows + mailMessageStore, + homeDirectory, + userPassword, + mailAlternateAddress, + qmailUID, + qmailGID, + mailQuota, + mailHost, + mailForwardingAddress, + deliveryProgramPath, + qmailDotMode, + deliveryMode, + mailReplyText, + accountStatus, + qmailAccountPurge + + +FOR OpenLDAP 2.x DO THIS INSTEAD: + +Copy qmail.schema to your OpenLDAP installation location and add this +to your slapd.conf: + + include /path/to/your/OpenLDAP/qmail.schema + +================================================================================ + +MAILINGLIST, BUGS & PROBLEMS + +There is a qmail-ldap specific mailinglist at qmail-ldap@argus.pipeline.ch. +To subscribe just write a mail to qmail-ldap-subscribe@argus.pipeline.ch. + +The qmail-ldap mailinglist archive can be found at +http://www.suares.com/qmail-ldap/archive + +There is also a life with qmail-ldap homepage at: +http://www.lifewithqmail.org/ldap + +If you have a problem with the patch or there seems to be a bug in the code +please add some output of qmail-ldap with LOGLEVEL set to something higher +then 2 (255 is a good setting to see all possible problems). +It is impossible to know where the problem is when somebody writes a mail like: +I have a problem with the patch. No mail gets send to the user in the ldap db. + +Normaly you get also a better response if you specify your problem in detail. +It seems that often a "RTFM" is enough, but when you read until here you +are probably not such a candidate. + +END :-) + diff -uN qmail-1.03/QLDAPNEWS qmail-ldap/QLDAPNEWS --- qmail-1.03/QLDAPNEWS Thu Jan 1 01:00:00 1970 +++ qmail-ldap/QLDAPNEWS Sun Sep 30 14:58:57 2001 @@ -0,0 +1,422 @@ +QMAIL_LDAP by Andre Oppermann , +Claudio Jeker and Boris Lutz +(c) 1998,1999,2000,2001 Internet Business Solutions Ltd. + +This LDAP patches for qmail come with NO WARRANTY. + +These patches are under the BSD license. + +RELEASE: $Date: 2001/09/29 21:48:32 $ ($Revision: 1.44 $) + + +This is the NEWS FILE, so the QLDAPINSTALL file gets a bit cleaner. +This file is NOT structured!! + +TODO: + + see QLDAPTODO + +NEWS for current stuff: + + added a variation of Henning Brauer's alternate mailhost patch. + For more info: mailto: + + added a variation of Henning Brauer's dash-ext patch. The main + difference is the way it handels the extensions. + Example lookup scheme: + aaaa-bbbb-cccc@domain.tld + aaaa-bbbb-CATCHALL@domain.tld + aaaa-CATCHALL@domain.tld + CATCHALL@domain.tld + where CATCHALL is replaced with the value of LDAP_CATCH_ALL defined + in qmail-ldap.h. If CATCHALL is set to "default" instead of the standart + "catchall" it is allmost stock qmails behaviour. + The dash-ext stuff can be turned on with the -DDASH_EXT option in Makefile. + + some rewrite of qmail-ldaplookup. See qmail-ldaplookup -h. + + Makefile bug fixed, spawn.c was compiled without -DDEBUG. Not in 0802i. + + Changes in qldap-ldaplib.*: + added qldap_open to open the ldap connection + added qldap_close to close the ldap connection + renamed ldap_lookup to qldap_lookup + Now it is possible to use one ldap (TCP) connection for multiple queries, so + the connection overhead with DASH_EXT is drastically reduced. + + new debug/log handling. In qmail-lspawn the debug output is no + longer added to bounce mails. + + bug fix in the cleaned up NS-MTA code. + + bugfix in catchall search string generation. Hopefully the last one. + + bugfix in qmail-ldaplookup (ldap_value_free). Thanks to Sascha Gresk. + + better handling of deliverymode in qmail-lspawn.c + +NEWS for 20010501 stuff: + + bugfix in qmail-local.c by Mark Belnap. Problems with deliverymode reply. + + disallow null passwords in auth_pop and auth_imap. + + added RBLONLYHEADER logging control file and variable. With this it will + no longer reject a mail upon a RBL match but it will mark it with a "X-RBL:" + header. + + major cleanup in digest_* and base64 to make the code more djb style. + Minor cleanup in some other files. compatibility.h is no longer needed. YES! + + string fix in digest_md5.c (NS_MTA handling) + + bugfix in catchall search string generation. + + bugfixes in maildir++ support. Thanks to Franky Van Liedekerke. + + bugfixes in qmail-reply + + new attribute qmailAccountPurge for automatic purging of maildirs from + deleted accounts + +NEWS for 20010301 + + added 0.0.0.0 patch + + some fixes for misc. stuff from Chris Noe + - with DEBUGLEVEL set, the default ldapGID is printed incorrectly + - The line above says 'without trailing slash' but the example has one :) + - Permanet -> Permanent + - Programm -> Program + - fix qmail-lspawn 'Out of memory' error when attempting local delivery + to a nonexistant user. + + fix for qmail-reply.c from Jamie Blondin + - handle precedence flag in the right way + + fix for qmail.schema mailReplyText from David E. Storey + + fix for ldaptimeout to just defer message delivery instead of bouncing + sometimes + +NEWS for 20010201: + + fix for ldapobjectclass bugfix + + beautyfied qmail-reply.c. Now it should handel most messages in a correct + and nice way. + + bugfix for the new ldapobjectclass and ldaptimeout stuff + + bugfix in maildir++.c: algorithm has ignored all subdirs except .Trash + +NEWS for 20010101: + + introduced ~control/objectclass to limit the ldap search to a specific + ldap objectclass as suggested in some recommended procedures. + + bugfix in maildir++: + files with sizes containig 0 or 9 where claclculated wrong + if only one of C or S type where declared the quota of the other was ignored + + changed ALIASEMPTY in qmail-ldap.h from /dev/null to |sh -c "cat > /dev/null" + direct writing to /dev/null resulted in a soft error. This shell call does the + same without an error. + + introduced ~control/ldaptimeout to limit the time and ldap search might + take until the delivery attempt is being deferred and tried again later. + The default is 30 seconds. + + works fine with OpenLDAP 2.x (2.0.7). + + included the OpenLDAP 2.x LDAPv3 Schema definition file created by + David E. Storey. This version is based on the original work by David + but modified quite a lot by Andre. Also qmail-ldap has got it's own + offcially IANA assigned OID. + +NEWS for 20001201: + + cluster loop protection enhanced, now also the users mailaddress is added: + Delivered-To: CLUSTERHOST host.name.as.in.control.me users@e-mail.addr + + new maildir++ quota algorithm implemented. This one is simpler and should + therefor work much better. NOTE: The code was not tested under havy load. + + major enhancements in qmail-reply.c. Fixed a bug that could crash qmail-reply + if a bad mail was sent. The output of qmail-reply was also beautified. + + introduced MAXRCPTCOUNT to limit the maximum number of rcpt to's in one session. + + introduced RBL support to check the senders IP against a number of RBL's, see + ~control/rbllist. + + documented ~control/relaymailfrom to allow relaying based on the senders + mail address. + + documented LOGLEVEL and DENYMAIL environment variables to qmail-smtpd. + +NEWS for 20001013: + + possible fix for newer gcc. Problems with va_arg and unsigned chars. + I don't have such a new gcc, so I don't know if this fixes the problem. + + bug fix for the problem mentioned by Aleksander Dzierzanowski (mail to deleted + mailfiles bounce if there is a quota set). + + cluster loop protection added. Now it should be impossible that mail loop + forever if the cluster was badly configured. It works via the Delivered-To line + and uses something like this: + Delivered-To: CLUSTERHOST host.name.as.in.control.me + + fixed multiple problems with suns cc. + + fixed multiple problems and bugs in TLS support. + + fixed a bug introduced with the bitmask support for debug outputs. + + cleanup at different locations to respect the signedness of variables + + added bitmask support for debug outputs, so DEBUGLEVEL=3 will print error and + warnings but DEBUGLEVEL=2 only warnings. Note: init_debug's 2nd argument has + changed, it's now a binary mask that is binary anded with the debuglevel. + e.g. to disable PASSWD outputs use something like -1^256 as 2nd argument. + + added some defines for better testing: + use -DPORT_SMTP="alternate smtp port", -DPORT_LDAP="alternate ldap port" and + -DPORT_QMQP="alternate qmqp port" to change those ports. + +NEWS for 20000701 patch: + + if the LDAP server is down put the message back into the queue instead of + bouncing + + correct spelling errors in many files + + forcing forwardonly and ldaponly when neither LDAP_MAILSTORE nor LDAP_HOMEDIR + is defined + + bugfixes in hier.c and install-big.c to install qmail-ldaplookup with correct + 0700 permission, as told in the QLDAPINSTALL file + + bug fix in checkpassword.c and qmail-ldaplookup.c with wrong index to the + LDAP args array. Thanks to Ricardo Cerqueira + + small bug fix in qmail-ldaplookup, fixed a wrong output. + + added possible connection less LDAP support. Untested because slapd does not + support cladp until now. To turn it on use -DUSE_CLDAP as LDAPFLAGS + +NEWS for 20000601 patch: + + update of the QLDAP* files + + bug fix in maildir++.c and qmail-local.c, now quota_add should add the correct + size of the mail. Until now only the message without DTLINE and RPLINE was + sized + + bugfixes in "empty file list :)" + + +NEWS for 20000501 patch (and some also for 20000401): + + Add the new control files and their meaning to qmail-showctl + You can use qmail-showctl to check your setup. + + added new tool qmail-ldaplookup with this program you can check the ldap + db entries. Similar to the old checkpassword with debug support. + Usage: qmail-ldaplookup {-m mailaddress | -u userid [passwd]} + NOTE: because this tool could show critical data (like the hashed passwd) + it is installed with mode 000 (no rights for anybody) + You should only give root the permission to start it. + + new mailMessageStore/homeDirectory handling. + Because a lot of people requested it and because I was also unhappy with it + I have rewritten/enhanced the mailMessageStore handling. + Now the homedir and aliasempty are set via both + mailMessageStore (LDAP_MAILSTORE) and homeDirectory (LDAP_HOMEDIR). + It works like this: + IF LDAP_HOMEDIR exists it is used as $HOME (qmail-locals 3rd ARGV) + IF also LDAP_MAILSTORE exists LDAP_MAILSTORE is used as aliasempty + (last ARGV of qmail-local) + ELSE (no LDAP_MAILSTORE ) use the aliasempty specified + in /var/qmail/rc or similar + FI + ELSE IF LDAP_MAILSTORE exists but no LDAP_HOMEDIR exists + IF LDAP_MAILSTORE is absolute use LDAP_MAILSTORE as + $HOME and use standard aliasempty + ELSE (LDAP_MAILSTORE not absolute) use control/ldapmessagestore as + prefix to LDAP_MAILSTORE and use this as $HOME and use std. aliasempty + ELSE neither LDAP_MAILSTORE nor LDAP_HOMEDIR exists + use ~alias as $HOME and ALIASDEVNULL as aliasempty + FI + + NOTE: the case neither LDAP_MAILSTORE nor LDAP_HOMEDIR is a bit special + ~alias is installed as root.qmail mode 02755 (rwxr-sr-x) so no user + can write to this directory. ALIASDEVNULL is defined in qmail-ldap.h + normally /dev/null can be used (forward-only and ldaponly will be forced + in the next release) or a special alert tool can be used + ("|/var/qmail/bin/myalerttool") + NOTE2: if you use "homeDirectory" and "mailMessageStore" in an incompatible + way and you want the old behavior back define LDAP_HOMEDIR in + qmail-ldap.h as an nonexistent ldap db field like noHomeDirectory. + + new check algorithm, I think it's faster and better. + Have a look at check.c. At the end of the file there is a array with all + ASCII chars (7bit). You can allow or deny char by adding: + DENY_ALL: always deny this char + ALLOW_ALL: always allow this char + ALLOW_USER: allow this char for username checks (chck_user) + DENY_USER: deny this char for username checks (chck_user) + ALLOW_PATH: allow this char for path checks (chck_path) + DENY_PATH: deny this char for path checks (chck_path) + ALLOW_PROG: allow this char for program checks (chck_prog) + DENY_PROG: deny this char for program checks (chck_prog) + NOT_FIRST: deny this char at the beginning of a string + SPACE: alias to ALLOW_PROG + PARANOIA: deny most shell special chars like '|' or '*' for program checks + can be turned on or of in qmail-ldap.h + Example: + /* 7 \007 ^G */ DENY_ALL, /* deny control chars */ + /* 45 '-' */ ALLOW_ALL|NOT_FIRST, /* allowed but not first */ + /* 47 '/' */ ALLOW_ALL&DENY_USER, /* allowed only for path and prog */ + /* 58 ':' */ ALLOW_PROG|ALLOW_PATH, /* like before */ + + As you can see ALLOWs have to be ORed together whereas DENYs have to be ANDed + NOT_FIRST has to be ORed and PARANOIA has to be ANDed. + + getcwd and chdir no longer used in qldap-ldaplib.c init_ldap function. + + changed the connection forwarding under pop and imap. Now it should work + correctly, or at least better then before ;-) + + major cleanup in maildir++ support (mainly maildir++.c) + + bugfixes in qmail-lspawn.c, qmail-reply.c and checkpassword.c + + +NEWS for previous releases: + + Added new debug facility that is usable for the auth tools and qmail-lspawn. + The debug-level can now be changed at runtime and everything gets logged via + splogger or any other logger connected to stderr of the execution chain. + You can set the debug level easily with the DEUBUGLEVEL environment variable. + + Created a new auth tool for pop3 and imap. The old checkpassword is not + needed anymore. The new programs are auth_pop and auth_imap. + To have the possibility to compare cleartextpasswords (password how are + stored clear text in ldap) define CLEARTEXTPASSWORD. Because this setting + is a security disaster it is normally off. All other modes (hashed MD4, MD5, + SHA and the standard DES crypt) are not affected. + + Rewritten qmail-lspawn and the auth tools. Both programs use now the same + debug and ldap functions, which are now moved to new files (qldap-*). + The complete ldap lookup is now more flexible, so you can easier add your + special stuff. + + The qmailUser ldap field and the corresponding conf file are no longer used, + they have been replaced with the uid field. + + Added maildir++ support, this means especially better quota support via the + maildir++ maildirsize file. For more info have a look at courier-imap + http://www.inter7.com/courierimap/ + + Added signal-handler for qmail-lspawn, now with a SIGHUP the qmail-lspawn + parent process reloads the his settings ( via the ~control files ) + + Added cluster support, use -DQLDAP_CLUSTER for enabling. + + Removed PWOPTS=-DLOOK_UP_PASSWD because it was only for checkpassword + and with ldaplocaldelivery you get the same result on the fly. + + Few minor bugfixes (qmail-qmqpd.c, qmail-qmtpd.c, receive.c) + + Updated QLDAPINSTALL and added new QLDAPNEWS because QLDAPINSTALL was + getting to long. + + Changed the make process, now with the make setup check also the qmail-ldap + parts are build and installed. Have fun ... + + Few minor bugfixes (accountStatus, AUTO_MAILDIRMAKE) + + Hack in the LDAP search filter escape function due to a bug in most LDAP + servers. Instead of escaping the wildchars we replace them with '_' as + long as -DLDAP_ESCAPE_BUG is present. (see Makefile) + + a catch all mail for one domain system is now available. The default + catchall account is "catchall@domain.com". You can change that to any + other sting in qmail-ldap.h at compile time. LDAP wildcards are not + allowed. + Due to a bug in the LDAP servers wildcards escaping does not work, so pay + attention. + + rewritten qmail-locals qldap code, now supports better support for different + dotModes. There are also some new settings. + + fixed some old bugs in qmail-local + + fixed already some bugs in new qmail-local code ;-) + + added a log facility to qmail-lspawn. + + added some experimental -extension support in qmail-lspawn. + + Added a headerfile qmail-ldap.h where all parameters are set. + This includes some changes in qmail-local.c qmail-lspawn.c and checkpassword.c + + qmail-lspawn checks no longer for "correct" mailaddresses, now the possible + mailaddress is escaped ('(', ')', '*') before added to the search filter. + + all the stuff that was fixed in the subpatches. (XXX double check that) + + Added some compile options in the Makefile for easier configuration (see 5.) + + Added Christopher K. Davis' patch to handle oversized dns packets. + + Added Chris Johnson's tarpitting patch. + + Added qmail-quotawarn and qmail-reply for better handling of quota-warnings + and auto reply + + deliveryMode is now a comma separated list see LDAP PARAMETER FIELDS + + Fixed a few things in qmail-local + + Supports OpenLDAP now + + WARNING: {SHA1} changed to {SHA} according to the standard + + Integrated Lindsay Haisley update to Rask Lambertsen's excellent + antispam patch for qmail v1.01, based on Lionel Widdifield's patch. + Please read ANTISPAM for more information. + + checkpassword now supports the password format used by Netscape + Mailserver pre-3.0 and Software.com's Post.Office (NS-MTA-MD5). + That string is hex encoded, the first 32 Octets are the MD5 hashed + password and the second 32 Octets are the salt to the MD5 function. + + Added automatic homedir and maildir maker to qmail-local. + This can be enabled with ~control/dirmaker + + qmail-smtpd does logging now. This can be set by an environment variable + in tcpserver: LOGLEVEL="X". "0" or not present = no logging, "1" = fatal + errors, "2" = connection setup and warnings, "3" = verbose. + + Added fix for qmail-pop3d stat command bug found by Aaron Nabil + . + + checkpassword compiled with QLDAPDEBUG now does complete LDAP debugging. + Usage: ./checkpassword POPLogin POPPassword + + digest computes MD4, MD5, RMD160 and SHA passwords (compatible to Netscape) + Usage: ./digest POPPassword + + solved a problem on big endian machines that caused wrong SHA, MD5, MD4, + RMD160 passwords. (Added an endian testprogram to solve those probs) + + added a working version of the "MAKE_NETSCAPE_WORK" patch under qmail-pop3d. + The download bar should now work correctly. + + Fixed the bugs in qmail-lspawn. Changed stralloc_catb to stralloc_cat. + Thanks to Franky Van Liedekerke + + diff -uN qmail-1.03/QLDAPPICTURE qmail-ldap/QLDAPPICTURE --- qmail-1.03/QLDAPPICTURE Thu Jan 1 01:00:00 1970 +++ qmail-ldap/QLDAPPICTURE Sun Jun 25 03:04:27 2000 @@ -0,0 +1,29 @@ + 1. qmail-smtpd accepts connection + + Is relayclient set? + Yes -> accept it anyway. + No -> check if recipient domain is listed in rcpthosts else + deny + + Does sender's domain have a valid MX or A record? + Yes -> accept for data + No -> deny + + Now the message gets queued. + + 2. qmail-send takes a look at it + + Is the recipients domain in virtualhosts or locals (doesn't matter + with qmail-ldap)? + Yes -> feed it to qmail-lspawn for local delivery + No -> feed it to qmail-rspawn for remote delivery (relaying as + usual) + + 3. qmail-lspawn gets it for local delivery + + Is the recipients full email address found in the LDAP directory? + Yes -> check if all needed attributes are present + Yes -> deliver it to the maildir + No -> bounce + No -> try a standard qmail (UNIX user or ~users/assign) delivery + diff -uN qmail-1.03/QLDAPTODO qmail-ldap/QLDAPTODO --- qmail-1.03/QLDAPTODO Thu Jan 1 01:00:00 1970 +++ qmail-ldap/QLDAPTODO Sun Sep 30 14:58:57 2001 @@ -0,0 +1,45 @@ +QMAIL-LDAP by Andre Oppermann , +Claudio Jeker and Boris Lutz +(c) 1998,1999,2000,2001 Internet Business Solutions Ltd. + +This LDAP patches for qmail come with NO WARRANTY. + +These patches are under the BSD license. + +RELEASE: $Date: 2001/09/22 16:12:46 $ ($Revision: 1.19 $) + +This is the TODO FILE, so the QLDAPINSTALL file gets a bit cleaner. +This file is NOT structured!! + +NEWS: + + see QLDAPNEWS + +TODO: + +ongoing - Debugging and testing, testing, testing +ongoing - The big qmail-ldap picture +ongoing - full code review by a third person +planned - splitting the patch into smaller separate pieces +planned - make it possible to have locals and rcpthosts in ldap + and perhaps also the rules for the tcpserver (certs?) + + +ALSO ON THE LIST: (priority list ???) +- force to alias if only mail and mailforwardingaddress is set (no uid). +- enhancement to debug code (almost done) +- benchmarking the code +- test what happens if only uid and mail is defiend in ldap or similar uncommon + cases (seems to be no problem, or?) +- add better documentation. (man files) +- make the current code rock solid (even if it is not perfect) +- better TLS support (better written??) (tls for pop???) +- SMTP-after-POP/IMAP and SMTP_AUTH +- make the complete lookup code modular so that it should be possible to add + diffrent backends. + It should also be so flexible that other auth services (smtp-auth/SASL) + are possible without rewriting to much. +- use connectionless ldap for lookups (done some work but it seems that the + udp support of slapd is just unusable, have to wait). Other possibility is + ldap over a local socket... + diff -uN qmail-1.03/TARGETS qmail-ldap/TARGETS --- qmail-1.03/TARGETS Mon Jun 15 12:53:16 1998 +++ qmail-ldap/TARGETS Tue Sep 4 00:19:34 2001 @@ -385,3 +385,32 @@ man setup check +check.o +base64.o +digest_md4.o +digest_md5.o +digest_rmd160.o +digest_sha1.o +checkpassword +checkpassword.o +digest +digest.o +endian +endian.o +qmail-reply +qmail-reply.o +qmail-quotawarn +qmail-quotawarn.o +maildir++.o +auth_imap.o +auth_pop.o +qldap-debug.o +qldap-ldaplib.o +qldap-mdm.o +auth_imap +auth_pop +qldap-errno.o +qmail-ldaplookup.o +qmail-ldaplookup +qldap-profile.o +output.o diff -uN qmail-1.03/TLS.readme qmail-ldap/TLS.readme --- qmail-1.03/TLS.readme Thu Jan 1 01:00:00 1970 +++ qmail-ldap/TLS.readme Sun Jan 16 13:36:38 2000 @@ -0,0 +1,71 @@ +Frederik Vermeulen 20000112 +http://www.esat.kuleuven.ac.be/~vermeule/qmail/tls.patch + +This patch implements RFC2487 in qmail. This means you can +get SSL or TLS encrypted and authenticated SMTP between +the MTAs and between MTA and an MUA like Netscape4.5. +The code is considered experimental. + +Usage: - install OpenSSL-0.9.4 http://www.openssl.org/ + - apply patch to qmail-1.03 http://www.qmail.org/ + Makefile and conf-cc were patched for appropriate + linking. Apart from that, the patches to qmail-remote.c + and qmail-smtpd.c can be applied separately. + - provide a certificate in /var/qmail/control/cert.pem. + "make cert" makes a self-signed certificate. + "make cert-req" makes a certificate request. + - replace qmail-smtpd and/or qmail-remote binary + - verify operation (header information should show + something like + "Received [..] with DES-CBC3-SHA encrypted SMTP;") + If you don't have a server to test with, you can test + by sending mail to ping@linux.student.kuleuven.ac.be, + which will bounce your mail. + +Optional: - when DEBUG is defined, some extra SSL info will be logged + - when a 512 RSA key is provided in /var/qmail/control/rsa512.pem, + this key will be used instead of on-the-fly generation by + qmail-smtpd. Daily replacement can be done by crontab: + 01 01 * * * /usr/local/ssl/bin/openssl genrsa \ + -out /var/qmail/control/rsa512.new 512 > /dev/null 2>&1;\ + chmod 600 /var/qmail/control/rsa512.new; chown qmaild.qmail \ + /var/qmail/control/rsa512.new; /bin/mv -f \ + /var/qmail/control/rsa512.new /var/qmail/control/rsa512.pem + - server authentication: + qmail-remote requires authentication from servers for which + /var/qmail/control/tlshosts/host.dom.ain.pem exists. + The .pem file contains the validating CA certificates + (or self-signed server certificate with openssl-0.9.5). + CommonName has to match. + WARNING: this option may cause mail to be delayed, bounced, + doublebounced, and lost. + - client authentication: + when relay rules would reject an incoming mail, + qmail-smtpd can allow the mail based on a presented cert. + Certs are verified against a CA list in + /var/qmail/control/clientca.pem (eg. http://www.modssl.org/ + source/cvs/exp/mod_ssl/pkg.mod_ssl/pkg.sslcfg/ca-bundle.crt) + and the cert email-address has to match a line in + /var/qmail/control/tlsclients. This email-address is logged + in the headers. + +Copyright: Same terms as qmail + Links with OpenSSL + Inspiration and code from examples in SSLeay (E. Young + and T. Hudson ), + stunnel (M. Trojnara ), + Postfix/TLS (L. Jaenicke ), + and modssl (R. Engelschall ). + Debug code from Jean-Philippe Donnio + Openssl usage consulting from Bodo M"oller + + +Interoperability: - Netscape 4.5 and higher + - Microsoft Outlook 5 + - Microsoft Exchange Internet Mail Server 5.5.2448.0 + - Postfix/TLS + http://www.aet.TU-Cottbus.DE/personen/jaenicke/pfixtls/ + - Sendmail-TLS http://opensource.3gi.com/sendmail-tls/ + +Patches: mailto: + diff -uN qmail-1.03/auth_imap.c qmail-ldap/auth_imap.c --- qmail-1.03/auth_imap.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/auth_imap.c Tue Sep 4 00:19:34 2001 @@ -0,0 +1,432 @@ +/* auth_imap.c, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#include +#include +#include +#include "error.h" +#include "qldap-errno.h" +#include "readwrite.h" +#include "stralloc.h" +#include "env.h" +#include "str.h" +#include "exit.h" +#include "timeoutread.h" +#include "fmt.h" +#include "sig.h" +#include "wait.h" +#include "scan.h" +#include "alloc.h" +#include "prot.h" +#include "auth_mod.h" +#include "qmail-ldap.h" +#include "qldap-debug.h" +#include "substdio.h" +#ifdef AUTOHOMEDIRMAKE +#include "qldap-mdm.h" +#endif + +unsigned int auth_port; +/* those are global defined so that auth_fail can use them */ +#define UP_LEN 1024 +char up[UP_LEN]; +int uplen; + +void auth_init(int argc, char **argv, stralloc *login, stralloc *authdata) +/* this function should return the 0-terminated string login and authdata + * argc and argv are the arguments of the next auth_module. */ +{ + char *s; + char *t; + char *l; + char *p; + int i; + const char *a=env_get("AUTHENTICATED"); + int waitstat; + + if (!argv[1]) { + qldap_errno = AUTH_NEEDED; + auth_error(); + } + + if (a && *a) { /* Already a good guy */ + log(8, "auth_init: allready authenticated\n"); + execvp( argv[1],argv + 1); + qldap_errno = AUTH_EXEC; + auth_error(); + } + + /* remove all zombies */ + sig_childdefault(); + while (wait(&waitstat) >= 0) ; + + uplen = 0; + for (;;) + { + do i = read(3,up + uplen,sizeof(up) - uplen); + while ((i == -1) && (errno == EINTR)); + if (i == -1) { + qldap_errno = ERRNO; + auth_error(); + } + if (i == 0) break; + uplen += i; + if (uplen >= sizeof(up)) { + qldap_errno = AUTH_PANIC; + auth_error(); + } + } + close(3); + + /* get the different fields: serviceAUTHTYPEAUTHDATA */ + i = 0; + s = up + i; /* service, for us uninteresting, but we could check for imap */ + while (up[i] && up[i] != '\n' ) if (++i == uplen) { + qldap_errno = AUTH_NEEDED; + auth_error(); + } + if (i == uplen) { + qldap_errno = AUTH_NEEDED; + auth_error(); + } + up[i++] = '\0'; + t = up + i; /* type has to be "login" else fail ... */ + while (up[i] && up[i] != '\n' ) if (++i == uplen) { + qldap_errno = AUTH_NEEDED; + auth_error(); + } + if (i == uplen) { + qldap_errno = AUTH_NEEDED; + auth_error(); + } + up[i++] = '\0'; + if ( str_diff("login", t) ) { + /* this modul supports only "login"-type, fail with AUTH_NOSUCH, so the + * next modul is called, perhaps with greater success */ + qldap_errno = AUTH_NOSUCH; + auth_fail(argc, argv, "unknown"); + } + l = up + i; /* next login */ + while (up[i] && up[i] != '\n' ) if (++i == uplen) { + qldap_errno = AUTH_NEEDED; + auth_error(); + } + if (i == uplen) { + qldap_errno = AUTH_NEEDED; + auth_error(); + } + up[i++] = '\0'; + p = up + i; /* and the password */ + while (up[i] && up[i] != '\n' ) if (++i == uplen) { + qldap_errno = AUTH_NEEDED; + auth_error(); + } + if (i == uplen) { + qldap_errno = AUTH_NEEDED; + auth_error(); + } + up[i++] = '\0'; + + /* copy the login and password into the coresponding structures */ + if (!stralloc_copys(login, l) ) { + qldap_errno = ERRNO; + auth_error(); + } + if (!stralloc_0(login) ) { + qldap_errno = ERRNO; + auth_error(); + } + + if (!stralloc_copys(authdata, p) ) { + qldap_errno = ERRNO; + auth_error(); + } + if (!stralloc_0(authdata) ) { + qldap_errno = ERRNO; + auth_error(); + } + + auth_port = 143; /* imap port */ + +} + +void auth_fail(int argc, char **argv, char *login) +/* Checks if it was a hard fail (bad password) or just a soft error + * (user not found) argc and argv are the arguments of the next auth_module. */ +{ + int i; + int pi[2]; + char *t; + t = up; + + log(2, "warning: auth_fail: user %s failed\n", login); + if ( qldap_errno == AUTH_NOSUCH ) { + log(4, "warning: auth_fail: user %s not found\n", login); + if ( !env_unset("AUTHENTICATED") ) { + qldap_errno = ERRNO; + auth_error(); + } + for( i=0; i uid || uid > UID_MAX ) { + log(2, "warning: auth_success: uid (%u) is to big or small (%u < uid < %u)\n", + uid, UID_MIN, UID_MAX); + qldap_errno = AUTH_ERROR; + auth_error(); + } + + if ( GID_MIN > gid || gid > GID_MAX ) { + log(2, "warning: auth_success: gid (%u) is to big or small (%u < gid < %u)\n", + gid, GID_MIN, GID_MAX); + qldap_errno = AUTH_ERROR; + auth_error(); + } + + /* first set the group id */ + if (prot_gid(gid) == -1) { + qldap_errno = AUTH_ERROR; + auth_error(); + } + log(32, "auth_success: setgid succeeded (%i)\n", gid); + /* ... then the user id */ + if (prot_uid(uid) == -1) { + qldap_errno = AUTH_ERROR; + auth_error(); + } + log(32, "auth_success: setuid succeeded (%i)\n", uid); + + /* ... go to home dir and create it if needed */ + if (chdir(home) == -1) { +#ifdef AUTOHOMEDIRMAKE + /* XXX homedirmake is not everywhere #ifdef'd because this would be too + * XXX hard. If you compile with a good compiler this should have the + * XXX same effect or you are probably loosing a few bytes of free mem + */ + if ( errno == error_noent && homedirmake && *homedirmake ) { + int ret; + + log(8, "auth_success: makeing homedir with %s %s %s\n", + homedirmake, home, (md && *md)? md: argv[2] ); + if (md && *md) { + ret = make_homedir(home, md, homedirmake ); + } else { + ret = make_homedir(home, argv[2], homedirmake ); + } + if (ret != 0 ) { + if ( qldap_errno == ERRNO ) { + log(2, "warning: auth_success: dirmaker failed (%s)\n", + error_str(errno)); + } else { + log(2, "warning: auth_success: dirmaker failed (%s)\n", + qldap_errno == MAILDIR_CRASHED? "program crashed": + "bad exit status"); + } + qldap_errno = MAILDIR_CORRUPT; + auth_error(); + } + if (chdir(home) == -1) { + log(2, "warning: auth_success: chdir failed after dirmaker (%s)\n", + error_str(errno)); + qldap_errno = MAILDIR_CORRUPT; + auth_error(); + } + log(32, "auth_success: homedir successfully made\n"); + } else { +#endif + qldap_errno = MAILDIR_CORRUPT; + auth_error(); +#ifdef AUTOHOMEDIRMAKE + } +#endif + } + + /* set up the environment for the execution of qmail-pop3d */ + if (!env_put2("USER",login)) { + qldap_errno = ERRNO; + auth_error(); + } + if (!env_put2("AUTHENTICATED",login)) { + qldap_errno = ERRNO; + auth_error(); + } + if (!env_put2("HOME",home)) { + qldap_errno = ERRNO; + auth_error(); + } + if ( md && *md ) { + if (!env_put2("MAILDIR",md)) { + qldap_errno = ERRNO; + auth_error(); + } + } else { + if ( !env_unset("MAILDIR") ) { + qldap_errno = ERRNO; + auth_error(); + } + } + + log(32, "auth_success: environment successfully set: USER=%s, HOME=%s, MAILDIR=%s\n", + login, home, (md && *md)? md:"unset using aliasempty" ); + + /* ... now check that we are realy not running as root */ + if (!getuid()) { + qldap_errno = AUTH_ERROR; + auth_error(); + } + execvp( argv[1],argv + 1); + + qldap_errno = AUTH_EXEC; + auth_error(); + /* end */ +} + +void auth_error(void) +/* error handler for this module, does not return */ +{ + char *env; + char envname[FMT_ULONG+8]; + char *n; + char *n2; + unsigned long numarg; + unsigned long i; + char **argvs; + + /* XXX under courier-imap it is not simple to give the correct failure back + * XXX to the user, perhaps somebody has a good idea */ + + log(2, "warning: auth_error: authorization failed (%s)\n", + qldap_err_str(qldap_errno) ); + if (! (env = env_get("ARGC") ) ) { + _exit(111); + } + scan_ulong(env, &numarg); + argvs = (char **) alloc( (numarg+1) * sizeof(char *) ); + n = envname; + n += fmt_str(n, "AUTHARGV"); + for (i = 0; i < numarg; i++) { + n2 = n; n2 += fmt_ulong(n2, i); *n2 = 0; + if (! (argvs[i] = env_get(envname) ) ) { + _exit(111); + } + } + argvs[i+1] = 0; + execvp(*argvs, argvs); + _exit(111); + +} + +#ifdef QLDAP_CLUSTER + +static void get_ok(int fd, char *tag) +/* get the ok for the next command, wait for "[TAG] OK.*\r\n" */ +/* XXX this should work now better (Idea from RFC 1730 and fetchmail) */ +{ +#define AUTH_TIMEOUT 10 /* 10 sec timeout */ +#define OK_LEN 8192+1 + char ok[OK_LEN]; + char *s; + unsigned char x; + int len; + int i; + + if ( !tag ) return; /* bad pointer */ + do { + len = timeoutread(AUTH_TIMEOUT, fd, ok, sizeof(ok) - 1); + if ( len == -1 ) { + qldap_errno = ERRNO; + auth_error(); + } + ok[len] = '\0'; + /* upper case all */ + for ( i = 0, s = ok ; i < len; i++ ) { + x = *s - 'a'; + if ( x <= 'z' - 'a' ) *s = x + 'A'; + s++; + } + } while ( str_diffn(ok, tag, str_len(tag) ) ); + /* tag found, next check for OK */ + s = ok + str_len(tag); /* skip tag */ + while ( *s == ' ' || *s == '\t' ) s++; /* skip all spaces */ + + if ( str_diffn(s, "OK", 2 ) == 0 ) return; + else if ( str_diffn(s, "BAD", 3) == 0 || str_diffn(s, "NO", 2) == 0 ) { + qldap_errno = BADCLUSTER; /* other server not happy */ + auth_error(); + } + /* ARRG, this server talks not my dialect */ + qldap_errno = BADCLUSTER; + auth_error(); +} + +void auth_forward(int fd, char *login, char *passwd) +/* for connection forwarding, makes the login part and returns after sending the + * latest command immidiatly */ +{ + char *tag = env_get("IMAPLOGINTAG"); + substdio ss; + char buf[512]; + + + if ( !( tag && *tag ) ) { + /* UH OH, no imap tag, how could that be ? */ + qldap_errno = AUTH_PANIC; + auth_error(); + } + + get_ok(fd, "*"); + substdio_fdbuf(&ss,write,fd,buf,sizeof(buf)); + substdio_put(&ss, tag, str_len(tag) ); + substdio_put(&ss, " login ", 7); + substdio_put(&ss, login, str_len(login) ); + substdio_put(&ss, " ", 1); + substdio_put(&ss, passwd, str_len(passwd) ); + substdio_put(&ss, "\n\r",1); + substdio_flush(&ss); + +} + +#endif /* QLDAP_CLUSTER */ + diff -uN qmail-1.03/auth_mod.h qmail-ldap/auth_mod.h --- qmail-1.03/auth_mod.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/auth_mod.h Mon Feb 14 13:11:53 2000 @@ -0,0 +1,28 @@ +/* auth_mod.h, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#ifndef __AUTH_MOD_H__ +#define __AUTH_MOD_H__ + +#include "stralloc.h" + +extern unsigned int auth_port; + +void auth_init(int argc, char **argv, stralloc *login, stralloc *authdata); +/* this function should return the 0-terminated string login and authdata + * argc and argv are the arguments of the next auth_module. */ + +void auth_fail(int argc, char **argv, char *login); +/* Checks if it was a hard fail (bad password) or just a soft error + * (user not found) argc and argv are the arguments of the next auth_module. */ + +void auth_success(int argc, char **argv, char *login, int uid, int gid, + char* home, char *homemaker, char *md); +/* starts the next auth_module, or what ever (argv ... ) */ + +void auth_error(void); +/* error handler, for this module, does not return */ + +void auth_forward(int fd, char *login, char *passwd); +/* for connection forwarding, makes the login part and returns after sending the + * latest command immidiatly */ + +#endif diff -uN qmail-1.03/auth_pop.c qmail-ldap/auth_pop.c --- qmail-1.03/auth_pop.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/auth_pop.c Tue Sep 4 00:19:34 2001 @@ -0,0 +1,325 @@ +/* auth_pop.c, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#include +#include "error.h" +#include "qldap-errno.h" +#include "readwrite.h" +#include "stralloc.h" +#include "env.h" +#include "str.h" +#include "exit.h" +#include "timeoutread.h" +#include "prot.h" +#include "auth_mod.h" +#include "qmail-ldap.h" +#include "qldap-debug.h" +#include "substdio.h" +#ifdef AUTOHOMEDIRMAKE +#include "qldap-mdm.h" +#endif + +unsigned int auth_port; + +void auth_init(int argc, char **argv, stralloc *login, stralloc *authdata) +/* this function should return the 0-terminated string login and authdata + * argc and argv are the arguments of the next auth_module. */ +{ +#define UP_LEN 513 + char up[UP_LEN]; + char *l; + char *p; + int uplen; + int i; + + + if (!argv[1]) { + qldap_errno = AUTH_NEEDED; + auth_error(); + } + + uplen = 0; + for (;;) + { + do i = read(3,up + uplen,sizeof(up) - uplen); + while ((i == -1) && (errno == EINTR)); + if (i == -1) { + qldap_errno = ERRNO; + auth_error(); + } + if (i == 0) break; + uplen += i; + if (uplen >= sizeof(up)) { + qldap_errno = AUTH_PANIC; + auth_error(); + } + } + close(3); + + i = 0; + l = up + i; + while (up[i++]) if (i == uplen) { + qldap_errno = AUTH_NEEDED; + auth_error(); + } + p = up + i; + if (i == uplen) { + qldap_errno = AUTH_NEEDED; + auth_error(); + } + while (up[i++]) if (i == uplen) { + qldap_errno = AUTH_NEEDED; + auth_error(); + } + + if (!stralloc_copys(login, l) ) { + qldap_errno = ERRNO; + auth_error(); + } + if (!stralloc_0(login) ) { + qldap_errno = ERRNO; + auth_error(); + } + + if (!stralloc_copys(authdata, p) ) { + qldap_errno = ERRNO; + auth_error(); + } + if (!stralloc_0(authdata) ) { + qldap_errno = ERRNO; + auth_error(); + } + + /* up no longer needed so delete it */ + for ( i=0; i uid || uid > UID_MAX ) { + log(2, "warning: auth_success: uid (%u) is to big or small (%u < uid < %u)\n", + uid, UID_MIN, UID_MAX); + qldap_errno = AUTH_ERROR; + auth_error(); + } + + if ( GID_MIN > gid || gid > GID_MAX ) { + log(2, "warning: auth_success: gid (%u) is to big or small (%u < gid < %u)\n", + gid, GID_MIN, GID_MAX); + qldap_errno = AUTH_ERROR; + auth_error(); + } + + /* first set the group id */ + if (prot_gid(gid) == -1) { + qldap_errno = AUTH_ERROR; + auth_error(); + } + log(32, "auth_success: setgid succeeded (%i)\n", gid); + /* ... then the user id */ + if (prot_uid(uid) == -1) { + qldap_errno = AUTH_ERROR; + auth_error(); + } + log(32, "auth_success: setuid succeeded (%i)\n", uid); + + /* ... go to home dir and create it if needed */ + if (chdir(home) == -1) { +#ifdef AUTOHOMEDIRMAKE + /* XXX homedirmake is not everywhere #ifdef'd because this would be too + * XXX hard. If you compile with a good compiler this should have the + * XXX same effect or you are probably loosing a few bytes of free mem + */ + if ( homedirmake && *homedirmake ) { + int ret; + + log(8, "auth_success: makeing homedir with %s %s %s\n", + homedirmake, home, (md && *md)? md: argv[2] ); + if (md && *md) { + ret = make_homedir(home, md, homedirmake ); + } else { + ret = make_homedir(home, argv[2], homedirmake ); + } + if (ret != 0 ) { + if ( qldap_errno == ERRNO ) { + log(2, "warning: auth_success: dirmaker failed (%s)\n", + error_str(errno)); + } else { + log(2, "warning: auth_success: dirmaker failed (%s)\n", + qldap_errno == MAILDIR_CRASHED? "program crashed": + "bad exit status"); + } + qldap_errno = MAILDIR_CORRUPT; + auth_error(); + } + if (chdir(home) == -1) { + log(2, + "warning: auth_success: chdir failed after dirmaker (%s)\n", + error_str(errno)); + qldap_errno = MAILDIR_CORRUPT; + auth_error(); + } + log(32, "auth_success: homedir successfully made\n"); + } else { +#endif + qldap_errno = MAILDIR_CORRUPT; + auth_error(); +#ifdef AUTOHOMEDIRMAKE + } +#endif + } + + /* set up the environment for the execution of qmail-pop3d */ + if (!env_put2("USER",login)) { + qldap_errno = ERRNO; + auth_error(); + } + if (!env_put2("HOME",home)) { + qldap_errno = ERRNO; + auth_error(); + } + if ( md && *md ) { + if (!env_put2("MAILDIR",md)) { + qldap_errno = ERRNO; + auth_error(); + } + } else { + if ( !env_unset("MAILDIR") ) { + qldap_errno = ERRNO; + auth_error(); + } + } + + log(32, "auth_success: environment successfully set: USER=%s, HOME=%s, MAILDIR=%s\n", + login, home, (md && *md)? md:"unset using aliasempty" ); + + /* start qmail-pop3d */ + /* ... now check that we are realy not running as root */ + if (!getuid()) { + qldap_errno = AUTH_ERROR; + auth_error(); + } + execvp( argv[1],argv + 1); + + qldap_errno = AUTH_EXEC; + auth_error(); + /* end */ +} + +void auth_error(void) +/* error handler for this module, does not return */ +{ + /* Error exit codes: + * 1 = error in server configuration + * 2 = unable to contact authorization server + * 25= user record incorrect + * 3 = authorization failed + * 4 = account disabled + * 5 = mailhost is unreachable + * 6 = mailbox is corrupted + * 7 = unable to start subprogram + * 8 = out of memory + */ + log(2, "warning: auth_error: authorization failed (%s)\n", + qldap_err_str(qldap_errno) ); + + if ( qldap_errno == LDAP_INIT ) _exit(1); + if ( qldap_errno == LDAP_BIND ) _exit(2); + if ( qldap_errno == AUTH_FAILED || qldap_errno == LDAP_REBIND || + qldap_errno == AUTH_NOSUCH ) _exit(3); + if ( qldap_errno == LDAP_SEARCH || qldap_errno == LDAP_NEEDED || + qldap_errno == ILL_AUTH || qldap_errno == ILL_PATH ) _exit(25); + if ( qldap_errno == ACC_DISABLED ) _exit(4); + if ( qldap_errno == BADCLUSTER ) _exit(5); + if ( qldap_errno == MAILDIR_CORRUPT ) _exit(6); + if ( qldap_errno == AUTH_EXEC ) _exit(7); + if ( qldap_errno == ERRNO && errno == error_nomem ) _exit(8); + _exit(111); +} + +#ifdef QLDAP_CLUSTER + +static void get_ok(int fd) +/* get the ok for the next command, wait for "+OK.*\r\n" */ +/* XXX this could be a mostly correct solution (adapted from fetchmail) */ +{ +#define AUTH_TIMEOUT 10 /* 10 sec timeout */ +#define OK_LEN 512 /* max length of response (RFC1939) */ + char ok[OK_LEN]; + char *c; + int len; + int i; + + /* first get one single line from the other pop server */ + len = timeoutread(AUTH_TIMEOUT, fd, ok, OK_LEN); + if ( len == -1 ) { + /* OK an error occured, giving up */ + qldap_errno = ERRNO; + auth_error(); + } + if ( len != 0 ) { + c = ok; + if ( *c == '+' || *c == '-' ) { + c++; + } else { + qldap_errno = BADCLUSTER; /* BAD POP3 Protocol */ + auth_error(); + } + for ( i = 1; i < len /* paranoia */ && + ('A' < *c && *c < 'Z') ; ) { i++; c++; } + + if ( i < len ) { + *c = '\0'; + if ( str_diff(ok, "+OK") == 0 ) { + return; + } else if ( str_diffn(ok, "-ERR", 4) ) { + qldap_errno = BADCLUSTER; /* other server is not happy */ + auth_error(); + } + } + } + /* ARRG, very strange POP3 answer */ + qldap_errno = BADCLUSTER; + auth_error(); +} + +void auth_forward(int fd, char *login, char *passwd) +/* for connection forwarding, makes the login part and returns after sending the + * last command immidiatly so the user gets the possible error */ +{ + char buf[512]; + substdio ss; + + substdio_fdbuf(&ss,write,fd,buf,sizeof(buf)); + get_ok(fd); + substdio_put(&ss, "user ", 5); + substdio_put(&ss, login, str_len(login) ); + substdio_put(&ss, "\n\r", 1); + substdio_flush(&ss); + get_ok(fd); + substdio_put(&ss, "pass ", 5); + substdio_put(&ss, passwd, str_len(passwd) ); + substdio_put(&ss, "\n\r",1); + substdio_flush(&ss); + +} + +#endif /* QLDAP_CLUSTER */ + diff -uN qmail-1.03/base64.c qmail-ldap/base64.c --- qmail-1.03/base64.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/base64.c Fri Apr 20 21:35:42 2001 @@ -0,0 +1,318 @@ +/* base64.c for QLDAP modified to use only djb's qmail stuff */ + +/* */ +/* BASE64 */ +/* */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include "str.h" + +#define Assert(Cond) if (!(Cond)) abort() + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +int +b64_ntop(src, srclength, target, targsize) + unsigned char const *src; + size_t srclength; + char *target; + size_t targsize; +{ + size_t datalength = 0; + unsigned char input[3]; + unsigned char output[4]; + int i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + Assert(output[3] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); +} + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +#define ISSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n' || (x) == '\r') +/* XXX + this is not the complete subset of ctypes.h isspace but for qmail-ldap + only space, tab, newline and carriage-return are useful (formfeed and + vertical tabs are normaly not used in network communications. + Claudio Jeker + */ + +int +b64_pton(src, target, targsize) + char const *src; + unsigned char *target; + size_t targsize; +{ + int tarindex, state, ch; + unsigned int pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0') { + if (ISSPACE(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = str_chr(Base64, ch); + if (pos > 63) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = pos << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= pos >> 4; + target[tarindex+1] = (pos & 0x0f) << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= pos >> 2; + target[tarindex+1] = (pos & 0x03) << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= pos; + } + tarindex++; + state = 0; + break; + default: + abort(); + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = *src++) + if (!ISSPACE(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = *src++) + if (!ISSPACE(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} diff -uN qmail-1.03/base64.h qmail-ldap/base64.h --- qmail-1.03/base64.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/base64.h Fri Apr 20 21:35:42 2001 @@ -0,0 +1,12 @@ +/* base64.h for QLDAP modified to use only djb's qmail stuff */ + +/* */ +/* BASE64 */ +/* */ + +/* base63 encode */ +int b64_ntop(); + +/* base64 decode */ +int b64_pton(); + diff -uN qmail-1.03/check.c qmail-ldap/check.c --- qmail-1.03/check.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/check.c Thu Apr 20 17:20:05 2000 @@ -0,0 +1,222 @@ +#include "qmail-ldap.h" +#include "check.h" +#include "str.h" + +extern unsigned char testvektor[128]; + +/* XXX this is not a security checker, it just looks that no special chars + * XXX are in the string this is because the ldap server could send some + * XXX faked datas */ +int sanitycheckb(register char *s, register unsigned int len, + register unsigned char mask) +{ + register unsigned char *tv; + register char x; + + tv = testvektor; + + x = *s++; if(!len--) return 1; + if ( x & 0x80 || !( *(tv + (unsigned long) x) & mask ) || + ( *(tv + (unsigned long) x) & 0x80 ) ) return 0; + /* is this char allowed as first char (normaly '-' is not) ??? */ + for (;;) { + x = *s++; if(!len--) return 1; + if ( x & 0x80 || !( *(tv + (unsigned long) x) & mask) ) return 0; + x = *s++; if(!len--) return 1; + if ( x & 0x80 || !( *(tv + (unsigned long) x) & mask) ) return 0; + x = *s++; if(!len--) return 1; + if ( x & 0x80 || !( *(tv + (unsigned long) x) & mask) ) return 0; + x = *s++; if(!len--) return 1; + if ( x & 0x80 || !( *(tv + (unsigned long) x) & mask) ) return 0; + } + return 0; /* paranoia */ +} + +/* XXX this is not a security checker, it just looks that no special chars + * XXX are in the string this is because the ldap server could send some + * XXX faked datas */ +int sanitypathcheckb(register char *s, register unsigned int len, + register unsigned char mask) +/* works like sanitycheckb but also looks that there is no '..' in the + * string. This should be used for maildirpaths */ +{ + register unsigned char *tv; + register char x; + register int doubledot; + + tv = testvektor; + + x = *s++; if(!len--) return 1; + /* XXX is this char allowed as first char (normaly '-' is not) */ + if ( x & 0x80 || !( *(tv + (unsigned long) x) & mask ) || + ( *(tv + (unsigned long) x) & 0x80 ) ) return 0; + if ( x == '.') doubledot = 1; else doubledot = 0; + for (;;) { + x = *s++; if(!len--) return 1; + if ( x & 0x80 || !( *(tv + (unsigned long) x) & mask) ) return 0; + if ( x == '.' ) { + if ( doubledot++ ) return 0; + } else doubledot = 0; + x = *s++; if(!len--) return 1; + if ( x & 0x80 || !( *(tv + (unsigned long) x) & mask) ) return 0; + if ( x == '.' ) { + if ( doubledot++ ) return 0; + } else doubledot = 0; + x = *s++; if(!len--) return 1; + if ( x & 0x80 || !( *(tv + (unsigned long) x) & mask) ) return 0; + if ( x == '.' ) { + if ( doubledot++ ) return 0; + } else doubledot = 0; + } + return 0; /* paranoia */ +} + +int sanitychecks(register char *s, register unsigned char mask) +{ + return sanitycheckb(s, str_len(s), mask); +} + +int sanitypathchecks(register char *s, register unsigned char mask) +{ + return sanitypathcheckb(s, str_len(s), mask); +} + +unsigned char testvektor[128] = { +#define SPACE ALLOW_PROG +#if RESTRICT_PROG == 1 +# define PARANOIA DENY_PROG +#else +# define PARANOIA 0xFF +#endif + /* nr char */ + /********************/ + /* 0 \000 ^@ */ DENY_ALL, + /* 1 \001 ^A */ DENY_ALL, + /* 2 \002 ^B */ DENY_ALL, + /* 3 \003 ^C */ DENY_ALL, + /* 4 \004 ^D */ DENY_ALL, + /* 5 \005 ^E */ DENY_ALL, + /* 6 \006 ^F */ DENY_ALL, + /* 7 \007 ^G */ DENY_ALL, + /* 8 \010 ^F */ DENY_ALL, + /* 9 \011 \t */ SPACE, + /* 10 \012 \n */ SPACE, + /* 11 \013 ^K */ DENY_ALL, + /* 12 \014 ^L */ DENY_ALL, + /* 13 \015 ^M */ DENY_ALL, + /* 14 \016 ^N */ DENY_ALL, + /* 15 \017 ^O */ DENY_ALL, + /* 16 \020 ^P */ DENY_ALL, + /* 17 \021 ^Q */ DENY_ALL, + /* 18 \022 ^R */ DENY_ALL, + /* 19 \023 ^S */ DENY_ALL, + /* 20 \024 ^T */ DENY_ALL, + /* 21 \025 ^U */ DENY_ALL, + /* 22 \026 ^V */ DENY_ALL, + /* 23 \027 ^W */ DENY_ALL, + /* 24 \030 ^X */ DENY_ALL, + /* 25 \031 ^Y */ DENY_ALL, + /* 26 \032 ^Z */ DENY_ALL, + /* 27 \033 ESC */ DENY_ALL, + /* 28 \034 ^\ */ DENY_ALL, + /* 29 \035 ^] */ DENY_ALL, + /* 30 \036 ^^ */ DENY_ALL, + /* 31 \037 ^_ */ DENY_ALL, + /* 32 ' ' */ SPACE, + /* 33 '!' */ ALLOW_PROG&PARANOIA, + /* 34 '"' */ ALLOW_PROG, + /* 35 '#' */ ALLOW_PROG&PARANOIA, + /* 36 '$' */ ALLOW_PROG&PARANOIA, + /* 37 '%' */ ALLOW_PROG&PARANOIA, + /* 38 '&' */ ALLOW_PROG&PARANOIA, + /* 39 ''' */ ALLOW_PROG, + /* 40 '(' */ ALLOW_PROG&PARANOIA, + /* 41 ')' */ ALLOW_PROG&PARANOIA, + /* 42 '*' */ ALLOW_PROG&PARANOIA, + /* 43 '+' */ ALLOW_PROG, + /* 44 ',' */ ALLOW_PROG, + /* 45 '-' */ ALLOW_ALL|NOT_FIRST, /*XXX*/ + /* 46 '.' */ ALLOW_ALL, + /* 47 '/' */ ALLOW_ALL&DENY_USER, /*XXX user*/ + /* 48 '0' */ ALLOW_ALL, + /* 49 '1' */ ALLOW_ALL, + /* 50 '2' */ ALLOW_ALL, + /* 51 '3' */ ALLOW_ALL, + /* 52 '4' */ ALLOW_ALL, + /* 53 '5' */ ALLOW_ALL, + /* 54 '6' */ ALLOW_ALL, + /* 55 '7' */ ALLOW_ALL, + /* 56 '8' */ ALLOW_ALL, + /* 57 '9' */ ALLOW_ALL, + /* 58 ':' */ ALLOW_PROG|ALLOW_PATH, + /* 59 ';' */ ALLOW_PROG&PARANOIA, + /* 60 '<' */ ALLOW_PROG&PARANOIA, + /* 61 '=' */ ALLOW_PROG|ALLOW_PATH, + /* 62 '>' */ ALLOW_PROG&PARANOIA, + /* 63 '?' */ ALLOW_PROG&PARANOIA, + /* 64 '@' */ ALLOW_USER|ALLOW_PATH|ALLOW_PROG, /*XXX*/ + /* 65 'A' */ ALLOW_ALL, + /* 66 'B' */ ALLOW_ALL, + /* 67 'C' */ ALLOW_ALL, + /* 68 'D' */ ALLOW_ALL, + /* 69 'E' */ ALLOW_ALL, + /* 70 'F' */ ALLOW_ALL, + /* 71 'G' */ ALLOW_ALL, + /* 72 'H' */ ALLOW_ALL, + /* 73 'I' */ ALLOW_ALL, + /* 74 'J' */ ALLOW_ALL, + /* 75 'K' */ ALLOW_ALL, + /* 76 'L' */ ALLOW_ALL, + /* 77 'M' */ ALLOW_ALL, + /* 78 'N' */ ALLOW_ALL, + /* 79 'O' */ ALLOW_ALL, + /* 80 'P' */ ALLOW_ALL, + /* 81 'Q' */ ALLOW_ALL, + /* 82 'R' */ ALLOW_ALL, + /* 83 'S' */ ALLOW_ALL, + /* 84 'T' */ ALLOW_ALL, + /* 85 'U' */ ALLOW_ALL, + /* 86 'V' */ ALLOW_ALL, + /* 87 'W' */ ALLOW_ALL, + /* 88 'X' */ ALLOW_ALL, + /* 89 'Y' */ ALLOW_ALL, + /* 90 'Z' */ ALLOW_ALL, + /* 91 '[' */ ALLOW_PROG&PARANOIA, + /* 92 '\' */ ALLOW_PROG, + /* 93 ']' */ ALLOW_PROG&PARANOIA, + /* 94 '^' */ ALLOW_PROG&PARANOIA, + /* 95 '_' */ ALLOW_ALL, + /* 96 '`' */ ALLOW_PROG&PARANOIA, + /* 97 'a' */ ALLOW_ALL, + /* 98 'b' */ ALLOW_ALL, + /* 99 'c' */ ALLOW_ALL, + /* 100 'd' */ ALLOW_ALL, + /* 101 'e' */ ALLOW_ALL, + /* 102 'f' */ ALLOW_ALL, + /* 103 'g' */ ALLOW_ALL, + /* 104 'h' */ ALLOW_ALL, + /* 105 'i' */ ALLOW_ALL, + /* 106 'j' */ ALLOW_ALL, + /* 107 'k' */ ALLOW_ALL, + /* 108 'l' */ ALLOW_ALL, + /* 109 'm' */ ALLOW_ALL, + /* 110 'n' */ ALLOW_ALL, + /* 111 'o' */ ALLOW_ALL, + /* 112 'p' */ ALLOW_ALL, + /* 113 'q' */ ALLOW_ALL, + /* 114 'r' */ ALLOW_ALL, + /* 115 's' */ ALLOW_ALL, + /* 116 't' */ ALLOW_ALL, + /* 117 'u' */ ALLOW_ALL, + /* 118 'v' */ ALLOW_ALL, + /* 119 'w' */ ALLOW_ALL, + /* 120 'x' */ ALLOW_ALL, + /* 121 'y' */ ALLOW_ALL, + /* 122 'z' */ ALLOW_ALL, + /* 123 '{' */ ALLOW_PROG&PARANOIA, + /* 124 '|' */ ALLOW_PROG&PARANOIA, + /* 125 '}' */ ALLOW_PROG&PARANOIA, + /* 126 '~' */ ALLOW_PROG&PARANOIA, + /* 127 ^? */ DENY_ALL +}; + diff -uN qmail-1.03/check.h qmail-ldap/check.h --- qmail-1.03/check.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/check.h Thu Apr 20 17:20:05 2000 @@ -0,0 +1,33 @@ +#ifndef _CHECK_H_ +#define _CHECK_H_ + + +#define DENY_ALL 0x00 +#define ALLOW_USER 0x01 +#define ALLOW_PATH 0x02 +#define ALLOW_PROG 0x04 +#define ALLOW_ALL (ALLOW_USER | ALLOW_PATH | ALLOW_PROG) +#define DENY_USER (unsigned char) ~ALLOW_USER +#define DENY_PATH (unsigned char) ~ALLOW_PATH +#define DENY_PROG (unsigned char) ~ALLOW_PROG +#define NOT_FIRST 0x80 + + +extern int sanitycheckb(register char *s, register unsigned int len, + register unsigned char mask); +extern int sanitychecks(register char *s, register unsigned char mask); + +extern int sanitypathcheckb(register char *s, register unsigned int len, + register unsigned char mask); +extern int sanitypathchecks(register char *s, register unsigned char mask); + +#define chck_userb(str, len) sanitycheckb(str, len, ALLOW_USER) +#define chck_users(str) sanitychecks(str, ALLOW_USER) + +#define chck_pathb(str, len) sanitypathcheckb(str, len, ALLOW_PATH) +#define chck_paths(str) sanitypathchecks(str, ALLOW_PATH) + +#define chck_progb(str, len) sanitycheckb(str, len, ALLOW_PROG) +#define chck_progs(str) sanitychecks(str, ALLOW_PROG) + +#endif diff -uN qmail-1.03/checkpassword.c qmail-ldap/checkpassword.c --- qmail-1.03/checkpassword.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/checkpassword.c Sun Sep 30 14:58:57 2001 @@ -0,0 +1,643 @@ +/* checkpasswd.c, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#include "qmail-ldap.h" +#include "stralloc.h" +#include "auth_mod.h" +#include "qldap-ldaplib.h" +#include "qldap-errno.h" +#include "readwrite.h" +#include "error.h" +#include "str.h" +#include "open.h" +#include "substdio.h" +#include "getln.h" +#include +#include +#include "digest_md4.h" +#include "digest_md5.h" +#include "digest_rmd160.h" +#include "digest_sha1.h" +#include "select.h" +#include "ipalloc.h" +#include "dns.h" +#include "timeoutconn.h" +#include "byte.h" +#include "scan.h" +#include "fmt.h" +#include "alloc.h" +#include "check.h" +#include "qldap-debug.h" +#include "output.h" +#ifdef QLDAP_CLUSTER +#include "constmap.h" +#endif + +/* Edit the first lines in the Makefile to enable local passwd lookups + * and debug options. + * To use shadow passwords under Solaris, uncomment the 'SHADOWOPTS' line + * in the Makefile. + * To use shadow passwords under Linux, uncomment the 'SHADOWOPTS' line and + * the 'SHADOWLIBS=-lshadow' line in the Makefile. + */ +#include +#ifdef PW_SHADOW +#include +#endif +#ifdef AIX +#include +#endif + +extern stralloc qldap_me; +extern stralloc qldap_objectclass; + +int rebind; +int cluster; + +static int check_ldap(stralloc *login, + stralloc *authdata, + unsigned long *uid, + unsigned long *gid, + stralloc *home, + stralloc *maildir); + +static int check_passwd(stralloc *login, + stralloc *authdata, + unsigned long *uid, + unsigned long *gid, + stralloc *home, + stralloc *md); + +static int cmp_passwd(unsigned char *clear, char *encrypted); + +static int get_local_maildir(stralloc *home, stralloc *maildir); + +#ifdef QLDAP_CLUSTER +extern struct constmap qldap_mailhosts; + +static void copyloop(int infd, int outfd, int timeout); +static void forward_session(char *host, char *name, char *passwd); +#endif + +static int make_filter(stralloc *value, stralloc *filter); +static void free_stralloc(stralloc *sa); + +void main(int argc, char **argv) +{ + int locald; + stralloc login = {0}; + stralloc authdata = {0}; + stralloc home = {0}; + stralloc homemaker = {0}; + stralloc maildir = {0}; + unsigned long uid; + unsigned long gid; + + log_init(STDERR, 255, 0); /* XXX limited to 64 so it is not possible to get + * XXX passwords via debug on normal systems */ + + auth_init(argc, argv, &login, &authdata); + log(256, "auth_init: login=%s, authdata=%s\n", login.s, authdata.s); + + if ( authdata.len <= 1 ) { + log(1, "alert: null password.\n"); + qldap_errno = AUTH_NEEDED; + auth_fail(argc, argv, login.s); + } + + if ( init_ldap(&locald, &cluster, &rebind, &homemaker, 0, 0, 0) == -1 ) { + log(1, "alert: init_ldap failed.\n"); + _exit(1); + } + log(64, "init_ldap: ld=%i, cluster=%i, rebind=%i, hdm=%s\n", + locald, cluster, rebind, homemaker.s); + + if ( check_ldap(&login, &authdata, &uid, &gid, &home, &maildir) ) { + log(16, "authentication with ldap was not successful\n"); + if ( locald == 1 && + (qldap_errno == LDAP_NOSUCH || qldap_errno == LDAP_SEARCH) ) { + log(16, "trying to authenticate with the local passwd db\n"); + if ( check_passwd(&login, &authdata, &uid, &gid, &home, &maildir) ) { + auth_fail(argc, argv, login.s); + } + } else { + auth_fail(argc, argv, login.s); + } + } + + auth_success(argc, argv, login.s, uid, gid, home.s, homemaker.s, maildir.s); + _exit(1); /* should never get here */ +} + +int check_ldap(stralloc *login, stralloc *authdata, unsigned long *uid, + unsigned long *gid, stralloc *home, stralloc *maildir) +{ + userinfo info; + extrainfo extra[2]; + searchinfo search; + stralloc filter = {0}; + int ret; + char *attrs[] = { LDAP_UID, /* the first 6 attrs are default */ + LDAP_QMAILUID, + LDAP_QMAILGID, + LDAP_ISACTIVE, + LDAP_MAILHOST, + LDAP_MAILSTORE, + LDAP_HOMEDIR, + LDAP_PASSWD, 0 }; /* passwd is extra */ + + /* initalize the different info objects */ + if ( rebind ) { + extra[0].what = 0; /* under rebind mode no additional info is needed */ + search.bindpw = authdata->s; + attrs[7] = 0; + /* rebind on, check passwd via ldap rebind */ + } else { + extra[0].what = LDAP_PASSWD; /* need to get the crypted password */ + search.bindpw = 0; /* rebind off */ + } + extra[1].what = 0; /* end marker for extra info */ + + if ( !make_filter(login, &filter ) ) { + /* create search filter */ + log(4, "warning: check_ldap: could not make a filter\n"); + /* qldap_errno set by make_filter */ + return -1; + } + search.filter = filter.s; + + if ( (ret = qldap_open() ) != -1 ) { + ret = qldap_lookup(&search, attrs, &info, extra); + qldap_close(); + } + free_stralloc(&filter); /* free the old filter */ + if ( ret != 0 ) { + log(4, "warning: check_ldap: qldap_lookup not successful!\n"); + /* qldap_errno set by qldap_lookup */ + return -1; + } + /* check the status of the account !!! */ + if ( info.status == STATUS_BOUNCE || info.status == STATUS_NOPOP ) { + qldap_errno = ACC_DISABLED; + return -1; + } + +#ifdef QLDAP_CLUSTER + /* for cluster check if I'm on the right host */ + if ( cluster && info.host && + str_diff(qldap_me.s, info.host) && + !constmap(&qldap_mailhosts, info.host, str_len(info.host)) ) { + + /* hostname is different, so I reconnect */ + log(8, "check_ldap: forwarding session to %s\n", info.host); + forward_session(info.host, login->s, authdata->s); + /* that's it. Function does not return */ + } +#endif + + scan_ulong(info.uid, uid); /* get uid, gid and home */ + scan_ulong(info.gid, gid); /* the values are checked later */ + if ( info.mms == 0 && info.homedir == 0 ) { + qldap_errno = AUTH_FAILED; + return -1; /* user authentification failed no homedir defined */ + } + if ( info.homedir ) { + if ( ! stralloc_copys(home, info.homedir) ) { + qldap_errno = ERRNO; + return -1; + } + if ( info.mms ) { + if ( ! stralloc_copys(maildir, info.mms) ) { + qldap_errno = ERRNO; + return -1; + } + /* XXX have a look at check.c and qmail-ldap.h for chck_pathb */ + if ( !chck_pathb(maildir->s,maildir->len) ) { + log(2, "warning: check_ldap: path contains illegal chars!\n"); + qldap_errno = ILL_PATH; + return -1; + } + } + + } else { + if ( ! stralloc_copys(home, info.mms) ) { + qldap_errno = ERRNO; + return -1; + } + } + /* XXX have a look at check.c and qmail-ldap.h for chck_pathb */ + if ( !chck_pathb(home->s,home->len) ) { + log(2, "warning: check_ldap: path contains illegal chars!\n"); + qldap_errno = ILL_PATH; + return -1; + } + if (!stralloc_0(home) ) { + qldap_errno = ERRNO; + return -1; + } + if (!stralloc_0(maildir) ) { + qldap_errno = ERRNO; + return -1; + } + /* free a part of the info struct */ + alloc_free(info.user); + alloc_free(info.uid); + alloc_free(info.gid); + if (info.homedir) alloc_free(info.homedir); + if (info.mms) alloc_free(info.mms); + + if ( rebind && search.bind_ok ) { + log(32, + "check_ldap: qldap_lookup sucessfully authenticated with rebind\n"); + return 0; + /* if we got till here under rebind mode, the user is authenticated */ + } else if ( rebind ) { + log(32, + "check_ldap: qldap_lookup authentication failed with rebind\n"); + qldap_errno = AUTH_FAILED; + return -1; /* user authentification failed */ + } + + if ( ! extra[0].vals ) { + log(2, "warning: check_ldap: password is missing for uid %s\n", + login); + qldap_errno = AUTH_NEEDED; + return -1; + } + + ret = cmp_passwd((unsigned char*) authdata->s, extra[0].vals[0]); + log(32, "check_ldap: password compare was %s\n", + ret==0?"successful":"not successful"); + ldap_value_free(extra[0].vals); + return ret; +} + +static int check_passwd(stralloc *login, stralloc *authdata, unsigned long *uid, + unsigned long *gid, stralloc *home, stralloc *md) +{ + int ret; + struct passwd *pw; +#ifdef PW_SHADOW + struct spwd *spw; +#endif +#ifdef AIX + struct userpw *spw; +#endif + + pw = getpwnam(login->s); + if (!pw) { + /* XXX: unfortunately getpwnam() hides temporary errors */ + log(32, "check_passwd: user %s not found in passwd db\n", login->s); + qldap_errno = AUTH_NOSUCH; + return -1; + } + *gid = pw->pw_gid; + *uid = pw->pw_uid; + + /* here we don't check the home and maildir path, if a user has a faked + * passwd entry, then you have a bigger problem on your system than just + * a guy how can read the mail of other users/customers */ + if (!stralloc_copys(home, pw->pw_dir) ) { + qldap_errno = ERRNO; + return -1; + } + + if ( get_local_maildir(home, md) == -1 ) { + /* function sets qldap_errno */ + return -1; + } + log(32, "get_local_maildir: maildir=%s\n", md->s); + + if (!stralloc_0(home) ) { + qldap_errno = ERRNO; + auth_error(); + } + +#ifdef PW_SHADOW + spw = getspnam(login->s); + if (!spw) { + /* XXX: again, temp hidden */ + qldap_errno = AUTH_ERROR; + return -1; + } + ret = cmp_passwd((unsigned char*) authdata->s, spw->sp_pwdp); +#else /* no PW_SHADOW */ +#ifdef AIX + spw = getuserpw(login->s); + if (!spw) { + /* XXX: and again */ + qldap_errno = AUTH_ERROR; + return -1; + } + ret = cmp_passwd((unsigned char*) authdata->s, spw->upw_passwd); +#else /* no AIX */ + ret = cmp_passwd((unsigned char*) authdata->s, pw->pw_passwd); +#endif /* END AIX */ +#endif /* END PW_SHADOW */ + log(32, "check_pw: password compare was %s\n", + ret==0?"successful":"not successful"); + return ret; + +} + +static int cmp_passwd(unsigned char *clear, char *encrypted) +{ +#define HASH_LEN 100 /* XXX is this enough, I think yes */ + /* What do you think ? */ + char hashed[HASH_LEN]; /* these to buffers can not be used for exploits */ + char salt[33]; + int shift; + + if (encrypted[0] == '{') { /* hashed */ + if (!str_diffn("{crypt}", encrypted, 7) ) { + /* CRYPT */ + shift = 7; + str_copy(hashed, crypt(clear, encrypted+shift) ); + } else if (!str_diffn("{MD4}", encrypted, 5) ) { + /* MD4 */ + shift = 5; + MD4DataBase64(clear, str_len(clear), hashed, sizeof(hashed)); + } else if (!str_diffn("{MD5}", encrypted, 5) ) { + /* MD5 */ + shift = 5; + MD5DataBase64(clear, str_len(clear), hashed, sizeof(hashed)); + } else if (!str_diffn("{NS-MTA-MD5}", encrypted, 12) ) { + /* NS-MTA-MD5 */ + shift = 12; + if (!str_len(encrypted) == 76) { + qldap_errno = ILL_AUTH; + return -1; + } /* boom */ + byte_copy(salt, 32, &encrypted[44]); + salt[32] = 0; + if (ns_mta_hash_alg(hashed, salt, (char *) clear) == -1) { + qldap_errno = ERRNO; + return -1; + } + byte_copy(&hashed[32], 33, salt); + } else if (!str_diffn("{SHA}", encrypted, 5) ) { + /* SHA */ + shift = 5; + SHA1DataBase64(clear, str_len(clear), hashed, sizeof(hashed)); + } else if (!str_diffn("{RMD160}", encrypted, 8) ) { + /* RMD160 */ + shift = 8; + RMD160DataBase64(clear, str_len(clear), hashed, sizeof(hashed)); + } else { + /* unknown hash function detected */ + shift = 0; + qldap_errno = ILL_AUTH; + return -1; + } + /* End getting correct hash-func hashed */ + log(256, "cpm_passwd: comparing hashed passwd (%s == %s)\n", + hashed, encrypted); + if (!*encrypted || str_diff(hashed,encrypted+shift) ) { + qldap_errno = AUTH_FAILED; + return -1; + } + /* hashed passwds are equal */ + } else { /* crypt or clear text */ + log(256, "cpm_passwd: comparing standart passwd (%s == %s)\n", + crypt(clear,encrypted), encrypted); + if (!*encrypted || str_diff(encrypted, crypt(clear,encrypted) ) ) { + /* CLEARTEXTPASSWD ARE NOT GOOD */ + /* so they are disabled by default */ +#ifdef CLEARTEXTPASSWD +#warning ___CLEARTEXT_PASSWORD_SUPPORT_IS_ON___ + if (!*encrypted || str_diff(encrypted, clear) ) { +#endif + qldap_errno = AUTH_FAILED; + return -1; +#ifdef CLEARTEXTPASSWD + } +#endif + /* crypted or cleartext passwd ok */ + } + } /* end -- hashed or crypt/clear text */ + + return 0; + +} + +static int get_local_maildir(stralloc *home, stralloc *maildir) +{ + substdio ss; + stralloc dotqmail = {0}; + char buf[512]; + int match; + int fd; + + if ( ! stralloc_copy(&dotqmail, home) ) { + qldap_errno = ERRNO; + return -1; + } + if ( ! stralloc_cats(&dotqmail, "/.qmail") ) { + qldap_errno = ERRNO; + return -1; + } + if ( ! stralloc_0(&dotqmail) ) { + qldap_errno = ERRNO; + return -1; + } + + if ( ( fd = open_read(dotqmail.s) ) == -1 ) { + if ( errno == error_noent ) return 0; + qldap_errno = ERRNO; + return -1; + } + + substdio_fdbuf(&ss,read,fd,buf,sizeof(buf)); + while (1) { + if (getln(&ss,&dotqmail,&match,'\n') != 0) goto tryclose; + if (!match && !dotqmail.len) break; + if ( (dotqmail.s[0] == '.' || dotqmail.s[0] == '/') && + dotqmail.s[dotqmail.len-2] == '/' ) { /* is a maildir line ? */ + if ( ! stralloc_copy(maildir, &dotqmail) ) goto tryclose; + maildir->s[maildir->len-1] = '\0'; + break; + } + } + + close(fd); + for (match = 0; match<512; buf[match++]=0 ) ; /* trust nobody */ + free_stralloc(&dotqmail); + return 0; + +tryclose: + for (match = 0; match<512; buf[match++]=0 ) ; /* trust nobody */ + match = errno; /* preserve errno */ + close(fd); + free_stralloc(&dotqmail); + errno = match; + qldap_errno = ERRNO; + return -1; + +} + +#ifdef QLDAP_CLUSTER +static void copyloop(int infd, int outfd, int timeout) +{ + fd_set iofds; + fd_set savedfds; + int maxfd; /* Maximum numbered fd used */ + struct timeval tv; + unsigned long bytes; + char buf[4096]; /* very big buffer ethernet pkgs are normaly + around 1500 bytes long */ + + /* file descriptor bits */ + FD_ZERO(&savedfds); + FD_SET(infd, &savedfds); + FD_SET(outfd, &savedfds); + + if (infd > outfd) { + maxfd = infd; + } else { + maxfd = outfd; + } + + while(1) { + /* Set up timeout *//* because of LINUX this has to be done everytime */ + tv.tv_sec = timeout; + tv.tv_usec = 0; + + byte_copy(&iofds, sizeof(iofds), &savedfds); + + if ( select( maxfd + 1, &iofds, (fd_set *)0, (fd_set *)0, &tv) <= 0 ) { + break; + } + + if(FD_ISSET(infd, &iofds)) { + if((bytes = read(infd, buf, sizeof(buf))) <= 0) + break; + if(write(outfd, buf, bytes) != bytes) + break; + } + if(FD_ISSET(outfd, &iofds)) { + if((bytes = read(outfd, buf, sizeof(buf))) <= 0) + break; + if(write(infd, buf, bytes) != bytes) + break; + } + } + + shutdown(infd,0); + shutdown(outfd,0); + close(infd); + close(outfd); + for(bytes=0; bytes<4096; buf[bytes++] = 0 ) ; /* paranoia */ + return; +} + +static void forward_session(char *host, char *name, char *passwd) +{ + ipalloc ip = {0}; + stralloc host_stralloc = {0}; + int ffd; + int timeout = 31*60; /* ~30 min timeout RFC1730 */ + int ctimeout = 20; + + if (!stralloc_copys(&host_stralloc, host)) { + qldap_errno = ERRNO; + auth_error(); + } + + dns_init(0); + switch (dns_ip(&ip,&host_stralloc)) { + case DNS_MEM: + qldap_errno = ERRNO; + auth_error(); + case DNS_SOFT: + qldap_errno = BADCLUSTER; + auth_error(); + case DNS_HARD: + qldap_errno = BADCLUSTER; + auth_error(); + case 1: + if (ip.len <= 0) { + qldap_errno = BADCLUSTER; + auth_error(); + } + } +/* if ( ip.len != 1 ) { + qldap_errno = BADCLUSTER; + auth_error(); + } */ /* 20010523 do not check if only one IP is returned, so it is + possible to have a cluster node consisting of multiple machines + XXX if your mailhost is bad (bad entries in ldap) you will get + bad loops. + */ + + ffd = socket(AF_INET,SOCK_STREAM,0); + if (ffd == -1) { + qldap_errno = ERRNO; + auth_error(); + } + + if (timeoutconn(ffd, &ip.ix[0].ip, auth_port, ctimeout) != 0) { + qldap_errno = ERRNO; + auth_error(); + } + + /* We have a connection, first send user and pass */ + auth_forward(ffd, name, passwd); + copyloop(0, ffd, timeout); + + _exit(0); /* all went ok, exit normaly */ + +} +#endif /* QLDAP_CLUSTER */ + +static int make_filter(stralloc *value, stralloc *filter) +/* create a searchfilter, "(uid=VALUE)" */ +{ + stralloc tmp = {0}; + + + if ( !stralloc_copy(&tmp, value) ) { + qldap_errno = ERRNO; + return 0; + } + if ( !escape_forldap(&tmp) ) { + qldap_errno = ERRNO; + return 0; + } + if ( !stralloc_copys(filter,"(" ) ) { + qldap_errno = ERRNO; + return 0; + } + if ( qldap_objectclass.len && ( + !stralloc_cats(filter,"&(" ) || + !stralloc_cats(filter,LDAP_OBJECTCLASS) || + !stralloc_cats(filter,"=") || + !stralloc_cat(filter,&qldap_objectclass) || + !stralloc_cats(filter,")(") ) ) { + qldap_errno = ERRNO; + return 0; + } + if ( !stralloc_cats(filter, LDAP_UID) || + !stralloc_cats(filter, "=") || + !stralloc_cat(filter, &tmp) || + !stralloc_cats(filter, ")") ) { + qldap_errno = ERRNO; + return 0; + } + if ( qldap_objectclass.len && + !stralloc_cats(filter,")") ) { + qldap_errno = ERRNO; + return 0; + } + if ( !stralloc_0(filter) ) { + qldap_errno = ERRNO; + return 0; + } + free_stralloc(&tmp); + return 1; +} + +static void free_stralloc(stralloc* sa) +{ + alloc_free(sa->s); + sa->s = 0; + return; +} + diff -uN qmail-1.03/chkspawn.c qmail-ldap/chkspawn.c --- qmail-1.03/chkspawn.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/chkspawn.c Sat Jan 15 14:38:12 2000 @@ -22,8 +22,8 @@ _exit(1); } - if (auto_spawn > 255) { - substdio_puts(subfderr,"Oops. You have set conf-spawn higher than 255.\n"); + if (auto_spawn > 65000) { + substdio_puts(subfderr,"Oops. You have set conf-spawn higher than 65000.\n"); substdio_flush(subfderr); _exit(1); } diff -uN qmail-1.03/conf-spawn qmail-ldap/conf-spawn --- qmail-1.03/conf-spawn Mon Jun 15 12:53:16 1998 +++ qmail-ldap/conf-spawn Sun Jan 16 13:52:14 2000 @@ -1,4 +1,4 @@ -120 +500 This is a silent concurrency limit. You can't set it above 255. On some systems you can't set it above 125. qmail will refuse to compile if the diff -uN qmail-1.03/digest.c qmail-ldap/digest.c --- qmail-1.03/digest.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/digest.c Fri Apr 20 21:35:43 2001 @@ -0,0 +1,32 @@ +/* Who knows? */ + +#include +#include +#include "digest_md4.h" +#include "digest_md5.h" +#include "digest_rmd160.h" +#include "digest_sha1.h" + +int main(int argc, char *argv[]) +{ + char buffer[100]; + + if (argc == 2) { + MD4DataBase64((unsigned char *) argv[1],strlen(argv[1]),buffer,sizeof(buffer)); + printf("{MD4}%s\n",buffer); + + MD5DataBase64((unsigned char *) argv[1],strlen(argv[1]),buffer,sizeof(buffer)); + printf("{MD5}%s\n",buffer); + + RMD160DataBase64((unsigned char *) argv[1],strlen(argv[1]),buffer,sizeof(buffer)); + printf("{RMD160}%s\n",buffer); + + SHA1DataBase64((unsigned char *) argv[1],strlen(argv[1]),buffer,sizeof(buffer)); + printf("{SHA}%s\n",buffer); + + exit(0); + } else { + printf("Only one Parameter\n"); + exit(1); + } +} diff -uN qmail-1.03/digest_md4.c qmail-ldap/digest_md4.c --- qmail-1.03/digest_md4.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/digest_md4.c Fri May 4 20:58:42 2001 @@ -0,0 +1,367 @@ +/* digest_md4.c for QLDAP modified to use djb stuff */ +/* contains MD4 algorithm stolen directly from OpenBSD */ + +/* */ +/* MD4 */ +/* */ + +/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD4 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD4 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + */ + +#include +#include "uint32.h" +#include "byte.h" +#include "digest_md4.h" +#include "base64.h" + +/* some systems don't have NULL defined */ +#ifndef NULL +#define NULL (void*) 0 +#endif + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* Constants for MD4Transform routine. + */ +#define S11 3 +#define S12 7 +#define S13 11 +#define S14 19 +#define S21 3 +#define S22 5 +#define S23 9 +#define S24 13 +#define S31 3 +#define S32 9 +#define S33 11 +#define S34 15 + +static void MD4Transform (); + +#ifdef __LITTLE_ENDIAN__ +#define Encode byte_copy +#define Decode byte_copy +#else /* __BIG_ENDIAN__ */ +static void Encode (); +static void Decode (); +#endif /* __LITTLE_ENDIAN__ */ + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G and H are basic MD4 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG and HH are transformations for rounds 1, 2 and 3 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s) { \ + (a) += F ((b), (c), (d)) + (x); \ + (a) = ROTATE_LEFT ((a), (s)); \ + } +#define GG(a, b, c, d, x, s) { \ + (a) += G ((b), (c), (d)) + (x) + (uint32)0x5a827999; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } +#define HH(a, b, c, d, x, s) { \ + (a) += H ((b), (c), (d)) + (x) + (uint32)0x6ed9eba1; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } + +#ifdef __BIG_ENDIAN__ +/* Encodes input (uint32) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (out, len, in) +void *out; +size_t len; +const void *in; +{ + const uint32 *input = in; + unsigned char *output = out; + size_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (uint32). Assumes len is + a multiple of 4. + */ +static void Decode (out, len, in) +void *out; +size_t len; +const void *in; +{ + uint32 *output = out; + const unsigned char *input = in; + size_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint32)input[j]) | (((uint32)input[j+1]) << 8) | + (((uint32)input[j+2]) << 16) | (((uint32)input[j+3]) << 24); +} +#endif /* __BIG_ENDIAN__ */ + +/* MD4 initialization. Begins an MD4 operation, writing a new context. + */ +void MD4Init (context) +MD4_CTX *context; /* context */ +{ + context->count[0] = 0; + context->count[1] = 0; + + /* Load magic initialization constants. + */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD4 block update operation. Continues an MD4 message-digest + operation, processing another message block, and updating the + context. + */ +void MD4Update (context, input, inputLen) +MD4_CTX *context; /* context */ +const unsigned char *input; /* input block */ +size_t inputLen; /* length of input block */ +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ( (context->count[0] += ((uint32)inputLen << 3)) /* lower part of count */ + < ((uint32)inputLen << 3) ) + context->count[1]++; /* low part of count overflowed */ + + context->count[1] += ((uint32)inputLen >> 29); /* update high part of count */ + + partLen = 64 - index; + /* Transform as many times as possible. */ + if (inputLen >= partLen) { + byte_copy + ((POINTER)&context->buffer[index], partLen, (POINTER)input); + MD4Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD4Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + byte_copy + ((POINTER)&context->buffer[index], inputLen-i, (POINTER)&input[i]); +} + +/* MD4 finalization. Ends an MD4 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void MD4Final (digest, context) +unsigned char digest[16]; /* message digest */ +MD4_CTX *context; /* context */ +{ + unsigned char bits[8]; + unsigned int index, padLen; + uint32 hi, lo; + + /* Save number of bits */ + hi = context->count[1]; + lo = context->count[0]; + Encode (bits, 4, &lo); + Encode (bits + 4, 4, &hi); + + /* Pad out to 56 mod 64. + */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD4Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD4Update (context, bits, 8); + + if (digest != NULL) { + /* Store state in digest */ + Encode (digest, 16, context->state); + + /* Zeroize sensitive information. + */ + byte_zero((POINTER) context, sizeof (*context)); + } +} + +/* MD4 basic transformation. Transforms state based on block. + */ +static void MD4Transform (state, block) +uint32 state[4]; +const unsigned char block[64]; +{ + uint32 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, 64, block); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11); /* 1 */ + FF (d, a, b, c, x[ 1], S12); /* 2 */ + FF (c, d, a, b, x[ 2], S13); /* 3 */ + FF (b, c, d, a, x[ 3], S14); /* 4 */ + FF (a, b, c, d, x[ 4], S11); /* 5 */ + FF (d, a, b, c, x[ 5], S12); /* 6 */ + FF (c, d, a, b, x[ 6], S13); /* 7 */ + FF (b, c, d, a, x[ 7], S14); /* 8 */ + FF (a, b, c, d, x[ 8], S11); /* 9 */ + FF (d, a, b, c, x[ 9], S12); /* 10 */ + FF (c, d, a, b, x[10], S13); /* 11 */ + FF (b, c, d, a, x[11], S14); /* 12 */ + FF (a, b, c, d, x[12], S11); /* 13 */ + FF (d, a, b, c, x[13], S12); /* 14 */ + FF (c, d, a, b, x[14], S13); /* 15 */ + FF (b, c, d, a, x[15], S14); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 0], S21); /* 17 */ + GG (d, a, b, c, x[ 4], S22); /* 18 */ + GG (c, d, a, b, x[ 8], S23); /* 19 */ + GG (b, c, d, a, x[12], S24); /* 20 */ + GG (a, b, c, d, x[ 1], S21); /* 21 */ + GG (d, a, b, c, x[ 5], S22); /* 22 */ + GG (c, d, a, b, x[ 9], S23); /* 23 */ + GG (b, c, d, a, x[13], S24); /* 24 */ + GG (a, b, c, d, x[ 2], S21); /* 25 */ + GG (d, a, b, c, x[ 6], S22); /* 26 */ + GG (c, d, a, b, x[10], S23); /* 27 */ + GG (b, c, d, a, x[14], S24); /* 28 */ + GG (a, b, c, d, x[ 3], S21); /* 29 */ + GG (d, a, b, c, x[ 7], S22); /* 30 */ + GG (c, d, a, b, x[11], S23); /* 31 */ + GG (b, c, d, a, x[15], S24); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 0], S31); /* 33 */ + HH (d, a, b, c, x[ 8], S32); /* 34 */ + HH (c, d, a, b, x[ 4], S33); /* 35 */ + HH (b, c, d, a, x[12], S34); /* 36 */ + HH (a, b, c, d, x[ 2], S31); /* 37 */ + HH (d, a, b, c, x[10], S32); /* 38 */ + HH (c, d, a, b, x[ 6], S33); /* 39 */ + HH (b, c, d, a, x[14], S34); /* 40 */ + HH (a, b, c, d, x[ 1], S31); /* 41 */ + HH (d, a, b, c, x[ 9], S32); /* 42 */ + HH (c, d, a, b, x[ 5], S33); /* 43 */ + HH (b, c, d, a, x[13], S34); /* 44 */ + HH (a, b, c, d, x[ 3], S31); /* 45 */ + HH (d, a, b, c, x[11], S32); /* 46 */ + HH (c, d, a, b, x[ 7], S33); /* 47 */ + HH (b, c, d, a, x[15], S34); /* 48 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. + */ + byte_zero((POINTER) x, sizeof (x)); +} + +/* mdXhl.c + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + */ + +/* ARGSUSED */ +char * +MD4End(ctx, buf) + MD4_CTX *ctx; + char *buf; /* buf needs to be 33 bytes big */ +{ + int i; + char *p = buf; + unsigned char digest[16]; + static const char hex[]="0123456789abcdef"; + + if (!p) + return 0; + MD4Final(digest,ctx); + for (i=0;i<16;i++) { + p[i+i] = hex[digest[i] >> 4]; + p[i+i+1] = hex[digest[i] & 0x0f]; + } + p[i+i] = '\0'; + return p; +} + +char * +MD4Data (data, len, buf) + const unsigned char *data; + size_t len; + char *buf; /* buf needs to be 33 bytes big */ +{ + MD4_CTX ctx; + + MD4Init(&ctx); + MD4Update(&ctx,data,len); + return MD4End(&ctx, buf); +} + +/* Base 64 */ + +char * +MD4DataBase64 (data, len, buf, buflen) + const unsigned char *data; + size_t len; + char *buf; /* buf needs to be 25 bytes big */ + size_t buflen; +{ + MD4_CTX ctx; + unsigned char buffer[16]; + + MD4Init(&ctx); + MD4Update(&ctx, data, len); + MD4Final(buffer,&ctx); + b64_ntop(buffer,sizeof(buffer),buf,buflen); + return(buf); +} + diff -uN qmail-1.03/digest_md4.h qmail-ldap/digest_md4.h --- qmail-1.03/digest_md4.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/digest_md4.h Fri Apr 20 21:35:43 2001 @@ -0,0 +1,47 @@ +/* digest_md4.h for QLDAP modified to use djb's stuff */ + +/* */ +/* MD4 */ +/* */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD4 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD4 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. */ + +#ifndef _MD4_H_ +#define _MD4_H_ + +#include "uint32.h" + +/* MD4 context. */ +typedef struct MD4Context { + uint32 state[4]; /* state (ABCD) */ + uint32 count[2]; /* number of bits, modulo 2^64 */ + unsigned char buffer[64]; /* input buffer */ +} MD4_CTX; + +void MD4Init (); +void MD4Update (); +void MD4Final (); +char *MD4End (); +char *MD4Data (); + +char *MD4DataBase64 (); + +#endif /* _MD4_H_ */ diff -uN qmail-1.03/digest_md5.c qmail-ldap/digest_md5.c --- qmail-1.03/digest_md5.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/digest_md5.c Tue Sep 4 00:19:34 2001 @@ -0,0 +1,471 @@ +/* digest_md5.c for QLDAP modified to use djb's stuff */ +/* contains MD5 algorithm stolen directly from OpenBSD */ + +/* */ +/* MD5 */ +/* */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +#include +#include "uint32.h" +#include "byte.h" +#include "digest_md5.h" +#include "base64.h" +#include "stralloc.h" +#include "str.h" + +/* some systems don't have NULL defined */ +#ifndef NULL +#define NULL (void*) 0 +#endif + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* Constants for MD5Transform routine. + */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform (); + +#ifdef __LITTLE_ENDIAN__ +#define Encode byte_copy +#define Decode byte_copy +#else /* __BIG_ENDIAN__ */ +static void Encode (); +static void Decode (); +#endif /* __LITTLE_ENDIAN__ */ + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +#ifdef __BIG_ENDIAN__ +/* Encodes input (uint32) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (out, len, in) +void *out; +size_t len; +const void *in; +{ + unsigned char *output = out; + size_t i, j; + const uint32 *input = in; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (uint32). Assumes len is + a multiple of 4. + */ +static void Decode (out, len, in) +void *out; +size_t len; +const void *in; +{ + uint32 *output = out; + const unsigned char *input = in; + size_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint32)input[j]) | (((uint32)input[j+1]) << 8) | + (((uint32)input[j+2]) << 16) | (((uint32)input[j+3]) << 24); +} +#endif /* __BIG_ENDIAN__ */ + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void MD5Init (context) +MD5_CTX *context; /* context */ +{ + context->count[0] = 0; + context->count[1] = 0; + + /* Load magic initialization constants. */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void MD5Update (context, input, inputLen) +MD5_CTX *context; /* context */ +const unsigned char *input; /* input block */ +size_t inputLen; /* length of input block */ +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ( (context->count[0] += ((uint32)inputLen << 3)) /* lower part of count */ + < ((uint32)inputLen << 3) ) + context->count[1]++; /* low part of count overflowed */ + + context->count[1] += ((uint32)inputLen >> 29); /* update high part of count */ + + partLen = 64 - index; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) { + byte_copy ((POINTER)&context->buffer[index], partLen, (POINTER)input); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + byte_copy ((POINTER)&context->buffer[index], inputLen-i, (POINTER)&input[i]); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void MD5Final (digest, context) +unsigned char digest[16]; /* message digest */ +MD5_CTX *context; /* context */ +{ + unsigned char bits[8]; + unsigned int index; + size_t padLen; + uint32 hi, lo; + + /* Save number of bits */ + hi = context->count[1]; + lo = context->count[0]; + Encode (bits, 4, &lo); + Encode (bits + 4, 4, &hi); + + /* Pad out to 56 mod 64. */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + if (digest != NULL) { + /* Store state in digest */ + Encode (digest, 16, context->state); + + /* Zeroize sensitive information. */ + byte_zero ((POINTER)context, sizeof (*context)); + } +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (state, block) +uint32 state[4]; +const unsigned char block[64]; +{ + uint32 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, 64, block); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + byte_zero ((POINTER)x, sizeof (x)); +} + +/* mdXhl.c + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + */ + +/* ARGSUSED */ +char * +MD5End(ctx, buf) + MD5_CTX *ctx; + char *buf; +{ + int i; + char *p = buf; + unsigned char digest[16]; + static const char hex[]="0123456789abcdef"; + + if (!p) + return 0; + MD5Final(digest,ctx); + for (i=0;i<16;i++) { + p[i+i] = hex[digest[i] >> 4]; + p[i+i+1] = hex[digest[i] & 0x0f]; + } + p[i+i] = '\0'; + return p; +} + +char * +MD5Data (data, len, buf) + const unsigned char *data; + size_t len; + char *buf; /* XXX buf needs to be at least 33 Bytes big. */ +{ + MD5_CTX ctx; + + MD5Init(&ctx); + MD5Update(&ctx,data,len); + return MD5End(&ctx, buf); +} + +/* Base 64 */ + +char * +MD5DataBase64 (data, len, buf, buflen) + const unsigned char *data; + size_t len; + char *buf; /* needs to be 25 Bytes big */ + size_t buflen; +{ + MD5_CTX ctx; + unsigned char buffer[16]; + + MD5Init(&ctx); + MD5Update(&ctx, data, len); + MD5Final(buffer,&ctx); + b64_ntop(buffer,sizeof(buffer),buf,buflen); + return(buf); +} + +/* Netscape MTA MD5 as found in Netscape MailServer < 2.02 and Software.com's + Post.Office */ + +/* XXX this Netscape MTA MD5 implementation is absolutly ugly. I fixed the + possible buffer overflows, but this does not mean it is perfect + Claudio Jeker jeker@n-r-g.com */ + +static char * ns_mta_hextab = "0123456789abcdef"; + +static void +ns_mta_hexify(char *buffer, char *str, int len) +/* normaly we should also tell the size of the buffer, this is implicitly done + buffer is enough great to hold the 32 hexchars (sizeof(buffer) == 65) */ +{ + char *pch = str; + char ch; + int i; + + for(i = 0;i < len; i ++) { + ch = pch[i]; + buffer[2*i] = ns_mta_hextab[(ch>>4)&0xF]; + buffer[2*i+1] = ns_mta_hextab[ch&0xF]; + } + + return; +} + +int +ns_mta_hash_alg(char *buffer, char *salt, char *passwd) +{ + MD5_CTX context; + stralloc saltstr = {0}; + unsigned char digest[16], c; + + if (!stralloc_copys(&saltstr, salt) ) return -1; /* errno set by stralloc */ + c = 89; + if (!stralloc_append(&saltstr, &c) ) return -1; + if (!stralloc_cats(&saltstr, passwd) ) return -1; + c = 247; + if (!stralloc_append(&saltstr, &c) ) return -1; + if (!stralloc_cats(&saltstr, salt) ) return -1; + /* the stralloc is not freed so we loose some memory (until exit) but + this is better than the possible root exploit that was in the code before + */ + + MD5Init(&context); + MD5Update(&context,(unsigned char *)saltstr.s,saltstr.len); + MD5Final(digest,&context); + ns_mta_hexify(buffer,(char*)digest,16); + buffer[32] = '\0'; + return 0; +} + +int +ns_mta_md5_cmp_pw(char * clear, char *mangled) +{ + char mta_hash[33]; + char mta_salt[33]; + char buffer[65]; + int match; + + if ( str_len(mangled) != 64 ) return -1; /* XXX is this correct ??? */ + + byte_copy(mta_hash,32,mangled); + byte_copy(mta_salt,32,&mangled[32]); + + mta_hash[32] = mta_salt[32] = 0; + if ( ns_mta_hash_alg(buffer,mta_salt,clear) ) return -1; + match = str_diffn(mta_hash,buffer, 32); + + return(match); +} + diff -uN qmail-1.03/digest_md5.h qmail-ldap/digest_md5.h --- qmail-1.03/digest_md5.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/digest_md5.h Fri Apr 20 21:35:43 2001 @@ -0,0 +1,52 @@ +/* digest_md5.h for QLDAP modified to use djb's stuff */ + +/* */ +/* MD5 */ +/* */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +#ifndef _MD5_H_ +#define _MD5_H_ + +#include "uint32.h" + +/* MD5 context. */ +typedef struct MD5Context { + uint32 state[4]; /* state (ABCD) */ + uint32 count[2]; /* number of bits, modulo 2^64 */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void MD5Init (); +void MD5Update (); +void MD5Final (); +char *MD5End (); +char *MD5Data (); + +char *MD5DataBase64 (); + +int ns_mta_hash_alg(); +int ns_mta_md5_cmp_pw(); + +#endif /* _MD5_H_ */ diff -uN qmail-1.03/digest_rmd160.c qmail-ldap/digest_rmd160.c --- qmail-1.03/digest_rmd160.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/digest_rmd160.c Fri Apr 20 21:35:43 2001 @@ -0,0 +1,487 @@ +/* digest_rmd160.c for QLDAP checkpassword.c */ +/* contains RMD160 algorithm stolen directly from OpenBSD */ + +/* */ +/* RMD160 */ +/* */ + +/********************************************************************\ + * + * FILE: rmd160.c + * + * CONTENTS: A sample C-implementation of the RIPEMD-160 + * hash-function. + * TARGET: any computer with an ANSI C compiler + * + * AUTHOR: Antoon Bosselaers, ESAT-COSIC + * (Arranged for libc by Todd C. Miller) + * DATE: 1 March 1996 + * VERSION: 1.0 + * + * Copyright (c) Katholieke Universiteit Leuven + * 1996, All Rights Reserved + * +\********************************************************************/ + +/* header files */ +#include +#include "uint32.h" +#include "byte.h" +#include "digest_rmd160.h" +#include "base64.h" + +/* some systems don't have NULL defined */ +#ifndef NULL +#define NULL (void*) 0 +#endif + +/* macro definitions */ + +/* collect four bytes into one word: */ +#define BYTES_TO_DWORD(strptr) \ + (((uint32) *((strptr)+3) << 24) | \ + ((uint32) *((strptr)+2) << 16) | \ + ((uint32) *((strptr)+1) << 8) | \ + ((uint32) *(strptr))) + +/* ROL(x, n) cyclically rotates x over n bits to the left */ +/* x must be of an unsigned 32 bits type and 0 <= n < 32. */ +#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* the three basic functions F(), G() and H() */ +#define F(x, y, z) ((x) ^ (y) ^ (z)) +#define G(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define H(x, y, z) (((x) | ~(y)) ^ (z)) +#define I(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define J(x, y, z) ((x) ^ ((y) | ~(z))) + +/* the eight basic operations FF() through III() */ +#define FF(a, b, c, d, e, x, s) { \ + (a) += F((b), (c), (d)) + (x); \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} +#define GG(a, b, c, d, e, x, s) { \ + (a) += G((b), (c), (d)) + (x) + 0x5a827999U; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} +#define HH(a, b, c, d, e, x, s) { \ + (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1U; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} +#define II(a, b, c, d, e, x, s) { \ + (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcU; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} +#define JJ(a, b, c, d, e, x, s) { \ + (a) += J((b), (c), (d)) + (x) + 0xa953fd4eU; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} +#define FFF(a, b, c, d, e, x, s) { \ + (a) += F((b), (c), (d)) + (x); \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} +#define GGG(a, b, c, d, e, x, s) { \ + (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9U; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} +#define HHH(a, b, c, d, e, x, s) { \ + (a) += H((b), (c), (d)) + (x) + 0x6d703ef3U; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} +#define III(a, b, c, d, e, x, s) { \ + (a) += I((b), (c), (d)) + (x) + 0x5c4dd124U; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} +#define JJJ(a, b, c, d, e, x, s) { \ + (a) += J((b), (c), (d)) + (x) + 0x50a28be6U; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} + +void RMD160Init(context) + RMD160_CTX *context; +{ + + /* ripemd-160 initialization constants */ + context->state[0] = 0x67452301U; + context->state[1] = 0xefcdab89U; + context->state[2] = 0x98badcfeU; + context->state[3] = 0x10325476U; + context->state[4] = 0xc3d2e1f0U; + context->length[0] = context->length[1] = 0; + context->buflen = 0; +} + +void RMD160Transform(state, block) + uint32 state[5]; + const uint32 block[16]; +{ + uint32 aa = state[0], bb = state[1], cc = state[2], + dd = state[3], ee = state[4]; + uint32 aaa = state[0], bbb = state[1], ccc = state[2], + ddd = state[3], eee = state[4]; + + /* round 1 */ + FF(aa, bb, cc, dd, ee, block[ 0], 11); + FF(ee, aa, bb, cc, dd, block[ 1], 14); + FF(dd, ee, aa, bb, cc, block[ 2], 15); + FF(cc, dd, ee, aa, bb, block[ 3], 12); + FF(bb, cc, dd, ee, aa, block[ 4], 5); + FF(aa, bb, cc, dd, ee, block[ 5], 8); + FF(ee, aa, bb, cc, dd, block[ 6], 7); + FF(dd, ee, aa, bb, cc, block[ 7], 9); + FF(cc, dd, ee, aa, bb, block[ 8], 11); + FF(bb, cc, dd, ee, aa, block[ 9], 13); + FF(aa, bb, cc, dd, ee, block[10], 14); + FF(ee, aa, bb, cc, dd, block[11], 15); + FF(dd, ee, aa, bb, cc, block[12], 6); + FF(cc, dd, ee, aa, bb, block[13], 7); + FF(bb, cc, dd, ee, aa, block[14], 9); + FF(aa, bb, cc, dd, ee, block[15], 8); + + /* round 2 */ + GG(ee, aa, bb, cc, dd, block[ 7], 7); + GG(dd, ee, aa, bb, cc, block[ 4], 6); + GG(cc, dd, ee, aa, bb, block[13], 8); + GG(bb, cc, dd, ee, aa, block[ 1], 13); + GG(aa, bb, cc, dd, ee, block[10], 11); + GG(ee, aa, bb, cc, dd, block[ 6], 9); + GG(dd, ee, aa, bb, cc, block[15], 7); + GG(cc, dd, ee, aa, bb, block[ 3], 15); + GG(bb, cc, dd, ee, aa, block[12], 7); + GG(aa, bb, cc, dd, ee, block[ 0], 12); + GG(ee, aa, bb, cc, dd, block[ 9], 15); + GG(dd, ee, aa, bb, cc, block[ 5], 9); + GG(cc, dd, ee, aa, bb, block[ 2], 11); + GG(bb, cc, dd, ee, aa, block[14], 7); + GG(aa, bb, cc, dd, ee, block[11], 13); + GG(ee, aa, bb, cc, dd, block[ 8], 12); + + /* round 3 */ + HH(dd, ee, aa, bb, cc, block[ 3], 11); + HH(cc, dd, ee, aa, bb, block[10], 13); + HH(bb, cc, dd, ee, aa, block[14], 6); + HH(aa, bb, cc, dd, ee, block[ 4], 7); + HH(ee, aa, bb, cc, dd, block[ 9], 14); + HH(dd, ee, aa, bb, cc, block[15], 9); + HH(cc, dd, ee, aa, bb, block[ 8], 13); + HH(bb, cc, dd, ee, aa, block[ 1], 15); + HH(aa, bb, cc, dd, ee, block[ 2], 14); + HH(ee, aa, bb, cc, dd, block[ 7], 8); + HH(dd, ee, aa, bb, cc, block[ 0], 13); + HH(cc, dd, ee, aa, bb, block[ 6], 6); + HH(bb, cc, dd, ee, aa, block[13], 5); + HH(aa, bb, cc, dd, ee, block[11], 12); + HH(ee, aa, bb, cc, dd, block[ 5], 7); + HH(dd, ee, aa, bb, cc, block[12], 5); + + /* round 4 */ + II(cc, dd, ee, aa, bb, block[ 1], 11); + II(bb, cc, dd, ee, aa, block[ 9], 12); + II(aa, bb, cc, dd, ee, block[11], 14); + II(ee, aa, bb, cc, dd, block[10], 15); + II(dd, ee, aa, bb, cc, block[ 0], 14); + II(cc, dd, ee, aa, bb, block[ 8], 15); + II(bb, cc, dd, ee, aa, block[12], 9); + II(aa, bb, cc, dd, ee, block[ 4], 8); + II(ee, aa, bb, cc, dd, block[13], 9); + II(dd, ee, aa, bb, cc, block[ 3], 14); + II(cc, dd, ee, aa, bb, block[ 7], 5); + II(bb, cc, dd, ee, aa, block[15], 6); + II(aa, bb, cc, dd, ee, block[14], 8); + II(ee, aa, bb, cc, dd, block[ 5], 6); + II(dd, ee, aa, bb, cc, block[ 6], 5); + II(cc, dd, ee, aa, bb, block[ 2], 12); + + /* round 5 */ + JJ(bb, cc, dd, ee, aa, block[ 4], 9); + JJ(aa, bb, cc, dd, ee, block[ 0], 15); + JJ(ee, aa, bb, cc, dd, block[ 5], 5); + JJ(dd, ee, aa, bb, cc, block[ 9], 11); + JJ(cc, dd, ee, aa, bb, block[ 7], 6); + JJ(bb, cc, dd, ee, aa, block[12], 8); + JJ(aa, bb, cc, dd, ee, block[ 2], 13); + JJ(ee, aa, bb, cc, dd, block[10], 12); + JJ(dd, ee, aa, bb, cc, block[14], 5); + JJ(cc, dd, ee, aa, bb, block[ 1], 12); + JJ(bb, cc, dd, ee, aa, block[ 3], 13); + JJ(aa, bb, cc, dd, ee, block[ 8], 14); + JJ(ee, aa, bb, cc, dd, block[11], 11); + JJ(dd, ee, aa, bb, cc, block[ 6], 8); + JJ(cc, dd, ee, aa, bb, block[15], 5); + JJ(bb, cc, dd, ee, aa, block[13], 6); + + /* parallel round 1 */ + JJJ(aaa, bbb, ccc, ddd, eee, block[ 5], 8); + JJJ(eee, aaa, bbb, ccc, ddd, block[14], 9); + JJJ(ddd, eee, aaa, bbb, ccc, block[ 7], 9); + JJJ(ccc, ddd, eee, aaa, bbb, block[ 0], 11); + JJJ(bbb, ccc, ddd, eee, aaa, block[ 9], 13); + JJJ(aaa, bbb, ccc, ddd, eee, block[ 2], 15); + JJJ(eee, aaa, bbb, ccc, ddd, block[11], 15); + JJJ(ddd, eee, aaa, bbb, ccc, block[ 4], 5); + JJJ(ccc, ddd, eee, aaa, bbb, block[13], 7); + JJJ(bbb, ccc, ddd, eee, aaa, block[ 6], 7); + JJJ(aaa, bbb, ccc, ddd, eee, block[15], 8); + JJJ(eee, aaa, bbb, ccc, ddd, block[ 8], 11); + JJJ(ddd, eee, aaa, bbb, ccc, block[ 1], 14); + JJJ(ccc, ddd, eee, aaa, bbb, block[10], 14); + JJJ(bbb, ccc, ddd, eee, aaa, block[ 3], 12); + JJJ(aaa, bbb, ccc, ddd, eee, block[12], 6); + + /* parallel round 2 */ + III(eee, aaa, bbb, ccc, ddd, block[ 6], 9); + III(ddd, eee, aaa, bbb, ccc, block[11], 13); + III(ccc, ddd, eee, aaa, bbb, block[ 3], 15); + III(bbb, ccc, ddd, eee, aaa, block[ 7], 7); + III(aaa, bbb, ccc, ddd, eee, block[ 0], 12); + III(eee, aaa, bbb, ccc, ddd, block[13], 8); + III(ddd, eee, aaa, bbb, ccc, block[ 5], 9); + III(ccc, ddd, eee, aaa, bbb, block[10], 11); + III(bbb, ccc, ddd, eee, aaa, block[14], 7); + III(aaa, bbb, ccc, ddd, eee, block[15], 7); + III(eee, aaa, bbb, ccc, ddd, block[ 8], 12); + III(ddd, eee, aaa, bbb, ccc, block[12], 7); + III(ccc, ddd, eee, aaa, bbb, block[ 4], 6); + III(bbb, ccc, ddd, eee, aaa, block[ 9], 15); + III(aaa, bbb, ccc, ddd, eee, block[ 1], 13); + III(eee, aaa, bbb, ccc, ddd, block[ 2], 11); + + /* parallel round 3 */ + HHH(ddd, eee, aaa, bbb, ccc, block[15], 9); + HHH(ccc, ddd, eee, aaa, bbb, block[ 5], 7); + HHH(bbb, ccc, ddd, eee, aaa, block[ 1], 15); + HHH(aaa, bbb, ccc, ddd, eee, block[ 3], 11); + HHH(eee, aaa, bbb, ccc, ddd, block[ 7], 8); + HHH(ddd, eee, aaa, bbb, ccc, block[14], 6); + HHH(ccc, ddd, eee, aaa, bbb, block[ 6], 6); + HHH(bbb, ccc, ddd, eee, aaa, block[ 9], 14); + HHH(aaa, bbb, ccc, ddd, eee, block[11], 12); + HHH(eee, aaa, bbb, ccc, ddd, block[ 8], 13); + HHH(ddd, eee, aaa, bbb, ccc, block[12], 5); + HHH(ccc, ddd, eee, aaa, bbb, block[ 2], 14); + HHH(bbb, ccc, ddd, eee, aaa, block[10], 13); + HHH(aaa, bbb, ccc, ddd, eee, block[ 0], 13); + HHH(eee, aaa, bbb, ccc, ddd, block[ 4], 7); + HHH(ddd, eee, aaa, bbb, ccc, block[13], 5); + + /* parallel round 4 */ + GGG(ccc, ddd, eee, aaa, bbb, block[ 8], 15); + GGG(bbb, ccc, ddd, eee, aaa, block[ 6], 5); + GGG(aaa, bbb, ccc, ddd, eee, block[ 4], 8); + GGG(eee, aaa, bbb, ccc, ddd, block[ 1], 11); + GGG(ddd, eee, aaa, bbb, ccc, block[ 3], 14); + GGG(ccc, ddd, eee, aaa, bbb, block[11], 14); + GGG(bbb, ccc, ddd, eee, aaa, block[15], 6); + GGG(aaa, bbb, ccc, ddd, eee, block[ 0], 14); + GGG(eee, aaa, bbb, ccc, ddd, block[ 5], 6); + GGG(ddd, eee, aaa, bbb, ccc, block[12], 9); + GGG(ccc, ddd, eee, aaa, bbb, block[ 2], 12); + GGG(bbb, ccc, ddd, eee, aaa, block[13], 9); + GGG(aaa, bbb, ccc, ddd, eee, block[ 9], 12); + GGG(eee, aaa, bbb, ccc, ddd, block[ 7], 5); + GGG(ddd, eee, aaa, bbb, ccc, block[10], 15); + GGG(ccc, ddd, eee, aaa, bbb, block[14], 8); + + /* parallel round 5 */ + FFF(bbb, ccc, ddd, eee, aaa, block[12] , 8); + FFF(aaa, bbb, ccc, ddd, eee, block[15] , 5); + FFF(eee, aaa, bbb, ccc, ddd, block[10] , 12); + FFF(ddd, eee, aaa, bbb, ccc, block[ 4] , 9); + FFF(ccc, ddd, eee, aaa, bbb, block[ 1] , 12); + FFF(bbb, ccc, ddd, eee, aaa, block[ 5] , 5); + FFF(aaa, bbb, ccc, ddd, eee, block[ 8] , 14); + FFF(eee, aaa, bbb, ccc, ddd, block[ 7] , 6); + FFF(ddd, eee, aaa, bbb, ccc, block[ 6] , 8); + FFF(ccc, ddd, eee, aaa, bbb, block[ 2] , 13); + FFF(bbb, ccc, ddd, eee, aaa, block[13] , 6); + FFF(aaa, bbb, ccc, ddd, eee, block[14] , 5); + FFF(eee, aaa, bbb, ccc, ddd, block[ 0] , 15); + FFF(ddd, eee, aaa, bbb, ccc, block[ 3] , 13); + FFF(ccc, ddd, eee, aaa, bbb, block[ 9] , 11); + FFF(bbb, ccc, ddd, eee, aaa, block[11] , 11); + + /* combine results */ + ddd += cc + state[1]; /* final result for state[0] */ + state[1] = state[2] + dd + eee; + state[2] = state[3] + ee + aaa; + state[3] = state[4] + aa + bbb; + state[4] = state[0] + bb + ccc; + state[0] = ddd; +} + +void RMD160Update(context, data, nbytes) + RMD160_CTX *context; + const unsigned char *data; + uint32 nbytes; +{ + uint32 X[16]; + uint32 ofs = 0; + uint32 i; +#ifdef __BIG_ENDIAN__ + uint32 j; +#endif /* __BIG_ENDIAN__ */ + + /* update length[] */ + if (context->length[0] + nbytes < context->length[0]) + context->length[1]++; /* overflow to msb of length */ + context->length[0] += nbytes; + + byte_zero(X, sizeof(X)); + + if ( context->buflen + nbytes < 64 ) + { + byte_copy(context->bbuffer + context->buflen, nbytes, data); + context->buflen += nbytes; + } + else + { + /* process first block */ + ofs = 64 - context->buflen; + byte_copy(context->bbuffer + context->buflen, ofs, data); +#ifdef __LITTLE_ENDIAN__ + byte_copy(X, sizeof(X), context->bbuffer); +#else /* __BIG_ENDIAN__ */ + for (j=0; j < 16; j++) + X[j] = BYTES_TO_DWORD(context->bbuffer + (4 * j)); +#endif /* __LITTLE_ENDIAN__ */ + RMD160Transform(context->state, X); + nbytes -= ofs; + + /* process remaining complete blocks */ + for (i = 0; i < (nbytes >> 6); i++) { +#ifdef __LITTLE_ENDIAN__ + byte_copy(X, sizeof(X), data + (64 * i) + ofs); +#else /* __BIG_ENDIAN__ */ + for (j=0; j < 16; j++) + X[j] = BYTES_TO_DWORD(data + (64 * i) + (4 * j) + ofs); +#endif /* __LITTLE_ENDIAN__ */ + RMD160Transform(context->state, X); + } + + /* + * Put last bytes from data into context's buffer + */ + context->buflen = nbytes & 63; + byte_copy(context->bbuffer, context->buflen, data + (64 * i) + ofs); + } +} + +void RMD160Final(digest, context) + unsigned char digest[20]; + RMD160_CTX *context; +{ + uint32 i; + uint32 X[16]; +#ifdef __BIG_ENDIAN__ + uint32 j; +#endif /* __BIG_ENDIAN__ */ + + /* append the bit m_n == 1 */ + context->bbuffer[context->buflen] = '\200'; + + byte_zero(context->bbuffer + context->buflen + 1, + 63 - context->buflen); +#ifdef __LITTLE_ENDIAN__ + byte_copy(X, sizeof(X), context->bbuffer); +#else /* __BIG_ENDIAN__ */ + for (j=0; j < 16; j++) + X[j] = BYTES_TO_DWORD(context->bbuffer + (4 * j)); +#endif /* __LITTLE_ENDIAN__ */ + if ((context->buflen) > 55) { + /* length goes to next block */ + RMD160Transform(context->state, X); + byte_zero(X, sizeof(X)); + } + + /* append length in bits */ + X[14] = context->length[0] << 3; + X[15] = (context->length[0] >> 29) | + (context->length[1] << 3); + RMD160Transform(context->state, X); + + if (digest != NULL) { + for (i = 0; i < 20; i += 4) { + /* extracts the 8 least significant bits. */ + digest[i] = context->state[i>>2]; + digest[i + 1] = (context->state[i>>2] >> 8); + digest[i + 2] = (context->state[i>>2] >> 16); + digest[i + 3] = (context->state[i>>2] >> 24); + } + } +} + + +/* rmd160hl.c + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + */ + +/* ARGSUSED */ +char * +RMD160End(ctx, buf) + RMD160_CTX *ctx; + char *buf; /* buf needs to be 41 bytes big */ +{ + int i; + char *p = buf; + unsigned char digest[20]; + static const char hex[]="0123456789abcdef"; + + if (p == NULL) + return 0; + + RMD160Final(digest,ctx); + for (i = 0; i < 20; i++) { + p[i + i] = hex[digest[i] >> 4]; + p[i + i + 1] = hex[digest[i] & 0x0f]; + } + p[i + i] = '\0'; + return(p); +} + +char * +RMD160Data (data, len, buf) + const unsigned char *data; + size_t len; + char *buf; /* buf needs to be 41 bytes big */ +{ + RMD160_CTX ctx; + + RMD160Init(&ctx); + RMD160Update(&ctx, data, len); + return(RMD160End(&ctx, buf)); +} + +/* Base 64 */ + +char * +RMD160DataBase64 (data, len, buf, buflen) + const unsigned char *data; + size_t len; + char *buf; /* buf needs to be 29 bytes big */ + size_t buflen; +{ + RMD160_CTX ctx; + unsigned char buffer[20]; + + RMD160Init(&ctx); + RMD160Update(&ctx, data, len); + RMD160Final(buffer,&ctx); + b64_ntop(buffer,sizeof(buffer),buf,buflen); + return(buf); +} + diff -uN qmail-1.03/digest_rmd160.h qmail-ldap/digest_rmd160.h --- qmail-1.03/digest_rmd160.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/digest_rmd160.h Fri Apr 20 21:35:43 2001 @@ -0,0 +1,52 @@ +/* digest_rmd160.h for QLDAP modified to use djb's stuff */ + +/* */ +/* RMD160 */ +/* */ + +/********************************************************************\ + * + * FILE: rmd160.h + * + * CONTENTS: Header file for a sample C-implementation of the + * RIPEMD-160 hash-function. + * TARGET: any computer with an ANSI C compiler + * + * AUTHOR: Antoon Bosselaers, ESAT-COSIC + * DATE: 1 March 1996 + * VERSION: 1.0 + * + * Copyright (c) Katholieke Universiteit Leuven + * 1996, All Rights Reserved + * +\********************************************************************/ + +#ifndef _RMD160_H /* make sure this file is read only once */ +#define _RMD160_H + +/********************************************************************/ +#include "uint32.h" + +/* structure definitions */ + +typedef struct { + uint32 state[5]; /* state (ABCDE) */ + uint32 length[2]; /* number of bits */ + unsigned char bbuffer[64]; /* overflow buffer */ + uint32 buflen; /* number of chars in bbuffer */ +} RMD160_CTX; + +/********************************************************************/ + +/* function prototypes */ + +void RMD160Init (); +void RMD160Transform (); +void RMD160Update (); +void RMD160Final (); +char *RMD160End (); +char *RMD160Data (); + +char *RMD160DataBase64 (); + +#endif /* _RMD160_H */ diff -uN qmail-1.03/digest_sha1.c qmail-ldap/digest_sha1.c --- qmail-1.03/digest_sha1.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/digest_sha1.c Fri Apr 20 21:35:43 2001 @@ -0,0 +1,262 @@ +/* digest_sha1.c for QLDAP modified to use djb stuff */ +/* contains SHA1 algorithm stolen directly from OpenBSD */ + +/* */ +/* SHA1 */ +/* */ + +/* + * SHA-1 in C + * By Steve Reid + * 100% Public Domain + * + * Test Vectors (from FIPS PUB 180-1) + * "abc" + * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D + * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 + * A million repetitions of "a" + * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F + */ + +#define SHA1HANDSOFF /* Copies data before messing with it. */ + +#include +#include "uint32.h" +#include "byte.h" +#include "digest_sha1.h" +#include "base64.h" + +/* some systems don't have NULL defined */ +#ifndef NULL +#define NULL (void*) 0 +#endif + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* + * blk0() and blk() perform the initial expand. + * I got the idea of expanding during the round function from SSLeay + */ +#ifdef __LITTLE_ENDIAN__ +# define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#else /* __BIG_ENDIAN__ */ +# define blk0(i) block->l[i] +#endif /* __LITTLE_ENDIAN__ */ + +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* + * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 + */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* + * Hash a single 512-bit block. This is the core of the algorithm. + */ +void SHA1Transform(state, buffer) + uint32 state[5]; + const unsigned char buffer[64]; +{ + uint32 a, b, c, d, e; + typedef union { + unsigned char c[64]; + unsigned int l[16]; + } CHAR64LONG16; + CHAR64LONG16 *block; + +#ifdef SHA1HANDSOFF + static unsigned char workspace[64]; + block = (CHAR64LONG16 *)workspace; + byte_copy(block, 64, buffer); +#else + block = (CHAR64LONG16 *)buffer; +#endif + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* + * SHA1Init - Initialize new context + */ +void SHA1Init(context) + SHA1_CTX *context; +{ + + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* + * Run your data through this. + */ +void SHA1Update(context, data, len) + SHA1_CTX *context; + const unsigned char *data; + unsigned int len; +{ + unsigned int i, j; + + j = context->count[0]; + if ((context->count[0] += len << 3) < j) + context->count[1] += (len>>29)+1; + j = (j >> 3) & 63; + if ((j + len) > 63) { + byte_copy(&context->buffer[j], (i = 64-j), data); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) + SHA1Transform(context->state, &data[i]); + j = 0; + } else { + i = 0; + } + byte_copy(&context->buffer[j], len - i, &data[i]); +} + + +/* + * Add padding and return the message digest. + */ +void SHA1Final(digest, context) + unsigned char digest[20]; + SHA1_CTX* context; +{ + unsigned int i; + unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (unsigned char *)"\200", 1); + while ((context->count[0] & 504) != 448) + SHA1Update(context, (unsigned char *)"\0", 1); + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + + if (digest) { + for (i = 0; i < 20; i++) + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + /* Zeroize sensitive information. + */ + byte_zero(context, sizeof (*context)); + } + +} + + +/* sha1hl.c + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + */ + +/* ARGSUSED */ +char * +SHA1End(ctx, buf) + SHA1_CTX *ctx; + char *buf; /* needs to be 41 bytes big */ +{ + int i; + char *p = buf; + unsigned char digest[20]; + static const char hex[]="0123456789abcdef"; + + if (p == NULL ) + return 0; + + SHA1Final(digest,ctx); + for (i = 0; i < 20; i++) { + p[i + i] = hex[digest[i] >> 4]; + p[i + i + 1] = hex[digest[i] & 0x0f]; + } + p[i + i] = '\0'; + return(p); +} + +char * +SHA1Data (data, len, buf) + const unsigned char *data; + size_t len; + char *buf; /* needs to be 41 bytes big */ +{ + SHA1_CTX ctx; + + SHA1Init(&ctx); + SHA1Update(&ctx, data, len); + return(SHA1End(&ctx, buf)); +} + +/* Base 64 */ + +char * +SHA1DataBase64 (data, len, buf, buflen) + const unsigned char *data; + size_t len; + char *buf; /* needs to be 29 bytes big */ + size_t buflen; +{ + SHA1_CTX ctx; + unsigned char buffer[20]; + + SHA1Init(&ctx); + SHA1Update(&ctx, data, len); + SHA1Final(buffer,&ctx); + b64_ntop(buffer,sizeof(buffer),buf,buflen); + return(buf); +} + diff -uN qmail-1.03/digest_sha1.h qmail-ldap/digest_sha1.h --- qmail-1.03/digest_sha1.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/digest_sha1.h Fri Apr 20 21:35:43 2001 @@ -0,0 +1,33 @@ +/* digest_sha1.h for QLDAP modified to use djb stuff */ + +/* */ +/* SHA1 */ +/* */ + +/* + * SHA-1 in C + * By Steve Reid + * 100% Public Domain + */ + +#ifndef _SHA1_H +#define _SHA1_H + +#include "uint32.h" + +typedef struct { + uint32 state[5]; + uint32 count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +void SHA1Transform (); +void SHA1Init (); +void SHA1Update (); +void SHA1Final (); +char *SHA1End (); +char *SHA1Data (); + +char *SHA1DataBase64 (); + +#endif /* _SHA1_H */ diff -uN qmail-1.03/dirmaker qmail-ldap/dirmaker --- qmail-1.03/dirmaker Thu Jan 1 01:00:00 1970 +++ qmail-ldap/dirmaker Thu Oct 7 16:51:09 1999 @@ -0,0 +1,3 @@ +#!/bin/sh +/bin/mkdir -m 700 -p $1 +#EOF diff -uN qmail-1.03/dns.c qmail-ldap/dns.c --- qmail-1.03/dns.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/dns.c Mon Sep 25 19:23:53 2000 @@ -21,10 +21,12 @@ static unsigned short getshort(c) unsigned char *c; { unsigned short u; u = c[0]; return (u << 8) + c[1]; } -static union { HEADER hdr; unsigned char buf[PACKETSZ]; } response; +static struct { unsigned char *buf; } response; +static int responsebuflen = 0; static int responselen; static unsigned char *responseend; static unsigned char *responsepos; +static u_long saveresoptions; static int numanswers; static char name[MAXDNAME]; @@ -45,18 +47,33 @@ errno = 0; if (!stralloc_copy(&glue,domain)) return DNS_MEM; if (!stralloc_0(&glue)) return DNS_MEM; - responselen = lookup(glue.s,C_IN,type,response.buf,sizeof(response)); + if (!responsebuflen) + if (response.buf = (unsigned char *)alloc(PACKETSZ+1)) + responsebuflen = PACKETSZ+1; + else return DNS_MEM; + + responselen = lookup(glue.s,C_IN,type,response.buf,responsebuflen); + if ((responselen >= responsebuflen) || + (responselen > 0 && (((HEADER *)response.buf)->tc))) + { + if (responsebuflen < 65536) + if (alloc_re(&response.buf, responsebuflen, 65536)) + responsebuflen = 65536; + else return DNS_MEM; + saveresoptions = _res.options; + _res.options |= RES_USEVC; + responselen = lookup(glue.s,C_IN,type,response.buf,responsebuflen); + _res.options = saveresoptions; + } if (responselen <= 0) { if (errno == ECONNREFUSED) return DNS_SOFT; if (h_errno == TRY_AGAIN) return DNS_SOFT; return DNS_HARD; } - if (responselen >= sizeof(response)) - responselen = sizeof(response); responseend = response.buf + responselen; responsepos = response.buf + sizeof(HEADER); - n = ntohs(response.hdr.qdcount); + n = ntohs(((HEADER *)response.buf)->qdcount); while (n-- > 0) { i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); @@ -66,7 +83,7 @@ if (i < QFIXEDSZ) return DNS_SOFT; responsepos += QFIXEDSZ; } - numanswers = ntohs(response.hdr.ancount); + numanswers = ntohs(((HEADER *)response.buf)->ancount); return 0; } @@ -273,6 +290,10 @@ if (!stralloc_copy(&glue,sa)) return DNS_MEM; if (!stralloc_0(&glue)) return DNS_MEM; +#ifdef TLS + if (!(ix.fqdn = alloc(glue.len) ) ) return DNS_MEM; + byte_copy(ix.fqdn, glue.len, glue.s); +#endif if (glue.s[0]) { ix.pref = 0; if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) @@ -280,6 +301,7 @@ if (!ipalloc_append(ia,&ix)) return DNS_MEM; return 0; } + } switch(resolve(sa,T_A)) diff -uN qmail-1.03/endian.c qmail-ldap/endian.c --- qmail-1.03/endian.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/endian.c Wed Mar 24 00:28:59 1999 @@ -0,0 +1,34 @@ +/* endian.c + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Claudio Jeker + * ---------------------------------------------------------------------------- + * + * This is a lowest-common-denominator (endian) program which should compile + * under the default cc on any system, no matter how primitite ... + * (even the SunOS one ;-) ) + */ + +#include + + +union endian_t { + unsigned char c[8]; + long l; +} endian; + +int main() +{ + + endian.c[0]=128; endian.c[1]=0; endian.c[2]=0; endian.c[3]=0; + endian.c[4]=0; endian.c[5]=0; endian.c[6]=0; endian.c[7]=0; + + if( endian.l < 0 ) + printf( "-D__BIG_ENDIAN__" ); + else + printf( "-D__LITTLE_ENDIAN__" ); + + return(0); +} diff -uN qmail-1.03/gettimeofday.c qmail-ldap/gettimeofday.c --- qmail-1.03/gettimeofday.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/gettimeofday.c Fri Apr 20 23:25:17 2001 @@ -0,0 +1,12 @@ +#include +#include + +struct timeval sincepoch = {0,0}; +struct timezone notimezone = {0,0}; + +main() +{ + gettimeofday(&sincepoch, ¬imezone); + printf("%d\n", sincepoch.tv_sec); +} + diff -uN qmail-1.03/hier.c qmail-ldap/hier.c --- qmail-1.03/hier.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/hier.c Mon Jun 19 10:25:25 2000 @@ -98,6 +98,11 @@ c(auto_qmail,"doc","PIC.relaybad",auto_uido,auto_gidq,0644); c(auto_qmail,"doc","PIC.relaygood",auto_uido,auto_gidq,0644); c(auto_qmail,"doc","PIC.rem2local",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","QLDAPINSTALL",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","QLDAPNEWS",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","QLDAPTODO",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","QLDAPPICTURE",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","ANTISPAM",auto_uido,auto_gidq,0644); c(auto_qmail,"bin","qmail-queue",auto_uidq,auto_gidq,04711); c(auto_qmail,"bin","qmail-lspawn",auto_uido,auto_gidq,0700); @@ -143,6 +148,11 @@ c(auto_qmail,"bin","qail",auto_uido,auto_gidq,0755); c(auto_qmail,"bin","elq",auto_uido,auto_gidq,0755); c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-reply",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-quotawarn",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","auth_pop",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","auth_imap",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","qmail-ldaplookup",auto_uido,auto_gidq,0700); c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644); c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644); diff -uN qmail-1.03/install-big.c qmail-ldap/install-big.c --- qmail-1.03/install-big.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/install-big.c Mon Jun 19 10:25:25 2000 @@ -98,6 +98,11 @@ c(auto_qmail,"doc","PIC.relaybad",auto_uido,auto_gidq,0644); c(auto_qmail,"doc","PIC.relaygood",auto_uido,auto_gidq,0644); c(auto_qmail,"doc","PIC.rem2local",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","QLDAPINSTALL",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","QLDAPNEWS",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","QLDAPTODO",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","QLDAPPICTURE",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","ANTISPAM",auto_uido,auto_gidq,0644); c(auto_qmail,"bin","qmail-queue",auto_uidq,auto_gidq,04711); c(auto_qmail,"bin","qmail-lspawn",auto_uido,auto_gidq,0700); @@ -143,7 +148,12 @@ c(auto_qmail,"bin","qail",auto_uido,auto_gidq,0755); c(auto_qmail,"bin","elq",auto_uido,auto_gidq,0755); c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755); - + c(auto_qmail,"bin","qmail-reply",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-quotawarn",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","auth_pop",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","auth_imap",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","qmail-ldaplookup",auto_uido,auto_gidq,0700); + c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644); c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644); c(auto_qmail,"man/man5","envelopes.5",auto_uido,auto_gidq,0644); diff -uN qmail-1.03/ipalloc.h qmail-ldap/ipalloc.h --- qmail-1.03/ipalloc.h Mon Jun 15 12:53:16 1998 +++ qmail-ldap/ipalloc.h Mon Sep 25 19:23:54 2000 @@ -3,7 +3,11 @@ #include "ip.h" +#ifdef TLS +struct ip_mx { struct ip_address ip; int pref; char *fqdn; } ; +#else struct ip_mx { struct ip_address ip; int pref; } ; +#endif #include "gen_alloc.h" diff -uN qmail-1.03/ipme.c qmail-ldap/ipme.c --- qmail-1.03/ipme.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/ipme.c Thu Mar 1 21:10:58 2001 @@ -45,6 +45,12 @@ if (!ipalloc_readyplus(&ipme,0)) return 0; ipme.len = 0; ix.pref = 0; + + /* 0.0.0.0 is a special address which always refers to + * "this host, this network", according to RFC 1122, Sec. 3.2.1.3a. + */ + byte_copy(&ix.ip,4,"\0\0\0\0"); + if (!ipalloc_append(&ipme,&ix)) { return 0; } if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) return -1; diff -uN qmail-1.03/maildir++.c qmail-ldap/maildir++.c --- qmail-1.03/maildir++.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/maildir++.c Fri Apr 20 21:35:44 2001 @@ -0,0 +1,633 @@ +#include +#include +#include +#include "readwrite.h" +#include "stralloc.h" +#include "str.h" +#include "open.h" +#include "substdio.h" +#include "getln.h" +#include "error.h" +#include "direntry.h" +#include "strerr.h" +#include "fmt.h" +#include "scan.h" +#include "now.h" +#include "seek.h" +#include "sig.h" +#include "maildir++.h" +#include "alloc.h" +#include "byte.h" + +static void temp_nomem() { strerr_die1x(111,"Out of memory. (QUOTA #1.0.1)"); } + +static int mailfolder(void); +static int quota_parsesize(quota_t *q, int *fd, char* buf, int len); +static int quota_calcsize(quota_t *q, int *fd, char* buf, int len); +static int quota_writesize(quota_t *q, int *fd, time_t maxtime); +static int check_maxtime(time_t time); +static int get_file_size(char *name, struct stat *st); +static void calc_curnew(quota_t *q, time_t *maxtime); +static int read5120(char* fn, char* buf, int *len); + + +static stralloc path = {0}; +static char writebuf[3*FMT_ULONG]; /* enough big to hold all needed data */ + +/* alarm handler */ +static void sigalrm() { unlink(path.s); + strerr_die1x(111,"Timeout while writing maildirsize. (QUOTA #1.0.2)"); } + +void quota_add(int fd, unsigned long size, unsigned long count) + /* add size and count to the quota (maildirsize) */ +{ + char num[FMT_ULONG]; + seek_pos pos; + substdio ss; + + if ( fd == -1 ) return; + + seek_end(fd); + pos = seek_cur(fd); /* again savety */ + + substdio_fdbuf(&ss,write,fd,writebuf,sizeof(writebuf)); + /* create string of the form '1234 12\n' and add it to the quota */ + if ( substdio_put(&ss, num, fmt_ulong(num, size) ) == -1 ) goto addfail; + if ( substdio_puts(&ss, " ") == -1 ) goto addfail; + if ( substdio_put(&ss, num, fmt_ulong(num, count) ) == -1 ) goto addfail; + if ( substdio_puts(&ss, "\n") == -1 ) goto addfail; + if ( substdio_flush(&ss) == -1 ) goto addfail; + if ( fsync(fd) == -1 ) goto addfail; + return; + +addfail: + strerr_warn3("Unable to add file to quota: ", error_str(errno), + ". (QUOTA #1.2.1)",0); + seek_trunc(fd,pos); /* recover form error */ + return; /* ignore errors, perhaps the file was removed */ +} + +void quota_rm(int fd, unsigned long size, unsigned long count) + /* remove size and count from the quota (maildirsize) * + * both size and count are POSITVE integers */ +{ + char num[FMT_ULONG]; + seek_pos pos; + substdio ss; + + if ( fd == -1 ) return; + + seek_end(fd); + pos = seek_cur(fd); /* again savety */ + + substdio_fdbuf(&ss,write,fd,writebuf,sizeof(writebuf)); + /* create string of the form '-1232 -12\n' and add it to the quota */ + if ( substdio_puts(&ss, "-") == -1 ) goto rmfail; + if ( substdio_put(&ss, num, fmt_ulong(num, size) ) == -1 ) goto rmfail; + if ( substdio_puts(&ss, " -") == -1 ) goto rmfail; + if ( substdio_put(&ss, num, fmt_ulong(num, count) ) == -1 ) goto rmfail; + if ( substdio_puts(&ss, "\n") == -1 ) goto rmfail; + if ( substdio_flush(&ss) == -1 ) goto rmfail; + if (fsync(fd) == -1 ) goto rmfail; + return; + +rmfail: + strerr_warn3("Unable to remove file from quota: ", error_str(errno), + ". (QUOTA #1.3.1)",0); + seek_trunc(fd,pos); /* recover form error */ + return; /* ignore errors, perhaps the file was removed */ +} + +int quota_calc(char *dir, int *fd, quota_t *q) +{ + char *bigbuf; /* need to be as big as maildirsize max size */ + int i = 0; + int ret; + + if ( ! stralloc_copys(&path, dir) ) temp_nomem(); + if ( ! (bigbuf = alloc(5120) ) ) temp_nomem(); + + while ( mailfolder() ) { + if ( ! stralloc_cats(&path, "/..") ) temp_nomem(); + if ( i++ > 1 ) strerr_die1x(111, + "Unable to calc quota: recursive maildir++ (QUOTA #1.1.1)"); + } + + if ( ! stralloc_cats(&path, "/maildirsize") ) temp_nomem(); + if ( ! stralloc_0(&path) ) temp_nomem(); + *fd = read5120( path.s, bigbuf, &i); + if ( *fd != -1 ) { + ret = quota_parsesize(q, fd, bigbuf, i); + } else { + ret = quota_calcsize(q, fd, bigbuf, i); + } + alloc_free(bigbuf); + return ret; +} + +int quota_recalc(char *dir, int *fd, quota_t *q, unsigned long size, + unsigned long count, int *perc) +{ + char *bigbuf; /* need to be as big as maildirsize max size */ + int i = 0; + int j; + int ret; + int lines = 0; + time_t tm; + struct stat st; + + if ( ! stralloc_copys(&path, dir) ) temp_nomem(); + if ( ! (bigbuf = alloc(5120) ) ) temp_nomem(); + + while ( mailfolder() ) { + if ( ! stralloc_cats(&path, "/..") ) temp_nomem(); + if ( i++ > 1 ) strerr_die1x(111, + "Unable to calc quota: recursive maildir++ (QUOTA #1.1.1)"); + } + + if ( ! stralloc_cats(&path, "/maildirsize") ) temp_nomem(); + if ( ! stralloc_0(&path) ) temp_nomem(); + *fd = read5120( path.s, bigbuf, &i); + + if ( *fd != -1 ) { + for ( j = 0; j < i && lines <= 2 ; j++ ) { + if ( bigbuf[j] == '\n' ) lines++; + } + if ( lines <= 2 ) { + if ( fstat(*fd, &st) == -1 ) + strerr_die3x(111, "Unable to fstat maildirsize: ", + error_str(errno), " (QUOTA #1.5.1)"); + tm = now(); + if ( tm < st.st_mtime + 15*60 ) { ret = -1; goto done; } + } + /* need to recalculate the quota */ + close(*fd); *fd = -1; + unlink(path.s); + } + if ( quota_calcsize(q, fd, bigbuf, i) == -1 ) { ret = -1; goto done; } + ret = quota_check(q, size, count, perc); +done: + alloc_free(bigbuf); + return ret; + +} + +int quota_check(quota_t *q, unsigned long size, unsigned long count, int *perc) +{ + int i; + + if ( q->quota_size == 0 && q->quota_count == 0 ) { + /* no quota defined */ + if (perc) *perc = 0; + return 0; + } + + if ( q->size + size > q->quota_size && q->quota_size != 0 ) { + if(perc) *perc = 100; + return -1; + } + + if ( q->count + count > q->quota_count && q->quota_count != 0 ) { + if(perc) *perc = 100; + return -1; + } + + if (!perc) return 0; + + *perc = q->quota_size ? (int) ( (q->size + size)*100/q->quota_size ) : 0; + i = q->quota_count ? (int) ( (q->count + count)*100/q->quota_count ) : 0; + if (i > *perc) *perc = i; + return 0; +} + +void quota_get(quota_t *q, char *quota) +{ + unsigned long i; + + q->quota_size = 0; + q->quota_count = 0; + q->size = 0; + q->count = 0; + + while (quota && *quota) { + if (*quota < '0' || *quota > '9') { + quota++; + continue; + } + i=0; + while (*quota >= '0' && *quota <= '9') + i = i*10 + (*quota++ - '0'); + + switch (*quota) { + case 'S': + q->quota_size = i; + break; + case 'C': + q->quota_count = i; + break; + default: /* defaults to size */ + q->quota_size = i*1024; + /* because in the old patch it was in kB */ + break; /* thanks to Aaron Nabil */ + } + } +} + +static int mailfolder(void) +{ + unsigned int len; + struct stat st; + + len = path.len; + /* check if we are in a maildir subfolder, normaly this is impossible + */ + + if ( ! stralloc_cats(&path, "/maildirfolder") ) temp_nomem(); + if ( ! stralloc_0(&path) ) temp_nomem(); + + if ( stat(path.s, &st) == -1 ) { /* are we in a subdir ? */ + if ( errno != error_noent ) { + strerr_die3x(111, "Unable to stat maildirfolder: ", + error_str(errno), " (QUOTA #1.4.1)"); + } + path.len = len; /* cut away what this function has added */ + return 0; + } else { + path.len = len; /* cut away what this function has added */ + return 1; + } +} + +static int quota_parsesize(quota_t *q, int *fd, char* buf, int len) +{ + int i; + int lines; + char *s; + long fig; + quota_t dummy; + + for ( i = 0; i < len; i++ ) { + if ( buf[i] == '\n' ) buf[i] = '\0'; + } + + quota_get(&dummy, buf); + if ( q->quota_size == 0 && q->quota_count == 0 ) { + /* no quota defined */ + q->quota_size = dummy.quota_size; + q->quota_count = dummy.quota_count; + } + + if ( q->quota_size != dummy.quota_size || + q->quota_count != dummy.quota_count ) { + /* quota definition has changed, remove old maildirsize file + * and recalculate the quota */ + close(*fd); *fd = -1; + unlink(path.s); + return quota_calcsize(q, fd, buf, len); + } + + q->size = 0; q->count = 0; /* just to be sure */ + lines = 0; s = buf; + + while( s - buf < len ) { + while( *s++ ); /* hop over the last line */ + + /* first comes the size ... */ + if ( *s == '-' ) { + if (! ( s += scan_ulong(++s, &fig) ) ) continue; + fig *= -1; + } else { + if (! ( s += scan_ulong(s, &fig) ) ) continue; + } + q->size += fig; + /* then the file count */ + while ( *++s == ' ' ) ; /* hop over the spaces */ + + if ( *s == '-' ) { + if (! ( s += scan_ulong(++s, &fig) ) ) continue; + fig *= -1; + } else { + if (! ( s += scan_ulong(s, &fig) ) ) continue; + } + q->count += fig; + lines++; + } + + return 0; +} + +static int quota_calcsize(quota_t *q, int *fd, char* buf, int len) +{ + unsigned int slen; + time_t tm; + time_t maxtime; + direntry *dp; + DIR *dirp; + + if ( q->quota_size == 0 && q->quota_count == 0 ) { + /* no quota defined */ + return 0; + } + + q->size = 0; q->count = 0; /* just to be sure */ + + tm = now(); + maxtime = 0; + + /* first pop away '/maildirsize' in path */ + path.len -= 13; /* including the '\0' char */ + slen = path.len; + if ( ! stralloc_0(&path) ) temp_nomem(); + + dirp = opendir(path.s); + while ( dirp && (dp = readdir(dirp)) != 0) { + if ( dp->d_name[0] == '.' && dp->d_name[1] != '\0' && + dp->d_name[1] != '.' && str_diff( ".Trash", dp->d_name) ) { + path.len = slen; + if ( ! stralloc_cats(&path, dp->d_name) ) temp_nomem(); + + calc_curnew(q, &maxtime); + path.len = slen; + } + } + + path.len = slen; + calc_curnew(q, &maxtime); + path.len = slen; + + /* quota is calculated, now create the new maildirsize file */ + return quota_writesize(q, fd, maxtime); +} + +static int quota_writesize(quota_t *q, int *fd, time_t maxtime) +{ + int pid; + int i; + char *buf; + char *s; + char num[FMT_ULONG]; + time_t tm; + struct stat st; + substdio ss; + + /* write maildirsize in standart Maildir manner */ + sig_alarmcatch(sigalrm); + + for (i = 0; ; ++i) { + tm = now(); + pid = getpid(); + if (! (buf = (char *) alloc(path.len + 17 + ( 2 * FMT_ULONG ) + 2) ) ) + temp_nomem(); + s = buf; + byte_copy(s, path.len, path.s); s += path.len; + byte_copy(s, 17, "/tmp/maildirsize."); s += 17; + s += fmt_ulong(s,maxtime); *s++ = '.'; + s += fmt_ulong(s,pid); *s++ = 0; + if (stat(buf, &st) == -1) if (errno == error_noent) break; + /* really should never get to this point */ + if (i == 2) _exit(1); + sleep(2); + } + + alarm(86400); + + if ( ( *fd = open(buf, O_RDWR | O_NDELAY | O_APPEND | O_CREAT, + 0600) ) == -1 ) { + if ( errno == error_noent ) return 0; + goto fail; + } + + substdio_fdbuf(&ss,write,*fd,writebuf,sizeof(writebuf)); + + if ( substdio_put(&ss, num, fmt_ulong(num, q->quota_size) ) == -1 ) + goto fail; + if ( substdio_puts(&ss,"S,") == -1 ) + goto fail; + if ( substdio_put(&ss, num, fmt_ulong(num, q->quota_count) ) == -1 ) + goto fail; + if ( substdio_puts(&ss,"C\n") == -1 ) + goto fail; + + if ( substdio_put(&ss, num, fmt_ulong(num, q->size) ) == -1 ) + goto fail; + if ( substdio_puts(&ss, " ") == -1 ) + goto fail; + if ( substdio_put(&ss, num, fmt_ulong(num, q->count) ) == -1 ) + goto fail; + if ( substdio_puts(&ss, "\n") == -1 ) + goto fail; + + if ( substdio_flush(&ss) == -1 ) goto fail; + if ( fsync(*fd) == -1 ) goto fail; + + i = check_maxtime(maxtime); + if ( ! stralloc_cats(&path, "/maildirsize") ) temp_nomem(); + if ( ! stralloc_0(&path) ) temp_nomem(); + if ( unlink(path.s) == -1 && errno != error_noent ) goto fail; + + if ( i ) { + /* race condition, don't write maildir size */ + unlink(buf); + alloc_free(buf); + *fd = -1; + return -1; + } + if (link(buf,path.s) == -1) goto fail; + unlink(buf); + + /* unset the alarm, else %*#! may happen */ + alarm(0); + sig_alarmdefault(); + + return 0; + +fail: + strerr_warn3("Problems while trying to get maildirsize: ", + error_str(errno), ". (QUOTA #1.1.1)", 0); + unlink(buf); + alloc_free(buf); + _exit(111); +} + +static int check_maxtime(time_t time) +/* check if a directory has changed, to avoid race conditions */ +{ + direntry *dp; + DIR *dirp; + struct stat filest; + unsigned int slen; + int i; + + slen = path.len; + if ( ! stralloc_0(&path) ) temp_nomem(); + dirp = opendir(path.s); + path.len = slen; + + while ( dirp && (dp = readdir(dirp)) != 0) { + if ( dp->d_name[0] == '.' && dp->d_name[1] != '\0' && + dp->d_name[1] != '.' && str_diff( ".Trash", dp->d_name) ) { + path.len = slen; + if ( ! stralloc_cats(&path, dp->d_name) ) temp_nomem(); + if ( ! stralloc_cats(&path, "/cur") ) temp_nomem(); + if ( ! stralloc_0(&path) ) temp_nomem(); + if ( stat(path.s, &filest) == 0 && filest.st_mtime > time) { + i = 1; + break; + } + path.len = slen; + if ( ! stralloc_cats(&path, dp->d_name) ) temp_nomem(); + if ( ! stralloc_cats(&path, "/new") ) temp_nomem(); + if ( ! stralloc_0(&path) ) temp_nomem(); + if ( stat(path.s, &filest) == 0 && filest.st_mtime > time) { + i = 1; + break; + } + } + if ( !str_diff( "new", dp->d_name ) ) { + path.len = slen; + if ( ! stralloc_cats(&path, "/new") ) temp_nomem(); + if ( stat(path.s, &filest ) == 0 && filest.st_mtime > time) { + i = 1; + break; + } + } + if ( !str_diff( "cur", dp->d_name ) ) { + path.len = slen; + if ( ! stralloc_cats(&path, "/cur") ) temp_nomem(); + if ( stat(path.s, &filest ) == 0 && filest.st_mtime > time) { + i = 1; + break; + } + } + } + i = 0; + path.len = slen; + closedir(dirp); + return i; +} + +static int get_file_size(char *name, struct stat *st) +/* get the filesize of the file name in dir, via the name or a stat */ +{ + char *s = name; + unsigned int slen; + + while (*s) { + if ( *s != ',' || s[1] != 'S' || s[2] != '=' ) { + s++; + } else { + s += 3; + st->st_size = 0; + while ( *s >= '0' && *s <= '9' ) + st->st_size = st->st_size*10 + (*s++ - '0'); + return 0; + } + } + /* stat the file */ + slen = --path.len; + if ( ! stralloc_cats(&path, name) ) temp_nomem(); + if ( ! stralloc_0(&path) ) temp_nomem(); + path.len = slen; + + if ( stat( path.s, st) == 0 ) { + if ( ! stralloc_0(&path) ) temp_nomem(); + return 0; + } else { + if ( ! stralloc_0(&path) ) temp_nomem(); + return -1; + } +} + +static void calc_curnew(quota_t *q, time_t *maxtime) +/* calculate the size of the two dirs new and cur of a maildir + * (uses get_file_size) */ +{ + direntry *dp; + DIR *dirp; + struct stat filest; + char *f; + + if ( ! stralloc_cats(&path, "/new/") ) temp_nomem(); + if ( ! stralloc_0(&path) ) temp_nomem(); + + /* update the latest modified time to avoid race conditions */ + if ( stat( path.s, &filest ) == 0 && filest.st_mtime > *maxtime) + *maxtime = filest.st_mtime; + + dirp = opendir(path.s); + /* start with new */ + while ( dirp && (dp = readdir(dirp)) != 0) { + f = dp->d_name; + if ( *f == '.' ) continue; /* ignore all dot-files */ + while(*f) { + if ( *f != ':' || f[1] != '2' || f[2] != ',' ) { + f++; + } else { + f += 3; + while( *f >= 'A' && *f <= 'Z' && *f != 'T' ) f++; + break; + } + } + if ( *f == 'T' ) continue; + /* get the file size */ + if( get_file_size(dp->d_name, &filest) == 0 ) { + q->count++; + q->size += (long) filest.st_size; + } + } + + path.s[path.len-3] = 'r'; + path.s[path.len-4] = 'u'; + path.s[path.len-5] = 'c'; + /* the same thing with cur */ + + if ( stat( path.s, &filest ) == 0 && filest.st_mtime > *maxtime) + *maxtime = filest.st_mtime; + + dirp = opendir(path.s); + while ( dirp && (dp = readdir(dirp)) != 0) { + f = dp->d_name; + if ( *f == '.' ) continue; /* ignore all dot-files */ + while(*f) { + if ( *f != ':' || f[1] != '2' || f[2] != ',' ) { + f++; + } else { + f += 3; + while( *f >= 'A' && *f <= 'Z' && *f != 'T' ) f++; + break; + } + } + if ( *f == 'T' ) continue; + + if( get_file_size(dp->d_name, &filest) == 0 ) { + q->count++; + q->size += (long) filest.st_size; + } + } +} + +static int read5120(char* fn, char* buf, int *len) +{ + int fd; + int r; + + if ( ( fd = open(fn, O_RDWR | O_NDELAY | O_APPEND, + 0600) ) == -1 ) { + if ( errno == error_noent ) return -1; + } + + *len = 0; + for (;;) { + r = read(fd, buf, 5120 - *len); + if (r == -1) if (errno == error_intr) continue; + if (*len >= 5120) { /* file to big */ + close(fd); + unlink(path.s); + return -1; + } + if (r == 0) return fd; /* no more data */ + *len += r; + buf += r; + } +} + diff -uN qmail-1.03/maildir++.h qmail-ldap/maildir++.h --- qmail-1.03/maildir++.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/maildir++.h Fri Dec 1 02:03:06 2000 @@ -0,0 +1,19 @@ +#ifndef __MAILDIRPP_H__ +#define __MAILDIRPP_H__ + +typedef struct { + unsigned long quota_size; + unsigned long quota_count; + long size; + long count; +} quota_t; + +void quota_add(int fd, unsigned long size, unsigned long count); +void quota_rm(int fd, unsigned long size, unsigned long count); +int quota_calc(char *dir, int *fd, quota_t *q); +int quota_recalc(char *dir, int *fd, quota_t *q, unsigned long size, + unsigned long count, int *perc); +int quota_check(quota_t *q, unsigned long size, unsigned long count, int *perc); +void quota_get(quota_t *q, char *quota); + +#endif diff -uN qmail-1.03/output.c qmail-ldap/output.c --- qmail-1.03/output.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/output.c Tue Sep 4 00:11:09 2001 @@ -0,0 +1,139 @@ +/* qldap-debug.c, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#include "stralloc.h" +#include "substdio.h" +#include "fmt.h" +#include "str.h" +#include "scan.h" +#include "output.h" + +#include + +char num[FMT_ULONG]; + +static const char nullString[] = "(null pointer)"; +static const char ioHexArray[16] = {'0','1','2','3','4','5','6','7', + '8','9','a','b','c','d','e','f'}; + +static int fmt_hexulong(char *s, unsigned long x) +/* s has to be allready allocated, use at least FMT_ULONG chars + * 40 chars should be enough for a 20 byte unsigned long (2^160) + * so djb's fmt_ulong would first fail ;-) */ +{ + unsigned int i; + + for (i = 0; i < sizeof(unsigned long) * 2; i++) { + *s++ = (ioHexArray[(x >> (sizeof(unsigned long)*8 - 4)) & 0xf]); + x = x << 4; + } + return ( sizeof(unsigned long) * 2 ); +} + +void va_output(substdio *ss, char *fmt, va_list args) +/* works like vprintf has the format options %i, ... + * all flags (#, 0, -, ' ', +, ' ... ) are not supported if not special noted + * Also not supported are all options for foating-point numbers + * (not needed in qmail) + * Supported conversion specifiers: diouxcsSp% + * diux are for integer (long) conversions + * c is a single unsigned char + * s is a zero terminated string + * S is a stralloc object (should not be zero terminated (else the zero + * will be printed)) + * p is the hex address of a generic pointer (void *) + * % is the % sign */ +{ + unsigned long ul; + long l; + char *s; + char *start; + char *cur; + void *p; + unsigned char c; + stralloc *sa; + + start = fmt; + cur = fmt; + if (!cur) return; + while (*cur) { + if (*cur == '%') { + if ( substdio_put(ss, start, cur-start) == -1 ) return; + /* no need to care if the output is save qmail-send looks if + the output is save */ + cur++; + switch (*cur) { + case 'd': + case 'i': + l = va_arg(args, long); + if ( l < 0 ) { /* negativ number, d and i are signed */ + l *= -1; + if ( substdio_put(ss, "-", 1) == -1 ) return; + } + ul = (unsigned long) l; + if ( substdio_put(ss, num, fmt_ulong(num, ul) ) ) + return; + break; + case 'u': + ul = va_arg(args, unsigned long); + if ( substdio_put(ss, num, fmt_ulong(num, ul) ) ) + return; + break; + case 's': + s = va_arg(args, char *); + if ( !s ) { + if ( substdio_put(ss, nullString, + str_len(nullString) ) ) + return; + break; + } + if ( substdio_put(ss, s, str_len(s) ) ) return; + break; + case 'S': + sa = va_arg(args, stralloc *); + if ( !sa ) { + if ( substdio_put(ss, nullString, + str_len(nullString) ) ) + return; + break; + } + if ( substdio_put(ss, sa->s, sa->len ) ) return; + break; + case '%': + if ( substdio_put(ss, "%", 1) == -1 ) return; + break; + case 'p': + p = va_arg(args, void *); + ul = (unsigned long) p; + if ( substdio_put(ss, "0x", 2) ) return; + if ( substdio_put(ss, num, fmt_hexulong(num, ul) ) ) + return; + break; + case 'x': + ul = va_arg(args, unsigned long); + if ( substdio_put(ss, "0x", 2) ) return; + if ( substdio_put(ss, num, fmt_hexulong(num, ul) ) ) + return; + break; + case 'c': + c = (unsigned char) va_arg(args, unsigned int); + substdio_BPUTC(ss, c); + break; + } + start = ++cur; + } else { + ++cur; + } + } + if ( substdio_put(ss, start, cur-start) == -1 ) return; +} + +void output(substdio *ss, char *fmt, ...) +/* see va_output */ +{ + va_list args; + + va_start(args,fmt); + va_output(ss, fmt, args); + va_end(args); + if ( substdio_flush(ss) == -1 ) return; +} + diff -uN qmail-1.03/output.h qmail-ldap/output.h --- qmail-1.03/output.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/output.h Tue Sep 4 00:11:09 2001 @@ -0,0 +1,27 @@ +/* qldap-debug.h, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#ifndef __OUTPUT_H__ +#define __OUTPUT_H__ + +#include "substdio.h" +#include + +#define STDERR 2 +#define STDOUT 1 +#define STDIN 0 + +void va_output(substdio *ss, char *fmt, va_list args); +/* works like printf has the format options %i, ... + * all flags (#, 0, -, ' ', +, ' ... ) are not supported + * Also not supported are all options for foating-point numbers + * (not needed in qmail) + * Supported conversion specifiers: diuxcsSp% + * diux are for integer (long) conversions (di are signed all other unsigned) + * c is a single unsigned char + * s is a zero terminated string + * S is a stralloc object (should not be zero terminated (else the zero + * will be printed)) + * p is the hex address of a generic pointer (void *) + * % is the % sign */ +void output(substdio *ss, char *fmt, ...); + +#endif diff -uN qmail-1.03/popfetch.pl qmail-ldap/popfetch.pl --- qmail-1.03/popfetch.pl Thu Jan 1 01:00:00 1970 +++ qmail-ldap/popfetch.pl Sun Feb 20 12:49:08 2000 @@ -0,0 +1,62 @@ +#!/usr/bin/perl + +# $localhost and $server need to changed +# If a file by the name "done" exists in the maildir we don't try to +# fetch the mails again. +# by Ingo Oppermann + +use Mail::POP3Client; + +# Variables + +$path = $ARGV[3]; +$mailpath = "./".$path; +$username = $ARGV[0]; +$pw = $ARGV[1]; +$server = 'mail.pipeline.ch'; +$localhost = "mail.schweizerinserate.ch"; +@filenames; + +# Main + +if(-e $mailpath."/done") +{ + ; +} +else +{ + $pop = new Mail::POP3Client($username,$pw,$server); + $numofmails = $pop->Count; + print $numofmails; + for($i = 1; $i <= $numofmails; $i++) + { + $curtime = time(); + $random = rand(); + $filename = $curtime.".".$$.".".$random.$localhost; + push(@filenames, $filename); + open(OUT, ">".$mailpath."/tmp/".$filename); + foreach($pop->Retrieve($i)) + { + print OUT $_, "\n"; + } +# Uncomment the next line if the retrieved mail should be deleted from +# the old pop server + # $pop->Delete($i); + close(OUT); + } + $pop->Close; + + foreach(@filenames) + { + $filename = $_; + $program = "mv $mailpath/tmp/$filename $mailpath/new/$filename"; + open(PROG, "|$program"); + close(PROG); + } + open(CHECK, ">$mailpath/done"); + print CHECK 1; + close(CHECK); +} + +exec "$ARGV[2] $ARGV[3]"; + diff -uN qmail-1.03/profile.patch qmail-ldap/profile.patch --- qmail-1.03/profile.patch Thu Jan 1 01:00:00 1970 +++ qmail-ldap/profile.patch Sat Jul 22 09:25:17 2000 @@ -0,0 +1,63 @@ +Common subdirectories: qmail-ldap/CVS and qmail-test/CVS +diff -BbuN qmail-ldap/Makefile qmail-test/Makefile +--- qmail-ldap/Makefile Thu Jul 20 22:07:09 2000 ++++ qmail-test/Makefile Thu Jul 20 22:55:52 2000 +@@ -1402,12 +1402,13 @@ + sig.a strerr.a getln.a wait.a case.a cdb.a fd.a open.a stralloc.a \ + alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_uids.o \ + auto_spawn.o auto_usera.o env.a qldap-ldaplib.o qldap-debug.o \ +-qldap-errno.o ++qldap-errno.o qldap-profile.o + ./load qmail-lspawn spawn.o prot.o slurpclose.o coe.o control.o \ +- check.o qldap-ldaplib.o qldap-debug.o sig.a strerr.a getln.a \ ++ check.o qldap-ldaplib.o qldap-profile.o \ ++ qldap-debug.o sig.a strerr.a getln.a \ + wait.a case.a cdb.a fd.a open.a env.a stralloc.a alloc.a \ + substdio.a str.a qldap-errno.o error.a fs.a auto_qmail.o \ +- auto_uids.o auto_usera.o auto_spawn.o $(LDAPLIBS) ++ auto_uids.o auto_usera.o auto_spawn.o $(LDAPLIBS) $(LIBTAI) + + qmail-lspawn.0: \ + qmail-lspawn.8 +@@ -1419,7 +1420,8 @@ + slurpclose.h auto_qmail.h auto_uids.h qlx.h qmail-ldap.h check.h \ + qldap-ldaplib.h qldap-errno.h qldap-debug.h env.h auto_usera.h \ + auto_uids.h fmt.h sig.h +- ./compile $(LDAPFLAGS) $(HDIRMAKE) $(LDAPINCLUDES) qmail-lspawn.c ++ ./compile $(LDAPFLAGS) $(HDIRMAKE) $(LDAPINCLUDES) $(INCTAI) ++ qmail-lspawn.c + + qmail-newmrh: \ + load qmail-newmrh.o cdbmss.o getln.a open.a cdbmake.a seek.a case.a \ +diff -BbuN qmail-ldap/qmail-lspawn.c qmail-test/qmail-lspawn.c +--- qmail-ldap/qmail-lspawn.c Mon Jul 3 13:22:01 2000 ++++ qmail-test/qmail-lspawn.c Thu Jul 20 22:55:53 2000 +@@ -31,6 +31,7 @@ + #include "str.h" + #include + #include ++#include "qldap-profile.h" + + char *aliasempty; + +@@ -369,7 +370,9 @@ + extra[6].what = 0; + + /* do the search for the email address */ ++ start_timing(0, "first ldap_lookup"); + ret = ldap_lookup(&search, attrs, &info, extra); ++ stop_timing(0); + if (!stralloc_copys(&filter, "")) _exit(QLX_NOMEM); + /* XXX doesn't free mem */ + if ( ret != 0 && qldap_errno == LDAP_NOSUCH ) { +@@ -391,8 +394,10 @@ + + debug(16, "retry with filter '%s'\n", filter.s); + /* do the search for the email address */ ++ start_timing(0, "first ldap_lookup"); + ret = ldap_lookup(&search, attrs, &info, extra); + /* count the results, we must have exactly one */ ++ stop_timing(0); + } + alloc_free(filter.s); filter.s = 0; + if ( ret != 0 ) { diff -uN qmail-1.03/qldap-debug.c qmail-ldap/qldap-debug.c --- qmail-1.03/qldap-debug.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qldap-debug.c Tue Sep 4 00:19:34 2001 @@ -0,0 +1,125 @@ +/* qldap-debug.c, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#include "output.h" +#include "qldap-debug.h" +#include "env.h" +#include "scan.h" +#include "readwrite.h" + +#include + +#ifdef ENABLE_PROFILE +#include +#endif + +#ifdef DEBUG + +/* + * Known LOGLEVELs: + * 1 = Error, only errors are reported (not verbose) + * 2 = Warning, errors and warnings are reported (normaly not verbose) + * 4 = Info, print some information (login name and success or fail) + * 8 = Info^2 (more info), session forwarding and maildirmake ... + * 16 = Debug, more information about authentication etc. + * 32 = Debug^2 (more debug info), even more ... + * 64 = LDAP-Debug, show everything in the ldap-module + *128 = some more LDAP-Debug stuff (good for ldap test tool) + *256 = PASSWD-Debug, this shows the encrypted and clear text passwords + * so use it with care + *1024= profiling output (if compiled with profile support) + */ + +#define LOGLEN 256 +static int addLOG; +static unsigned long loglevel; +substdio sslog; +char logbuffer[LOGLEN]; +void log_init(int fd, unsigned long mask, int via_spawn) +/* + * Known LOGLEVELs: + */ +{ + char *a = env_get("LOGLEVEL"); + + loglevel = 0; + addLOG = via_spawn; + if ( a && *a ) { + scan_ulong(a, &loglevel); + } else if ((a = env_get("DEBUGLEVEL")) && *a ) { + scan_ulong(a, &loglevel); + } + loglevel &= mask; + + substdio_fdbuf(&sslog, write, fd, logbuffer, sizeof(logbuffer) ); + log(1, "LOGLEVEL set to %i\n", loglevel); +} + +void log(unsigned long level, char *fmt, ...) +/* see va_output (output.c) */ +{ + va_list ap; + char ch; + + va_start(ap, fmt); + if ( ! ( loglevel & level ) ) return; + ch = 15; + if ( addLOG ) if ( substdio_put(&sslog, &ch, 1) ) return; + va_output(&sslog, fmt, ap); + va_end(ap); + ch = 16; + if ( addLOG ) if ( substdio_put(&sslog, &ch, 1) ) return; + if ( substdio_flush(&sslog) == -1 ) return; +} + +/* use logstart, logadd and logend with care, if there is no corresponding + start or end starnge messages will be loged or some important messages + will be lost */ +void logstart(unsigned long level, char *fmt, ...) +{ + va_list ap; + char ch; + + va_start(ap, fmt); + if ( ! ( loglevel & level ) ) return; + ch = 15; + if ( addLOG ) if ( substdio_put(&sslog, &ch, 1) ) return; + va_output(&sslog, fmt, ap); + va_end(ap); +} + +void logadd(unsigned long level, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if ( ! ( loglevel & level ) ) return; + va_output(&sslog, fmt, ap); + va_end(ap); +} + +void logend(unsigned long level, char *fmt, ...) +{ + va_list ap; + char ch; + + va_start(ap, fmt); + if ( ! ( loglevel & level ) ) return; + va_output(&sslog, fmt, ap); + va_end(ap); + ch = 16; + if ( addLOG ) if ( substdio_put(&sslog, &ch, 1) ) return; + if ( substdio_flush(&sslog) == -1 ) return; +} + +void profile(char *s) +{ +#ifdef ENABLE_PROFILE + char buf[TAIA_PACK]; + struct taia t; + + taia_now(&t); + taia_pack(buf,&t); + log(LOG_PROFILE, "PROFILE: %s @%s\n", s, buf); +#endif +} +#endif + diff -uN qmail-1.03/qldap-debug.h qmail-ldap/qldap-debug.h --- qmail-1.03/qldap-debug.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qldap-debug.h Tue Sep 4 00:19:34 2001 @@ -0,0 +1,23 @@ +#ifndef __QLDAP_DEBUG_H__ +#define __QLDAP_DEBUG_H__ + +#ifdef DEBUG +void log_init(int fd, unsigned long mask, int via_spawn); +void log(unsigned long level, char *fmt, ...); +void logstart(unsigned long level, char *fmt, ...); +void logadd(unsigned long level, char *fmt, ...); +void logend(unsigned long level, char *fmt, ...); +void profile(char *s); + +#define PROFILE(s) profile(s) +#else +static void log_init() {}; +static void log() {}; +static void logstart() {}; +static void logadd() {}; +static void logend() {}; + +#define PROFILE(s) +#endif + +#endif diff -uN qmail-1.03/qldap-errno.c qmail-ldap/qldap-errno.c --- qmail-1.03/qldap-errno.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qldap-errno.c Fri May 19 22:47:16 2000 @@ -0,0 +1,55 @@ +/* qldap-errno.c */ +#include "qldap-errno.h" +#include "error.h" + +int qldap_errno; + +char *qldap_err_str(int enbr ) +/* returns a string that corresponds to the qldap_errno */ +{ + switch (enbr) { + case ERRNO: + return error_str(errno); + case LDAP_INIT: + return "initalizing of ldap connection failed"; + case LDAP_BIND: + return "binding to ldap server failed"; + case LDAP_SEARCH: + return "ldap_search failed"; + case LDAP_NOSUCH: + return "no such object"; + case LDAP_REBIND: + return "rebinding to ldap server failed"; + case LDAP_NEEDED: + return "needed object/field is missing"; + case LDAP_COUNT: + return "too many entries found"; + + case AUTH_FAILED: + return "authorization failed wrong password"; + case AUTH_ERROR: + return "error on authentication"; + case ILL_PATH: + return "illegal path"; + case ILL_AUTH: + return "illegal authentication mode"; + case BADCLUSTER: + return "bad settings for clustering"; + case ACC_DISABLED: + return "account disabled"; + case AUTH_PANIC: + return "unexpected event, PANIC"; + case AUTH_EXEC: + return "unable to start subprogram"; + + case MAILDIR_CORRUPT: + return "maildir seems to be corrupted"; + case MAILDIR_CRASHED: + return "dirmaker script crashed"; + case MAILDIR_BADEXIT: + return "dirmaker exit status not zero"; + default: + return "unknown error occured"; + } +} + diff -uN qmail-1.03/qldap-errno.h qmail-ldap/qldap-errno.h --- qmail-1.03/qldap-errno.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qldap-errno.h Thu Mar 1 20:37:03 2001 @@ -0,0 +1,42 @@ +/* qldap-errno.h, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#ifndef __QLDAP_ERRNO_H__ +#define __QLDAP_ERRNO_H__ + +extern int qldap_errno; + +/* generic errors */ +#define ERRNO 1 /* check errno for more info */ + +/* first the LDAP errnos */ +#define LDAP_INIT 2 /* error while initalizing ldap connection */ +#define LDAP_BIND 3 /* error while binding to ldap server */ +#define LDAP_BIND_UNREACH 31 /* ldap server down or unreachable */ +#define LDAP_SEARCH 4 /* error on ldap search */ +#define LDAP_SEARCH_TIMEOUT 41 /* timeout on ldap search */ +#define LDAP_NOSUCH 5 /* no such ldap db entry */ +#define LDAP_REBIND 6 /* error while rebinding to ldap server */ +#define LDAP_ERRNO ERRNO /* check errno for more info */ +#define LDAP_NEEDED 7 /* needed db field missing */ +#define LDAP_COUNT 8 /* too many entries found */ + +/* now the checkpassword errnos */ +#define AUTH_FAILED 9 /* authorization failed wrong password */ +#define AUTH_ERROR 10 /* error on authentication */ +#define AUTH_NOSUCH LDAP_NOSUCH /* no such user */ +#define ILL_PATH 11 /* illegal path */ +#define ILL_AUTH 12 /* illegal authentication mode */ +#define AUTH_NEEDED LDAP_NEEDED /* needed authentication field missing */ +#define BADCLUSTER 13 /* bad settings for clustering */ +#define ACC_DISABLED 14 /* account disabled */ +#define AUTH_PANIC 15 /* PANIC, ARRGGG ... */ +#define AUTH_EXEC 16 /* unable to start subprogram */ + +/* now the maildirmake errnos */ +#define MAILDIR_CORRUPT 17 /* maildir seems to be corrupted */ +#define MAILDIR_CRASHED 18 /* dirmaker script crashed */ +#define MAILDIR_BADEXIT 19 /* dirmaker exit status not zero */ + +char *qldap_err_str(int enbr ); +/* returns a string that corresponds to the qldap_errno */ + +#endif diff -uN qmail-1.03/qldap-ldaplib.c qmail-ldap/qldap-ldaplib.c --- qmail-1.03/qldap-ldaplib.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qldap-ldaplib.c Sun Sep 30 14:58:57 2001 @@ -0,0 +1,670 @@ +/* qldap-ldaplib.c, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#include "qmail-ldap.h" +#include "qldap-errno.h" +#include +#include +#include "qldap-ldaplib.h" +#include "alloc.h" +#include "stralloc.h" +#include "error.h" +#include /* for ERANGE et al. */ +#include "control.h" +#include "auto_qmail.h" +#include "str.h" +#include "byte.h" +#include "qldap-debug.h" +#include "fmt.h" +#include /* for ldap search timeout */ +#ifdef QLDAP_CLUSTER +#include "constmap.h" +#endif + +#define QLDAP_PORT LDAP_PORT +#ifndef PORT_LDAP /* this is for testing purposes, so you can overwrite + this port via a simple -D argument */ +#define PORT_LDAP QLDAP_PORT +#endif + +/* system libraries for syscalls */ +/* #include */ + +/* internal functions */ +static int ldap_get_userinfo(LDAP *ld, LDAPMessage *msg, userinfo *info); +static int ldap_get_extrainfo(LDAP *ld, LDAPMessage *msg, extrainfo *info); + +/* internal data structures */ +stralloc qldap_me = {0}; /* server name, also external visible */ +stralloc qldap_objectclass = {0}; /* the search objectclass, external visible */ + +#ifdef QLDAP_CLUSTER +struct constmap qldap_mailhosts; /* mailhost constmap for clustering */ +static stralloc qldap_mh = {0}; /* buffer for constmap */ +#endif + +/* internal use only vars */ +static stralloc qldap_server = {0}; /* name of ldap server */ +static stralloc qldap_basedn = {0}; /* the search basedn */ +static stralloc qldap_user = {0}; /* the ldap user ( for login ) */ +static stralloc qldap_password = {0}; /* the ldap login password */ + +static stralloc qldap_uid = {0}; /* UID if not specified in db */ +static stralloc qldap_gid = {0}; /* UID if not specified in db */ +static stralloc qldap_messagestore = {0}; /* prefix for maildirpaths */ +static long qldap_timeout = QLDAP_TIMEOUT; /* default timeout is 30 secs */ + +/* char replacement */ +static unsigned int replace(char *s, register unsigned int len, char f, char r) +{ + register char *t; + register int count = 0; + + t=s; + for(;;) { + if (!len) return count; if (*t == f) { *t=r; count++; } ++t; --len; + if (!len) return count; if (*t == f) { *t=r; count++; } ++t; --len; + if (!len) return count; if (*t == f) { *t=r; count++; } ++t; --len; + if (!len) return count; if (*t == f) { *t=r; count++; } ++t; --len; + } +} + +int init_ldap(int *localdelivery, int *cluster, int *bind, stralloc *hm, + stralloc *dotmode, stralloc *quota, stralloc *quotawarning) +/* reads all necesary control files and makes everything ready for a ldap lookup + * Returns 0 if successful else -1 is returned and errno is set. + * Localdelivery is set to 0 or 1 as in ~control/ldaplocaldelivery specified. + * Also bind and cluster are set to 0 and 1 as in their files described */ +{ + char *ctrl_file; + char *cf; + char *t; + + if ( localdelivery != 0 ) + *localdelivery = 1; /* localdelivery is on (DEFAULT) */ + if ( cluster != 0 ) + *cluster = 0; /* clustering normaly off */ + if ( bind != 0 ) + *bind = 0; /* bind normaly off */ + + if ( ! (ctrl_file = alloc(64 + str_len(auto_qmail) + 2 ) )) return -1; + /* XXX 64 char should be enough to handle all ~control/ files */ + cf = ctrl_file; + cf += fmt_str(cf, auto_qmail); + *cf++ = '/'; + + t = cf; + t += fmt_strn(cf, "control/me", 64); *t=0; + if (control_rldef(&qldap_me, ctrl_file, 0, "") == -1) return -1; + if (!stralloc_0(&qldap_me)) return -1; + log(64, "init_ldap: control/me: %s\n", qldap_me.s); + + t = cf; + t += fmt_strn(cf, "control/ldapserver", 64); *t=0; + if (control_rldef(&qldap_server, ctrl_file, 0, (char *) 0) != 1) { + return -1; /* also here the errno should be set by control_* */ + } + if (!stralloc_0(&qldap_server)) return -1; + log(64, "init_ldap: control/ldapserver: %s\n", qldap_server.s); + + t = cf; + t += fmt_strn(cf, "control/ldapbasedn", 64); *t=0; + if (control_rldef(&qldap_basedn, ctrl_file, 0, "") == -1) return -1; + if (!stralloc_0(&qldap_basedn)) return -1; /* also stralloc sets errno's */ + log(64, "init_ldap: control/ldapbasedn: %s\n", qldap_basedn.s); + + t = cf; + t += fmt_strn(cf, "control/ldapobjectclass", 64); *t=0; + if (control_rldef(&qldap_objectclass, ctrl_file, 0, (char *) 0) == -1) return -1; + log(64, "init_ldap: control/ldapobjectclass: %S\n", &qldap_objectclass); + + t = cf; + t += fmt_strn(cf, "control/ldaplogin", 64); *t=0; + if (control_rldef(&qldap_user, ctrl_file, 0, "") == -1) return -1; + if (!stralloc_0(&qldap_user)) return -1; + log(64, "init_ldap: control/ldaplogin: %s\n", qldap_user.s); + + t = cf; + t += fmt_strn(cf, "control/ldappassword", 64); *t=0; + if (control_rldef(&qldap_password, ctrl_file, 0, "") == -1) + return -1; + if (!stralloc_0(&qldap_password)) return -1; + log(64, "init_ldap: control/ldappassword: %s\n", qldap_password.s); + + t = cf; + t += fmt_strn(cf, "control/ldapuid", 64); *t=0; + if (control_rldef(&qldap_uid, ctrl_file, 0, "") == -1) return -1; + if (!stralloc_0(&qldap_uid)) return -1; + log(64, "init_ldap: control/ldapuid: %s\n", qldap_uid.s); + + t = cf; + t += fmt_strn(cf, "control/ldapgid", 64); *t=0; + if (control_rldef(&qldap_gid, ctrl_file, 0, "") == -1) return -1; + if (!stralloc_0(&qldap_gid)) return -1; + log(64, "init_ldap: control/ldapgid: %s\n", qldap_gid.s); + + t = cf; + t += fmt_strn(cf, "control/ldapmessagestore", 64); *t=0; + if (control_rldef(&qldap_messagestore, ctrl_file, 0, "") == -1) + return -1; + if (!stralloc_0(&qldap_messagestore)) return -1; + log(64, "init_ldap: control/ldapmessagestore: %s\n", + qldap_messagestore.s); + + t = cf; + t += fmt_strn(cf, "control/ldaptimeout", 64); *t=0; + if (control_readint(&qldap_timeout, ctrl_file) == -1) + return -1; + log(64, "init_ldap: control/ldaptimeout: %i\n", qldap_timeout); + + if (localdelivery != 0) { + t = cf; + t += fmt_strn(cf, "control/ldaplocaldelivery", 64); *t=0; + if (control_readint(localdelivery, ctrl_file) == -1) + return -1; + log(64, "init_ldap: control/ldaplocaldelivery: %i\n", *localdelivery); + } +#ifdef QLDAP_CLUSTER + if (cluster != 0 ) { + t = cf; + t += fmt_strn(cf, "control/ldapcluster", 64); *t=0; + if (control_readint(cluster, ctrl_file) == -1) return -1; + log(64, "init_ldap: control/ldapcluster: %i\n", *cluster); + } + if ( cluster != 0 && *cluster == 1 ) { + t = cf; + t += fmt_strn(cf, "control/ldapclusterhosts", 64); *t=0; + if (control_readfile(&qldap_mh,ctrl_file,0) == -1) + return -1; + log(64, "init_ldap: control/ldapclusterhosts: read\n"); + if (!constmap_init(&qldap_mailhosts, qldap_mh.s, qldap_mh.len,0)) + return -1; + } else { + if (!constmap_init(&qldap_mailhosts, "", 0, 0) ) + return -1; + } +#endif + if ( bind != 0 ) { + t = cf; + t += fmt_strn(cf, "control/ldaprebind", 64); *t=0; + if (control_readint(bind, ctrl_file) == -1) return -1; + log(64, "init_ldap: control/ldaprebind: %i\n", *bind); + } + + if ( hm != 0 ) { + t = cf; + t += fmt_strn(cf, "control/dirmaker", 64); *t=0; + if (control_rldef(hm, ctrl_file, 0, "") == -1) return -1; + if (!stralloc_0(hm)) return -1; + log(64, "init_ldap: control/dirmaker: %s\n", hm->s); + } + + if ( dotmode != 0 ) { + t = cf; + t += fmt_strn(cf, "control/ldapdefaultdotmode", 64); *t=0; + if (control_rldef(dotmode, ctrl_file, 0, "ldaponly") == -1) return -1; + if (!stralloc_0(dotmode)) return -1; + } + + if ( quota != 0 ) { + t = cf; + t += fmt_strn(cf, "control/ldapdefaultquota", 64); *t=0; + if (control_rldef(quota, ctrl_file, 0, "") == -1) + return -1; + if (!stralloc_0(quota)) return -1; + } + + if ( quotawarning != 0 ) { + t = cf; + t += fmt_strn(cf, "control/quotawarning", 64); *t=0; + if (control_readfile(quotawarning, ctrl_file, 0) == 1 ) { + replace(quotawarning->s, quotawarning->len, '\0', '\n'); + if (!stralloc_0(quotawarning)) return -1; + } else { + if (!stralloc_copys(quotawarning, "") ) return -1; + } + } + + alloc_free(ctrl_file); + return 0; +} + +static LDAP *ld; +/* XXX THIS IS A UGLY HACK */ + +int qldap_open(void) +/* Open a connection to the ldap server */ +/* XXX THIS IS A UGLY HACK */ +{ + int rc; + int version; + +#ifndef USE_CLDAP + log(128, "qldap_open: "); + /* allocate the connection */ + if ( (ld = ldap_init(qldap_server.s,PORT_LDAP)) == 0 ) { + qldap_errno = LDAP_INIT; + return -1; + } + log(128, "init successful"); + +#ifdef LDAP_OPT_PROTOCOL_VERSION + /* set LDAP connection options (only with Mozilla LDAP SDK) */ + version = LDAP_VERSION2; + if ( ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version) + != LDAP_SUCCESS ) { + qldap_errno = LDAP_INIT; + return -1; + } + log(128, ", set_option successful"); +#endif + + /* connect to the LDAP server */ + if ( (rc = ldap_simple_bind_s(ld,qldap_user.s,qldap_password.s)) + != LDAP_SUCCESS ) { + log(128, ", bind NOT successful (%s)\n", ldap_err2string(rc) ); + + /* probably more detailed information should be returned, eg.: + LDAP_STRONG_AUTH_NOT_SUPPORTED, + LDAP_STRONG_AUTH_REQUIRED, + *LDAP_INAPPROPRIATE_AUTH*, + *LDAP_INVALID_CREDENTIALS*, + LDAP_AUTH_UNKNOWN + */ + if (rc == LDAP_SERVER_DOWN) { + qldap_errno = LDAP_BIND_UNREACH; + return -1; + } + else { + qldap_errno = LDAP_BIND; + return -1; + } + } + log(128, ", bind successful\n"); + return 0; +} + + +int qldap_lookup(searchinfo *search, char **attrs, userinfo *info, + extrainfo *extra) +/* searches a db entry as specified in search, and fills up info and extra with + * the coresponding db entries or NULL if not available. + * Returns 0 if a entry was found, 1 if more than one or no corresponding entry + * was found. On error it returns -1 and sets the appropriate qldap_errno. */ +{ + LDAPMessage *res, *msg; + char *dn; + int rc; + int num_entries; + struct timeval ldaptimeout = {0}; + + /* set up the ldap search timeout */ + ldaptimeout.tv_sec = qldap_timeout; + ldaptimeout.tv_usec = 0; + + /* do the search for the login uid */ + if ( (rc = ldap_search_st(ld, qldap_basedn.s, LDAP_SCOPE_SUBTREE, + search->filter, attrs, 0, &ldaptimeout, &res )) != LDAP_SUCCESS ) { + log(64, "qldap_lookup: search for %s failed (%s)\n", + search->filter, ldap_err2string(rc) ); + + /* probably more detailed information should be returned, eg.: + LDAP_TIMELIMIT_EXCEEDED, + LDAP_SIZELIMIT_EXCEEDED, + LDAP_PARTIAL_RESULTS, + LDAP_INSUFFICIENT_ACCESS, + LDAP_BUSY, + LDAP_UNAVAILABLE, + LDAP_UNWILLING_TO_PERFORM, + LDAP_TIMEOUT + */ + + switch(rc) + { + case LDAP_TIMEOUT: + case LDAP_TIMELIMIT_EXCEEDED: + case LDAP_BUSY: + qldap_errno = LDAP_SEARCH_TIMEOUT; + + default: + qldap_errno = LDAP_SEARCH; + } + + return -1; + } +#else /* USE_CLDAP */ + log(128, "qldap_lookup: "); + /* allocate the connection */ + if ( (ld = cldap_open(qldap_server.s,PORT_LDAP)) == 0 ) { + qldap_errno = LDAP_INIT; + return -1; + } + log(128, "cldap_open succesful\n"); + /* do the search for the login uid */ + if ( (rc = cldap_search_s(ld, qldap_basedn.s, LDAP_SCOPE_SUBTREE, + search->filter, attrs, 0, &res, qldap_user.s )) + != LDAP_SUCCESS ) + { + log(64, "qldap_lookup: csearch for %s failed (%s)\n", + search->filter, ldap_err2string(rc) ); + qldap_errno = LDAP_SEARCH; + return -1; + } +#endif + + log(128, "qldap_lookup: search for %s succeeded\n", search->filter); + + /* go to the first entry */ + msg = ldap_first_entry(ld,res); + + /* count the results, we must have exactly one */ + if ( (num_entries = ldap_count_entries(ld,msg)) != 1) { + log(64, "qldap_lookup: Too many (less) entries found (%i)\n", + num_entries); + if ( num_entries ) + qldap_errno = LDAP_COUNT; + else + qldap_errno = LDAP_NOSUCH; + return -1; + } + + /* get the dn and free it (we dont need it, to prevent memory leaks) + * but first try to rebind with the password */ + dn = ldap_get_dn(ld,msg); + if ( search->bindpw ) { + if ( dn == 0 ) { + qldap_errno = LDAP_REBIND; + return -1; + } + /* do re-bind here */ + if ( (rc = ldap_simple_bind_s(ld,dn,search->bindpw)) != LDAP_SUCCESS) { + alloc_free(dn); + log(64, "qldap_lookup: rebind with %s failed (%s)", + dn, ldap_err2string(rc) ); + search->bind_ok = 0; + qldap_errno = LDAP_REBIND; + return -1; + } + search->bind_ok = 1; + log(128, "qldap_lookup: rebind with %s succeeded", dn ); + } + if ( dn != 0 ) alloc_free(dn); + + if ( ldap_get_userinfo(ld, msg, info) == -1 ) { + return -1; /* function sets qldap_errno */ + } + + if ( ldap_get_extrainfo(ld, msg, extra) == -1 ) { + return -1; /* function sets qldap_errno */ + } + + /* ok, we finished, lets clean up and disconnect from the LDAP server */ + /* XXX we should also free msg and res */ + /* ldap_msgfree(msg); */ /* with this I get segv's :-( don't ask me why */ + ldap_msgfree(res); + return 0; +} + +int qldap_close(void) +/* Close a established ldap connection */ +/* XXX THIS IS A UGLY HACK */ +{ +#ifndef USE_CLDAP + ldap_unbind_s(ld); +#else /* USE_CLDAP */ + cldap_close(ld); +#endif + return 0; +} + +static int ldap_get_mms(char **mmsval, char **hdval, char **mms, char **homedir); + +static int ldap_get_userinfo(LDAP *ld, LDAPMessage *msg, userinfo *info) +/* NOTE: all default qldap_* strallocs are 0-terminated */ +/* Thanks to Tony Abbott for the bug fixes */ +{ + char **vals; + char **vals2; + int i; + + if (! info ) return 0; + /* get those entries LDAP_QMAILUID, LDAP_QMAILGID, LDAP_MAILSTORE, + * LDAP_MAILHOST, LDAP_ISACTIVE and LDAP_UID */ + log(64, "ldap_get_userinfo: %s: ", LDAP_QMAILUID); + if ( (vals = ldap_get_values(ld,msg,LDAP_QMAILUID)) != 0 ) { + if ( (info->uid = alloc( str_len( vals[0] ) + 1 ) ) == 0 ) { + qldap_errno = LDAP_ERRNO; + return -1; + } + log(64, "%s (from server)\n", vals[0]); + str_copy( info->uid, vals[0] ); + } else { + if (!( qldap_uid.s && qldap_uid.s[0] ) ) { + log(64, "undefined\n"); + qldap_errno = LDAP_NEEDED; + return -1; + } + if ( (info->uid = alloc( qldap_uid.len ) ) == 0 ) { + qldap_errno = LDAP_ERRNO; + return -1; + } + log(64, "%s (default)\n", qldap_uid.s); + str_copy( info->uid, qldap_uid.s ); + } + ldap_value_free(vals); + + log(64, "ldap_get_userinfo: %s: ", LDAP_QMAILGID); + if ( (vals = ldap_get_values(ld,msg,LDAP_QMAILGID)) != 0 ) { + if ( (info->gid = alloc( str_len( vals[0] ) + 1 ) ) == 0 ) { + qldap_errno = LDAP_ERRNO; + return -1; + } + log(64, "%s (from server)\n", vals[0]); + str_copy( info->gid, vals[0] ); + } else { + if (!( qldap_gid.s && qldap_gid.s[0] ) ) { + log(64, "undefined\n"); + qldap_errno = LDAP_NEEDED; + return -1; + } + if ( (info->gid = alloc( qldap_gid.len ) ) == 0 ) { + qldap_errno = LDAP_ERRNO; + return -1; + } + log(64, "%s (default)\n", qldap_gid.s); + str_copy( info->gid, qldap_gid.s ); + } + ldap_value_free(vals); + + /* get the username for delivery on the local system */ + log(64, "ldap_get_userinfo: %s: ", LDAP_UID); + if ( (vals = ldap_get_values(ld,msg,LDAP_UID)) != 0 ) { + if ( (info->user = alloc( str_len( vals[0] ) + 1 ) ) == 0 ) { + qldap_errno = LDAP_ERRNO; + return -1; + } + log(64, "%s (from server)\n", vals[0]); + str_copy( info->user, vals[0] ); + } else { + log(64, "undefined but NEEDED !!!!!!!\n"); + qldap_errno = LDAP_NEEDED; + return -1; + } + ldap_value_free(vals); + + /* check if the ldap entry is active */ + log(64, "ldap_get_userinfo: %s: ", LDAP_ISACTIVE); + if ( (vals = ldap_get_values(ld,msg,LDAP_ISACTIVE)) != 0 ) { + log(64, "%s (from server)\n", vals[0]); + if ( !str_diff(ISACTIVE_BOUNCE, vals[0]) ) + info->status = STATUS_BOUNCE; + else if ( !str_diff(ISACTIVE_DELETE, vals[0]) ) + info->status = STATUS_BOUNCE; + else if ( !str_diff(ISACTIVE_NOPOP, vals[0]) ) + info->status = STATUS_NOPOP; + else info->status = STATUS_OK; + } else { + log(64, "undefined\n"); + info->status = STATUS_UNDEF; + } + ldap_value_free(vals); + + log(64, "ldap_get_userinfo: %s: ", LDAP_MAILHOST); + if ( (vals = ldap_get_values(ld,msg,LDAP_MAILHOST)) != 0 ) { + if ( (info->host = alloc( str_len( vals[0] ) + 1 ) ) == 0 ) { + qldap_errno = LDAP_ERRNO; + return -1; + } + log(64, "%s (from server)\n", vals[0]); + str_copy( info->host, vals[0] ); + } else { + log(64, "undefined\n"); + info->host = 0; + } + ldap_value_free(vals); + + log(64, "ldap_get_userinfo: %s & %s: \n", LDAP_MAILSTORE, LDAP_HOMEDIR); + vals = ldap_get_values(ld,msg,LDAP_MAILSTORE); + vals2 = ldap_get_values(ld,msg,LDAP_HOMEDIR); + i = ldap_get_mms(vals, vals2, &(info->mms), &(info->homedir)); + log(64, "%s=%s & %s=%s\n", LDAP_HOMEDIR, info->homedir, + LDAP_MAILSTORE, info->mms); + ldap_value_free(vals); + ldap_value_free(vals2); + if ( i == -1 ) { + /* ldap_get_mms sets qldap_errno */ + return -1; + } + return 0; +} + +static int ldap_get_extrainfo(LDAP *ld, LDAPMessage *msg, extrainfo *info) +/* this function moves just some pointers */ +{ + int i; + + if (! info ) return 0; + for ( i = 0; info[i].what != 0 ; i++ ) { + log(64, "ldap_get_extrainfo: %s: ", info[i].what); + info[i].vals = ldap_get_values(ld,msg,info[i].what); + log(64, " %s\n", + info[i].vals?info[i].vals[0]:"nothing found"); + /* free info[i].vals with ldap_value_free(info[i].vals) */ + } + return 0; +} + +static int ldap_get_mms(char **mmsval, char **hdval, char **mms, char **homedir) +{ + int i; + int s; + + if ( hdval ) { + if ( hdval[0][0] != '/' ) { + log(64, "non absolute homedirectory path!\n"); + qldap_errno = LDAP_NEEDED; + return -1; + } + if ( (*homedir = alloc( str_len( hdval[0] ) + 1 ) ) == 0 ) { + qldap_errno = LDAP_ERRNO; + return -1; + } + log(64, "%s=%s (from server)\n", LDAP_HOMEDIR, hdval[0]); + str_copy( *homedir, hdval[0] ); + } else { + log(64, "%s=undefined\n", LDAP_HOMEDIR); + *homedir = 0; + } + if ( mmsval ) { + log(64, "%s=%s (from server)\n", LDAP_MAILSTORE, mmsval[0]); + if ( mmsval[0][0] != '/' ) { + /* local path, use ldapmessagestore as prefix or return a error */ + if ( (!qldap_messagestore.s || qldap_messagestore.s[0] != '/') + && *homedir == 0 ) { + log(64, "non absolute path but neither ctrl/ldapmessagestore nor homedir defined!\n"); + qldap_errno = LDAP_NEEDED; + return -1; + } + i = 0; s = -1; + if ( *homedir == 0 ) { + log(64, " using %s as prefix\n", qldap_messagestore.s); + /* XXX if both homedir and ldapmms are defined homedir has + * higher priority (ldapmms will be ignored (not prefixed ) ) */ + if ( qldap_messagestore.s[qldap_messagestore.len - 1] != '/' ) { + /* arrg need to add a / between the two */ + s = 0; + } + i = qldap_messagestore.len + s; + /* qldap_mms is one char too long so reduce the length */ + } + i += str_len( mmsval[0] ) + 1; + if ( (*mms = alloc( i ) ) == 0 ) { + qldap_errno = LDAP_ERRNO; + return -1; + } + if ( *homedir == 0) { + str_copy( *mms, qldap_messagestore.s ); + if ( s == 0 ) str_copy( *mms + str_len(*mms), "/" ); + /* str_cat done with str_copy because djb has no str_cat :-( */ + str_copy( *mms + str_len(*mms), mmsval[0] ); + } else { + str_copy( *mms, mmsval[0] ); + } + } else { + i = str_len( mmsval[0] ) + 1; + if ( (*mms = alloc( i ) ) == 0 ) { + qldap_errno = LDAP_ERRNO; + return -1; + } + str_copy( *mms, mmsval[0] ); + } + } else { + log(64, "%s=undefined\n", LDAP_MAILSTORE); + *mms = 0; + } + return 0; +} + +int escape_forldap(stralloc *toescape) +/* Under LDAP, '(', ')', '\', '*' and '\0' have to be escaped with '\' */ +{ + unsigned int len; + unsigned int newlen; + char x; + char *t; + char *s; + char *tmp; + + newlen = 0; + len = toescape->len; + s = toescape->s; + + if ( s[len-1] == '\0' ) len-- ; /* this handles \0 terminated strallocs */ + + if ( ( tmp = alloc( len*2 ) ) == 0 ) return 0; + t = tmp; + + for(;;) { +#ifndef LDAP_ESCAPE_BUG + if(!len) break; + x = *s; + if (x == '*' || x == '(' || x == ')' || x == '\\' || x == '\0' ) { + *t++ = '\\' ; newlen++; + } + *t++ = *s++; + len--; newlen++; +#else +#warning __LDAP_ESCAPE_BUG__IS__ON__ + if(!len) break; + x = *s; + if (x == '*' || x == '(' || x == ')' || x == '\\' || x == '\0' ) + *t++ = '_' ; + else *t++ = *s++; + len--; newlen++; +#endif + } + if (!stralloc_ready(toescape, newlen) ) return 0; + toescape->len = newlen; + byte_copy(toescape->s, newlen, tmp); + alloc_free(tmp); + return 1; +} + diff -uN qmail-1.03/qldap-ldaplib.h qmail-ldap/qldap-ldaplib.h --- qmail-1.03/qldap-ldaplib.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qldap-ldaplib.h Sun Sep 30 14:58:57 2001 @@ -0,0 +1,59 @@ +/* qldap-ldaplib.h, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#ifndef __QLDAPLIB_H__ +#define __QLDAPLIB_H__ +#include "stralloc.h" + +/* XXX this file and the corresponding .c file needs a major update */ + +typedef struct userinfo_t { + int status; + char *user; + char *uid; + char *gid; + char *mms; + char *homedir; + char *host; +} userinfo; + +typedef struct extrainfo_t { + char *what; + char **vals; +} extrainfo; + +typedef struct searchinfo_t { + int bind_ok; + char *bindpw; + char *filter; +} searchinfo; + +int init_ldap(int *localdelivery, int *cluster, int *bind, stralloc *hm, + stralloc *dotmode, stralloc *quota, stralloc *quotawarning); +/* reads all necesary control files and makes everything ready for a ldap lookup + * Returns 0 if successful else -1 is returned and errno is set. + * Localdelivery is set to 0 or 1 as in ~control/ldaplocaldelivery specified. + * Also bind and cluster are set to 0 and 1 as in their files described */ + +int qldap_open(void); +/* Open a connection to the ldap server */ +/* XXX THIS IS A UGLY HACK */ + +int qldap_lookup(searchinfo *search, char **attrs, userinfo *info, + extrainfo *extra); +/* searches a db entry as specified in search, and fills up info and extra with + * the coresponding db entries or NULL if not available. + * Returns 0 if a entry was found, 1 if more than one or no corresponding entry + * was found. On error it returns -1 and sets the appropriate qldap_errno. */ + +int qldap_close(void); +/* Close a established ldap connection */ +/* XXX THIS IS A UGLY HACK */ + +int escape_forldap(stralloc *toescape); +/* Under LDAP, '(', ')', '\', '*' and '\0' have to be escaped with '\' + * on success returns 1 else 0 */ + +extern void ldap_value_free(); +/* LDAP function to free **vals */ + +#endif + diff -uN qmail-1.03/qldap-log.c qmail-ldap/qldap-log.c --- qmail-1.03/qldap-log.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qldap-log.c Sat Jul 22 15:16:49 2000 @@ -0,0 +1,43 @@ +#include "substdio.h" +#include "qldap-log.h" + +/* level 0 = no logging + 1 = fatal errors + 2 = connection setup and warnings + 3 = verbose */ + +int loglevel = 0; + +void logpid(level) int level; +{ + char pidstring[FMT_ULONG]; + if (level > loglevel) return; + substdio_puts(subfderr,"qmail-smtpd "); + pidstring[fmt_ulong(pidstring,(unsigned long) getpid())] = 0; + substdio_puts(subfderr,pidstring); + substdio_puts(subfderr,": "); +} + +void logline(level,string) int level; char *string; +{ + if (level > loglevel) return; + logpid(); + substdio_puts(subfderr,string); + substdio_puts(subfderr,"\n"); + substdio_flush(subfderr); +} + +void logstring(level,string) int level; char *string; +{ + if (level > loglevel) return; + substdio_puts(subfderr,string); + substdio_puts(subfderr," "); +} + +void logflush(level) int level; +{ + if (level > loglevel) return; + substdio_puts(subfderr,"\n"); + substdio_flush(subfderr); +} + diff -uN qmail-1.03/qldap-log.h qmail-ldap/qldap-log.h --- qmail-1.03/qldap-log.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qldap-log.h Sat Jul 22 15:18:25 2000 @@ -0,0 +1,14 @@ +#ifndef __QLDAP_LOG_H__ +#define __QLDAP_LOG_H__ + +/* level 0 = no logging + 1 = fatal errors + 2 = connection setup and warnings + 3 = verbose */ + +void logpid(level) int level; +void logline(level,string) int level; char *string; +void logstring(level,string) int level; char *string; +void logflush(level) int level; + +#endif diff -uN qmail-1.03/qldap-mdm.c qmail-ldap/qldap-mdm.c --- qmail-1.03/qldap-mdm.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qldap-mdm.c Fri May 19 22:47:16 2000 @@ -0,0 +1,45 @@ +/* qldap-mdm.c, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#include "qldap-errno.h" +#include "wait.h" + + +int make_homedir(char *home, char *maildir, char *dirmaker) +/* executes the file specified with dirmaker returns 0 on success */ +/* XXX ~control/dirmaker has to be only at max writeable for root */ +{ +#ifdef AUTOHOMEDIRMAKE + /* do the auto homedir creation */ + int child; + char *(dirargs[3]); + int wstat; + + switch(child = fork()) { + case -1: + qldap_errno = ERRNO; + return -1; + case 0: + dirargs[0] = dirmaker; dirargs[1] = home; + dirargs[2] = maildir; dirargs[3] = 0; + execv(*dirargs,dirargs); + qldap_errno = ERRNO; + return -1; + } + + wait_pid(&wstat,child); + if (wait_crashed(wstat)) { + qldap_errno = MAILDIR_CRASHED; + return -1; + } + switch(wait_exitcode(wstat)) { + case 0: + return 0; + default: + qldap_errno = MAILDIR_BADEXIT; + return -1; + } +#endif +} + +/* XXX the maildirmake stuff is dirictly in qmail-local.c and qmail-pop3d.c + * XXX this is simpler and better (Perhaps I'll find a better way sometimes) ;-) */ +/* int make_maildir(...) */ diff -uN qmail-1.03/qldap-mdm.h qmail-ldap/qldap-mdm.h --- qmail-1.03/qldap-mdm.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qldap-mdm.h Mon Feb 14 13:11:55 2000 @@ -0,0 +1,10 @@ +/* qldap-mdm.h, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#ifndef __QLDAP_MDM_H__ +#define __QLDAP_MDM_H__ + +int make_homedir(char *home, char *maildir, char *dirmaker); +/* executes the file specified with dirmaker returns 0 on success */ + + +#endif + diff -uN qmail-1.03/qldap-profile.c qmail-ldap/qldap-profile.c --- qmail-1.03/qldap-profile.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qldap-profile.c Sat Jul 22 15:07:41 2000 @@ -0,0 +1,44 @@ +#include "taia.h" +#include "qldap-profile.h" +#include "qldap-debug.h" + +struct profile_t { + struct taia start; + char *function; +}; + +static struct profile_t profile_list[PROFILES_MAX]; + +void start_timing(int profile, char *function) +{ + if ( profile >= PROFILES_MAX ) { + debug(0x400, "Max Number of profiles exceeded\n"); + return; + } + + taia_now(&(profile_list[profile].start)); + +} + +void stop_timing(int profile) +{ + struct taia stop; + struct taia diff; + char nano[TAIA_FMTFRAC]; + unsigned long sec; + + if ( profile >= PROFILES_MAX ) { + debug(0x400, "Max Number of profiles exceeded\n"); + return; + } + + taia_now(&stop); + + taia_sub(&diff, &stop, &profile_list[profile].start); + nano[taia_fmtfrac(nano, &diff)] = 0; /* terminate to be sure */ + nano[7] = 0; /* only the first 6-7 figures are != 0, (nano seconds) */ + sec=(unsigned long) ((unsigned long long) diff.sec.x); + debug(0x400, "%s took %u.%s Sec\n", profile_list[profile].function, sec, nano); + +} + diff -uN qmail-1.03/qldap-profile.h qmail-ldap/qldap-profile.h --- qmail-1.03/qldap-profile.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qldap-profile.h Sat Jul 22 09:25:18 2000 @@ -0,0 +1,12 @@ +#ifndef __QLDAP_PROFILE_H__ +#define __QLDAP_PROFILE_H__ + +#define PROFILES_MAX 4 /* 4 concurrent profiles */ + +void start_timing(int profile, char *function); +/* start the timing of a function */ + +void stop_timing(int profile); +/* stop the timing of a function and print the difference */ + +#endif diff -uN qmail-1.03/qmail-ldap.h qmail-ldap/qmail-ldap.h --- qmail-1.03/qmail-ldap.h Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qmail-ldap.h Tue Apr 17 00:27:41 2001 @@ -0,0 +1,108 @@ +#ifndef _QMAIL_LDAP_H_ +#define _QMAIL_LDAP_H_ + +/* this is the "catch all" string + * ATTN: escape the string correctly, remember + * '(', ')', '\', '*' and '\0' have to be escaped with '\' + * Escaping is broken in OpenLDAP up to release 1.2.6, 1.2.7 is OK + */ +#define LDAP_CATCH_ALL "catchall" + +/* triger level for quotawarning (0-100) */ +#define QUOTA_WARNING_LEVEL 70 + +/* the maximum and minimum uid allowed */ +#define UID_MIN 100 +#define UID_MAX 65535 + +/* the maximum and minimum gid allowed */ +#define GID_MIN 100 +#define GID_MAX 65535 + +/* if the sanitycheck function should be less restricted for + * program pathes, this means especially that most special chars + * of the shell are allowed (like &, &, ;, and <,|,>) + * You should know what you are doing when disallowing this */ +/* 1 = restriced sanitycheck; 0 = less restriced sanitycheck */ +#define RESTRICT_PROG 1 + +/* ALIASDEVNULL replacement for the std. aliasempty for user with + * neither homeDirectory nor mailMessageStore defined */ +#define ALIASDEVNULL "|sh -c \"cat > /dev/null\"" +/* just pipe everything to /dev/null, you could also use a program/script + * to make a notify the postmaster if something like this happens. + * It's up to the reader to write such a simple script */ + +/* Default ldap search timeout. In seconds */ +#define QLDAP_TIMEOUT 30 + +/********************************************************************* + ldap variables used in qmail-lspawn and checkpassword +*********************************************************************/ +#define LDAP_MAIL "mail" +#define LDAP_MAILALTERNATE "mailAlternateAddress" +#define LDAP_QMAILUID "qmailUID" +#define LDAP_QMAILGID "qmailGID" +#define LDAP_MAILSTORE "mailMessageStore" +#define LDAP_HOMEDIR "homeDirectory" +#define LDAP_QUOTA "mailQuota" +#define LDAP_FORWARDS "mailForwardingAddress" +#define LDAP_PROGRAM "deliveryProgramPath" +#define LDAP_MAILHOST "mailHost" +#define LDAP_MODE "deliveryMode" +#define LDAP_REPLYTEXT "mailReplyText" +#define LDAP_DOTMODE "qmailDotMode" +#define LDAP_UID "uid" +#define LDAP_PASSWD "userPassword" +#define LDAP_OBJECTCLASS "objectclass" +#define LDAP_ISACTIVE "accountStatus" +#define LDAP_PURGE "qmailAccountPurge" + +#define DOTMODE_LDAPONLY "ldaponly" +#define DOTMODE_LDAPWITHPROG "ldapwithprog" +#define DOTMODE_DOTONLY "dotonly" +#define DOTMODE_BOTH "both" +#define DOTMODE_NONE "none" + +#define MODE_NORMAL "normal" +#define MODE_FORWARD "forwardonly" +#define MODE_NOMBOX "nombox" +#define MODE_LDELIVERY "localdelivery" +#define MODE_REPLY "reply" +#define MODE_ECHO "echo" + +#define ISACTIVE_BOUNCE "disabled" +#define ISACTIVE_DELETE "deleted" +#define ISACTIVE_NOPOP "nopop" +#define ISACTIVE_ACTIVE "active" + + +/********************************************************************* + normaly you can stop editing here +*********************************************************************/ +/* the same values as ints */ +#define STATUS_BOUNCE 2 +#define STATUS_NOPOP 1 +#define STATUS_OK 0 +#define STATUS_UNDEF -1 + +/* environment variables used between qmail-lspan and qmail-local + * and some other tools + */ +#define ENV_HOMEDIRMAKE "QLDAPAUTOHOMEDIRMAKE" + +#define ENV_QUOTA "QMAILQUOTA" +#define ENV_QUOTAWARNING "QMAILQUOTAWARNING" + +#define ENV_DOTMODE "QMAILDOTMODE" +#define ENV_MODE "QMAILMODE" +#define ENV_REPLYTEXT "QMAILREPLYTEXT" +#define ENV_FORWARDS "QMAILFORWARDS" +#define ENV_PROGRAM "QMAILDELIVERYPROGRAM" + +/* qmail-local.c only */ +#define DO_LDAP 0x01 +#define DO_DOT 0x02 +#define DO_BOTH (DO_LDAP | DO_DOT) + +#endif diff -uN qmail-1.03/qmail-ldaplookup.c qmail-ldap/qmail-ldaplookup.c --- qmail-1.03/qmail-ldaplookup.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qmail-ldaplookup.c Sun Sep 30 14:58:57 2001 @@ -0,0 +1,647 @@ +/* qmail-ldaplookup.c, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#include "qmail-ldap.h" +#include "qldap-errno.h" +#include "qldap-ldaplib.h" +#include "stralloc.h" +#include "alloc.h" +#include "error.h" +#include "strerr.h" +#include "str.h" +#include "output.h" +#include "qldap-debug.h" +#include "check.h" +#include "substdio.h" +#include "fmt.h" +#include "scan.h" +#include "readwrite.h" +#include "byte.h" +#include "getln.h" +#include +#include "digest_md4.h" +#include "digest_md5.h" +#include "digest_rmd160.h" +#include "digest_sha1.h" +#include "open.h" +#include "sgetopt.h" +#include "env.h" +#include "auto_break.h" +#include "constmap.h" + +/* Edit the first lines in the Makefile to enable local passwd lookups + * and debug options. + * To use shadow passwords under Solaris, uncomment the 'SHADOWOPTS' line + * in the Makefile. + * To use shadow passwords under Linux, uncomment the 'SHADOWOPTS' line and + * the 'SHADOWLIBS=-lshadow' line in the Makefile. + */ +#include +#ifdef PW_SHADOW +#include +#endif +#ifdef AIX +#include +#endif + +typedef enum mode_d { unset=0, uid, mail} mode_d; + +extern stralloc qldap_me; +extern stralloc qldap_objectclass; + +#ifdef QLDAP_CLUSTER +extern struct constmap qldap_mailhosts; +#endif + +int rebind; +int cluster; +int locald; + +stralloc homemaker = {0}; +stralloc defdot = {0}; +stralloc defquota = {0}; +stralloc quotawarning = {0}; +stralloc filter = {0}; +stralloc value = {0}; +stralloc home = {0}; +stralloc md = {0}; + +substdio ssout; +#define LEN 256 +char buffer[LEN]; + +static int cmp_passwd(unsigned char *clear, char *encrypted); +static void local_lookup(char *username, char *passwd); +int create_mail_filter(); +int create_uid_filter(); + +void usage() +{ + output(&ssout, "usage: qmail-ldaplookup [-d level] {-u uid [-p passwd] | -m mail}\n", optprogname); + output(&ssout, "\t-d level:\tsets log-level to level\n\ +\t-u uid: \tsearch for user id uid (pop3/imap lookup)\n\ +\t-p passwd:\tpassword for user id lookups (XXX only root)\n\ +\t-m mail:\tlookup the mailaddress\n"); + _exit(1); +} + +int main(int argc, char **argv) +{ + mode_d mode = unset; + userinfo info; + extrainfo extra[10]; + searchinfo search; + int ret, i, j; + unsigned long tid; + char *attrs[] = { + LDAP_UID, /* the first 6 attrs are default */ + LDAP_QMAILUID, + LDAP_QMAILGID, + LDAP_ISACTIVE, + LDAP_MAILHOST, + LDAP_MAILSTORE, + LDAP_HOMEDIR, + LDAP_QUOTA, /* the last 6 are extra infos */ + LDAP_MAIL, + LDAP_MAILALTERNATE, + LDAP_FORWARDS, + LDAP_PROGRAM, + LDAP_MODE, + LDAP_REPLYTEXT, + LDAP_DOTMODE, + LDAP_PASSWD, 0 }; /* passwd is extra */ + char* passwd = 0; + int opt; + int done; + + + substdio_fdbuf(&ssout, write, STDOUT, buffer, sizeof(buffer) ); + + while ( ( opt = getopt(argc, argv, "d:u:m:p:") ) != opteof) + switch (opt) { + case 'd': + if ( env_put2("LOGLEVEL", optarg) == 0 ) + strerr_die2x(1, "ERROR: setting loglevel", error_str(errno)); + break; + case 'u': + case 'm': + if ( mode != unset ) usage(); + mode = opt=='u'?uid:mail; + if ( ! stralloc_copys(&value, optarg) ) { + strerr_die2x(1, "ERROR: ", error_str(errno)); + } + break; + case 'p': + if ( mode != uid ) usage(); + passwd = optarg; + break; + default: + usage(); + } + if ( argc != optind || mode == unset ) usage(); + + log_init(STDERR, -1, 0); + + if ( init_ldap( &locald, &cluster, &rebind, &homemaker, &defdot, &defquota, + "awarning) == -1 ) { + strerr_die2x(1, "ERROR: init_ldap failed: ", qldap_err_str(qldap_errno)); + } + + output(&ssout, "init_ldap:\tpasswords are %scompared via rebind\n", + rebind?"":"not "); + output(&ssout, "\t\tlocaldelivery:\t %s\n\t\tclustering:\t %s\n", + locald?"on":"off", cluster?"on":"off"); + output(&ssout, "\t\tldapobjectclass: %S\n", &qldap_objectclass); + output(&ssout, "\t\thomedirmaker:\t %s\n", homemaker.len?homemaker.s:"undefined"); + output(&ssout, "\t\tdefaultDotMode:\t %s\n", defdot.s); + output(&ssout, "\t\tdefaultQuota:\t %s\n", defquota.len?defquota.s:"undedined"); + output(&ssout, "\t\tQuotaWarning:\n------\n%s\n------\n", + quotawarning.len?quotawarning.s:"undefined"); + + /* initalize the different objects */ + extra[9].what = 0; /* end marker for extra info */ + extra[0].what = LDAP_MAIL; + extra[1].what = LDAP_MAILALTERNATE; + extra[2].what = LDAP_QUOTA; + extra[3].what = LDAP_FORWARDS; + extra[4].what = LDAP_PROGRAM; + extra[5].what = LDAP_DOTMODE; + extra[6].what = LDAP_MODE; + extra[7].what = LDAP_REPLYTEXT; + if ( mode == mail ) { + extra[8].what = 0; /* under mail lookups no passwords are compared */ + attrs[15] = 0; + search.bindpw = 0; /* rebind off */ + } else if (!passwd || rebind ) { + extra[8].what = 0; /* passwd lookup not needed */ + attrs[15] = 0; + search.bindpw = 0; /* rebind off */ + if (rebind) { + search.bindpw = argv[3]; + } + } else { + extra[8].what = LDAP_PASSWD; /* need to get the crypted password */ + search.bindpw = 0; /* rebind off */ + } + if ( !escape_forldap(&value) ) { + strerr_die2x(1, "ERROR: escape_forldap failed: ", error_str(errno) ); + } + + ret = qldap_open(); + if ( ret != 0 ) + strerr_die2x(1, "qldap_open:\tNOT successful: ", + qldap_err_str(qldap_errno)); + + do { + if ( mode == mail ) + done = create_mail_filter(); + else + done = create_uid_filter(); + + search.filter = filter.s; + output(&ssout, "qldap_lookup:\tsearching with %s\n", filter.s); + ret = qldap_lookup(&search, attrs, &info, extra); + if ( ret != 0 ) { + output(&ssout, "qldap_lookup:\tNOT successful: %s\n", + qldap_err_str(qldap_errno)); + } else { + output(&ssout, "qldap_lookup:\tsucceeded, found:\n"); + break; + } + } while ( !done ) ; + qldap_close(); /* now close the ldap (TCP) connection */ + + + if ( ret != 0 ) { + if ( mode == uid && locald ) { + output(&ssout, "Will try a local password lookup\n"); + if ( !stralloc_0(&value) ) { + strerr_die2x(1, "ERROR: ", + error_str(errno)); + } + local_lookup(value.s, passwd); + } else { + output(&ssout, "%s\n", mode!=uid?"user not found giving up": + "localdelivery off, so no local lookup"); + exit(111); + } + } + + output(&ssout, "\t\t%s: %s\n", LDAP_UID, info.user); + if (!chck_users(info.user) ) { + output(&ssout, "\tWARNING %s contains illegal chars!\n", LDAP_UID); + } + output(&ssout, "\t\t%s: %s\n\t\t%s: %s\n", + LDAP_QMAILUID, info.uid, LDAP_QMAILGID, info.gid); + scan_ulong(info.uid, &tid); + if (UID_MIN > tid || tid > UID_MAX ) { + output(&ssout, "\tWARNING %s is out of range (%i...%i)\n", + LDAP_QMAILUID, UID_MIN, UID_MAX); + } + scan_ulong(info.gid, &tid); + if (GID_MIN > tid || tid > GID_MAX ) { + output(&ssout, "\tWARNING %s is out of range (%i...%i)\n", + LDAP_QMAILGID, GID_MIN, GID_MAX); + } + output(&ssout, "\t\t%s: %s\n", LDAP_ISACTIVE, + info.status==STATUS_BOUNCE?ISACTIVE_BOUNCE: + info.status==STATUS_BOUNCE?ISACTIVE_DELETE: + info.status==STATUS_NOPOP?ISACTIVE_NOPOP: + info.status==STATUS_OK?ISACTIVE_ACTIVE:"undefined"); + + output(&ssout, "\t\t%s: %s\n", LDAP_MAILSTORE, info.mms); + if (info.mms) if ( !chck_paths(info.mms) ) { + output(&ssout, "\tWARNING %s contains illegal chars!\n", LDAP_MAILSTORE); + } + output(&ssout, "\t\t%s: %s\n", LDAP_HOMEDIR, info.homedir); + if (info.homedir) if ( !chck_paths(info.homedir) ) { + output(&ssout, "\tWARNING %s contains illegal chars!\n", LDAP_HOMEDIR); + } + + output(&ssout, "\t\t%s: %s\n", LDAP_MAILHOST, info.host); + if ( cluster && info.host && + str_diff(qldap_me.s, info.host) +#ifdef QLDAP_CLUSTER + /* qldap_mailhosts only defined when QLDAP_CLUSTER defined */ + && !constmap(&qldap_mailhosts, info.host, str_len(info.host)) +#endif + ) { + /* hostname is different, so I would reconnect */ + output(&ssout, "\tINFO would reconnect to host %s\n", info.host); + } + + /* free a part of the info struct */ + alloc_free(info.user); + alloc_free(info.uid); + alloc_free(info.gid); + if (info.mms) alloc_free(info.mms); + if (info.homedir) alloc_free(info.homedir); + alloc_free(info.host); + + for ( i = 0; extra[i].what != 0; i++ ) { + if ( extra[i].vals != 0 ) { + output(&ssout, "\t\t%s: %s\n", extra[i].what, extra[i].vals[0]); + for ( j = 1; extra[i].vals[j] != 0; j++ ) { + output(&ssout, "\t\t\t\t %s\n", extra[i].vals[j]); + if ( i == 4 && !chck_progs(extra[i].vals[j]) ) { + output(&ssout, "\tWARNING %s contains illegal chars!\n", + LDAP_PROGRAM); + } + } + } else { + output(&ssout, "\t\t%s: no entry in the database\n", extra[i].what); + } + } + + if ( mode == uid && passwd && !rebind && + extra[8].vals && extra[8].vals[0] ) { + ret = cmp_passwd((unsigned char *) passwd, extra[8].vals[0] ); + output(&ssout, "qldap_lookup:\tpassword compare was %s\n", + ret==0?"successful":"not successful"); + } + /* now it's save to free the entries, thanks to Sascha Gresk for the indication */ + for ( i = 0; extra[i].what != 0; i++ ) + ldap_value_free(extra[i].vals); + + return 0; +} + +int create_mail_filter() +{ + static int at = 0; + static int i = 0; + char* s = value.s; + int len = value.len; + + if ( at == 0 ) { /* first round */ + for (at = len - 1; s[at] != '@' && at >= 0 ; at--) ; + /* handels also mail with 2 @ */ + /* at = index to last @ sign in mail address */ + /* s = mailaddress, len = lenght of address */ + /* i = position of current '-' */ + if ( at == -1 ) { + strerr_die1x(1, "ERROR: invalid mailaddress: no '@' present"); + } + i = at; + } + + /* this handles the "catch all" and "-default" extension */ + /* but also the normal eMail address */ + + /* build the search string for the email address */ + if (!stralloc_copys(&filter,"(" ) ) goto nomem; + /* optional objectclass */ + if ( qldap_objectclass.len ) { + if (!stralloc_cats(&filter,"&(")) goto nomem; + if (!stralloc_cats(&filter,LDAP_OBJECTCLASS)) goto nomem; + if (!stralloc_cats(&filter,"=")) goto nomem; + if (!stralloc_cat(&filter,&qldap_objectclass)) goto nomem; + if (!stralloc_cats(&filter,")(")) goto nomem; + } /* end */ + + /* mail address */ + if (!stralloc_cats(&filter,"|(")) goto nomem; + if (!stralloc_cats(&filter,LDAP_MAIL)) goto nomem; + if (!stralloc_cats(&filter,"=")) goto nomem; + /* username till current '-' */ + if (!stralloc_catb(&filter,s, i)) goto nomem; + if ( i != at ) { /* do not append catchall in the first round */ + /* catchall or default */ + if ( i != 0 ) /* add '-' */ + if (!stralloc_cats(&filter,auto_break)) goto nomem; + if (!stralloc_cats(&filter,LDAP_CATCH_ALL)) goto nomem; + } + /* @damin.com */ + if (!stralloc_catb(&filter,s+at, len-at)) goto nomem; + + /* mailalternate address */ + if (!stralloc_cats(&filter,")(")) goto nomem; + if (!stralloc_cats(&filter,LDAP_MAILALTERNATE)) goto nomem; + if (!stralloc_cats(&filter,"=")) goto nomem; + /* username till current '-' */ + if (!stralloc_catb(&filter,s, i)) goto nomem; + if ( i != at ) { /* do not append catchall in the first round */ + /* catchall or default */ + if ( i != 0 ) /* add '-' */ + if (!stralloc_cats(&filter,auto_break)) goto nomem; + if (!stralloc_cats(&filter,LDAP_CATCH_ALL)) goto nomem; + } + /* @damin.com */ + if (!stralloc_catb(&filter,s+at, len-at)) goto nomem; + if (!stralloc_cats(&filter,"))")) goto nomem; + + /* optional objectclass */ + if ( qldap_objectclass.len ) { + if (!stralloc_cats(&filter,")")) goto nomem; + } /* end */ + if (!stralloc_0(&filter)) goto nomem; + + if ( i == 0 ) return 1; + + /* this is for the next turn */ +#ifdef DASH_EXT + /* XXX if mail starts with a - it will probably not work as expected */ + while ( i != 0 ) { + i--; + if ( s[i] == *auto_break ) break; + } +#else + /* normal qmial-ldap behavior test for username@domain.com and + catchall@domain.com */ + i = 0; +#endif + return 0; + +nomem: + strerr_die2x(1, "ERROR: can not create a filter: ", + error_str(errno)); + return 1; /* to make gcc happy */ +} + +int create_uid_filter() +{ + if ( !stralloc_copys(&filter,"(") ) { + strerr_die2x(1, "ERROR: can not create a filter: ", + error_str(errno)); + } + if ( qldap_objectclass.len && ( + !stralloc_cats(&filter,"&(" ) || + !stralloc_cats(&filter,LDAP_OBJECTCLASS) || + !stralloc_cats(&filter,"=") || + !stralloc_cat(&filter,&qldap_objectclass) || + !stralloc_cats(&filter,")(") ) ) { + strerr_die2x(1, "ERROR: can not create a filter: ", + error_str(errno)); + } + if ( !stralloc_cats(&filter, LDAP_UID) || + !stralloc_cats(&filter, "=") || + !stralloc_cat(&filter, &value) || + !stralloc_cats(&filter, ")") ) { + strerr_die2x(1, "ERROR: can not create a filter: ", + error_str(errno)); + } + if ( qldap_objectclass.len && + !stralloc_cats(&filter,")") ) { + strerr_die2x(1, "ERROR: can not create a filter: ", + error_str(errno)); + } + if ( !stralloc_0(&filter) ) { + strerr_die2x(1, "ERROR: can not create a filter: ", + error_str(errno)); + } + return 1; +} + +static int get_local_maildir(stralloc *home, stralloc *maildir); + +static void local_lookup(char *username, char *passwd) +{ + int ret; + struct passwd *pw; +#ifdef PW_SHADOW + struct spwd *spw; +#endif +#ifdef AIX + struct userpw *spw; +#endif + + pw = getpwnam(username); + if (!pw) { + /* XXX: unfortunately getpwnam() hides temporary errors */ + output(&ssout, "local_lookup:\tuser %s not found in passwd db\n", username); + _exit(0); + } + output(&ssout, "local_lookup:\tsucceeded\n\t\tuser %s found in passwd database\n", + username); + output(&ssout, "\t\tuid: %u\n\t\tgid: %u\n", + pw->pw_uid, pw->pw_gid); + if (UID_MIN > pw->pw_uid || pw->pw_uid > UID_MAX ) { + output(&ssout, "\tWARNING uid is out of range (%i...%i)\n", + UID_MIN, UID_MAX); + } + if (GID_MIN > pw->pw_gid || pw->pw_gid > GID_MAX ) { + output(&ssout, "\tWARNING gid is out of range (%i...%i)\n", + GID_MIN, GID_MAX); + } + + /* here we don't check the home and maildir path, if a user has a faked + * passwd entry, then you have a bigger problem on your system than just + * a guy how can read the mail of other users/customers */ + output(&ssout, "\t\thome: %s\n", pw->pw_dir ); + if (!stralloc_copys(&home, pw->pw_dir) ) { + strerr_die2x(1, "ERROR: local_lookup: ", + error_str(errno)); + } + + if ( get_local_maildir(&home, &md) == -1 ) { + strerr_die2x(1, "ERROR: local_lookup: ", + qldap_err_str(qldap_errno)); + } + output(&ssout, "\t\tmaildir: %s (from ~/.qmail)\n", md.s); + + if ( !passwd ) { + output(&ssout, "No more information available\n"); + _exit(0); + } +#ifdef PW_SHADOW + spw = getspnam(username); + if (!spw) { + /* XXX: again, temp hidden */ + qldap_errno = AUTH_ERROR; + strerr_die2x(1, "ERROR: local_lookup: ", + qldap_err_str(qldap_errno)); + } + output(&ssout, "\t\tcrypted passwd: %s\n", spw->sp_pwdp); + ret = cmp_passwd((unsigned char *) passwd, spw->sp_pwdp); +#else /* no PW_SHADOW */ +#ifdef AIX + spw = getuserpw(username); + if (!spw) { + /* XXX: and again */ + qldap_errno = AUTH_ERROR; + strerr_die2x(1, "ERROR: local_lookup: ", + qldap_err_str(qldap_errno)); + } + output(&ssout, "\t\tcrypted passwd: %s\n", spw->upw_passwd); + ret = cmp_passwd((unsigned char *) passwd, spw->upw_passwd); +#else /* no AIX */ + output(&ssout, "\t\tcrypted passwd: %s\n", pw->pw_passwd); + ret = cmp_passwd((unsigned char *) passwd, pw->pw_passwd); +#endif /* END AIX */ +#endif /* END PW_SHADOW */ + output(&ssout, "local_lookup:\tpassword compare was %s\n", + ret==0?"successful":"not successful"); + _exit(0); +} + +static int cmp_passwd(unsigned char *clear, char *encrypted) +{ +#define HASH_LEN 100 /* XXX is this enough, I think yes */ + /* What do you think ? */ + char hashed[HASH_LEN]; /* these to buffers can not be used for exploits */ + char salt[33]; + int shift; + + if (encrypted[0] == '{') { /* hashed */ + if (!str_diffn("{crypt}", encrypted, 7) ) { + /* CRYPT */ + shift = 7; + str_copy(hashed, crypt(clear, encrypted+shift) ); + } else if (!str_diffn("{MD4}", encrypted, 5) ) { + /* MD4 */ + shift = 5; + MD4DataBase64(clear, str_len(clear), hashed, sizeof(hashed)); + } else if (!str_diffn("{MD5}", encrypted, 5) ) { + /* MD5 */ + shift = 5; + MD5DataBase64(clear, str_len(clear), hashed, sizeof(hashed)); + } else if (!str_diffn("{NS-MTA-MD5}", encrypted, 12) ) { + /* NS-MTA-MD5 */ + shift = 12; + if (!str_len(encrypted) == 76) { + qldap_errno = ILL_AUTH; + return -1; + } /* boom */ + byte_copy(salt, 32, &encrypted[44]); + salt[32] = 0; + if ( ns_mta_hash_alg(hashed, salt, (char *) clear) == -1 ) { + qldap_errno = ERRNO; + return -1; + } + byte_copy(&hashed[32], 33, salt); + } else if (!str_diffn("{SHA}", encrypted, 5) ) { + /* SHA */ + shift = 5; + SHA1DataBase64(clear, str_len(clear), hashed, sizeof(hashed)); + } else if (!str_diffn("{RMD160}", encrypted, 8) ) { + /* RMD160 */ + shift = 8; + RMD160DataBase64(clear, str_len(clear), hashed, sizeof(hashed)); + } else { + /* unknown hash function detected */ + shift = 0; + qldap_errno = ILL_AUTH; + return -1; + } + /* End getting correct hash-func hashed */ + log(256, "cpm_passwd: comparing hashed passwd (%s == %s)\n", + hashed, encrypted+shift); + if (!*encrypted || str_diff(hashed,encrypted+shift) ) { + qldap_errno = AUTH_FAILED; + return -1; + } + /* hashed passwds are equal */ + } else { /* crypt or clear text */ + log(256, "cpm_passwd: comparing standart passwd (%s == %s)\n", + crypt(clear,encrypted), encrypted); + if (!*encrypted || str_diff(encrypted, crypt(clear,encrypted) ) ) { + /* CLEARTEXTPASSWD ARE NOT GOOD */ + /* so they are disabled by default */ +#ifdef CLEARTEXTPASSWD +#warning ___CLEARTEXT_PASSWORD_SUPPORT_IS_ON___ + if (!*encrypted || str_diff(encrypted, clear) ) { +#endif + qldap_errno = AUTH_FAILED; + return -1; +#ifdef CLEARTEXTPASSWD + } +#endif + /* crypted or cleartext passwd ok */ + } + } /* end -- hashed or crypt/clear text */ + + return 0; + +} + +static int get_local_maildir(stralloc *home, stralloc *maildir) +{ + substdio ss; + stralloc dotqmail = {0}; + char buf[512]; + int match; + int fd; + + if ( ! stralloc_copy(&dotqmail, home) ) { + qldap_errno = ERRNO; + return -1; + } + if ( ! stralloc_cats(&dotqmail, "/.qmail") ) { + qldap_errno = ERRNO; + return -1; + } + if ( ! stralloc_0(&dotqmail) ) { + qldap_errno = ERRNO; + return -1; + } + + if ( ( fd = open_read(dotqmail.s) ) == -1 ) { + if ( errno == error_noent ) return 0; + qldap_errno = ERRNO; + return -1; + } + + substdio_fdbuf(&ss,read,fd,buf,sizeof(buf)); + while (1) { + if (getln(&ss,&dotqmail,&match,'\n') != 0) goto tryclose; + if (!match && !dotqmail.len) break; + if ( (dotqmail.s[0] == '.' || dotqmail.s[0] == '/') && + dotqmail.s[dotqmail.len-2] == '/' ) { /* is a maildir line ? */ + if ( ! stralloc_copy(maildir, &dotqmail) ) goto tryclose; + maildir->s[maildir->len-1] = '\0'; + break; + } + } + + close(fd); + for (match = 0; match<512; buf[match++]=0 ) ; /* trust nobody */ + return 0; + +tryclose: + for (match = 0; match<512; buf[match++]=0 ) ; /* trust nobody */ + match = errno; /* preserve errno */ + close(fd); + errno = match; + qldap_errno = ERRNO; + return -1; + +} + diff -uN qmail-1.03/qmail-local.c qmail-ldap/qmail-local.c --- qmail-1.03/qmail-local.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/qmail-local.c Fri May 4 20:58:43 2001 @@ -29,6 +29,15 @@ #include "gfrom.h" #include "auto_patrn.h" +#include "qmail-ldap.h" +#include "qldap-errno.h" +#include "auto_qmail.h" +#include "scan.h" +#include "maildir++.h" +#ifdef AUTOHOMEDIRMAKE +#include "qldap-mdm.h" +#endif + void usage() { strerr_die1x(100,"qmail-local: usage: qmail-local [ -nN ] user homedir local dash ext domain sender aliasempty"); } void temp_nomem() { strerr_die1x(111,"Out of memory. (#4.3.0)"); } @@ -53,6 +62,9 @@ char *sender; char *aliasempty; +/* define the global variables */ +char *quotastring; + stralloc safeext = {0}; stralloc ufline = {0}; stralloc rpline = {0}; @@ -68,11 +80,11 @@ char outbuf[1024]; /* child process */ - char fntmptph[80 + FMT_ULONG * 2]; -char fnnewtph[80 + FMT_ULONG * 2]; +char fnnewtph[83 + FMT_ULONG * 3]; void tryunlinktmp() { unlink(fntmptph); } void sigalrm() { tryunlinktmp(); _exit(3); } +int msfd; /* global filedescriptor to the quota file */ void maildir_child(dir) char *dir; @@ -88,7 +100,45 @@ substdio ssout; sig_alarmcatch(sigalrm); - if (chdir(dir) == -1) { if (error_temp(errno)) _exit(1); _exit(2); } + if (chdir(dir) == -1) { +#ifdef AUTOMAILDIRMAKE + /* this one handles the case where the aliasempty is not "./" */ + if (errno == error_noent) { + umask(077); + if (mkdir(dir,0700) == -1) { if (error_temp(errno)) _exit(5); _exit(6); } + if (chdir(dir) == -1) { if (error_temp(errno)) _exit(5); _exit(6); } + if (mkdir("tmp",0700) == -1) { if (error_temp(errno)) _exit(5); _exit(6); } + if (mkdir("new",0700) == -1) { if (error_temp(errno)) _exit(5); _exit(6); } + if (mkdir("cur",0700) == -1) { if (error_temp(errno)) _exit(5); _exit(6); } + } else +#endif + if (error_temp(errno)) _exit(1); else _exit(2); + } + +/* this one handles the case where the aliasempty is "./" */ +#ifdef AUTOMAILDIRMAKE + if ( !str_diff(dir, "./") ) { + umask(077); + if (stat("new", &st) == -1) { + if (errno == error_noent) { + if (mkdir("new",0700) == -1) { if (error_temp(errno)) _exit(5); _exit(6); } + } else if (error_temp(errno)) _exit(5); else _exit(6); + } else if (! S_ISDIR(st.st_mode) ) _exit(7); + + if (stat("cur", &st) == -1) { + if (errno == error_noent) { + if (mkdir("cur",0700) == -1) { if (error_temp(errno)) _exit(5); _exit(6); } + } else if (error_temp(errno)) _exit(5); else _exit(6); + } else if (! S_ISDIR(st.st_mode) ) _exit(7); + + if (stat("tmp", &st) == -1) { + if (errno == error_noent) { + if (mkdir("tmp",0700) == -1) { if (error_temp(errno)) _exit(5); _exit(6); } + } else if (error_temp(errno)) _exit(5); else _exit(6); + } else if (! S_ISDIR(st.st_mode) ) _exit(7); + } +#endif + pid = getpid(); host[0] = 0; gethostname(host,sizeof(host)); @@ -99,7 +149,8 @@ s += fmt_str(s,"tmp/"); s += fmt_ulong(s,time); *s++ = '.'; s += fmt_ulong(s,pid); *s++ = '.'; - s += fmt_strn(s,host,sizeof(host)); *s++ = 0; + s += fmt_strn(s,host,sizeof(host)); + *s++ = 0; if (stat(fntmptph,&st) == -1) if (errno == error_noent) break; /* really should never get to this point */ if (loop == 2) _exit(1); @@ -125,8 +176,21 @@ if (substdio_flush(&ssout) == -1) goto fail; if (fsync(fd) == -1) goto fail; + if (fstat(fd, &st) == -1) goto fail; if (close(fd) == -1) goto fail; /* NFS dorks */ + s = fnnewtph; + while( *s ) s++; + s += fmt_str(s,",S="); + s += fmt_ulong(s,(unsigned long) st.st_size); + *s++ = 0; + + if( quotastring && *quotastring ) { + /* finally update the quota file "maildirsize" */ + quota_add(msfd, (unsigned long) st.st_size, 1); + close(msfd); + } + if (link(fntmptph,fnnewtph) == -1) goto fail; /* if it was error_exist, almost certainly successful; i hate NFS */ tryunlinktmp(); _exit(0); @@ -136,12 +200,82 @@ /* end child process */ +/* quota handling warning and bounce */ +void quota_bounce(char *type) { strerr_die3x(100, "The users ", type, " is over the allowed quota (size)."); } + +void quota_warning(char *fn) +{ + int child; + char *(args[3]); + int wstat; + + if (!env_get(ENV_QUOTAWARNING) ) return; + if (!stralloc_copys(&foo, auto_qmail)) temp_nomem(); + if (!stralloc_cats(&foo, "/bin/qmail-quotawarn")) temp_nomem(); + if (!stralloc_0(&foo)) temp_nomem(); + + if (seek_begin(0) == -1) temp_rewind(); + + switch(child = fork()) + { + case -1: + temp_fork(); + case 0: + args[0] = foo.s; args[1] = fn; args[2] = 0; + sig_pipedefault(); + execv(*args,args); + strerr_die5x(111,"Unable to run quotawarn program: ", foo.s, ": ",error_str(errno),". (LDAP-ERR #2.3.0)"); + } + + wait_pid(&wstat,child); + if (wait_crashed(wstat)) + temp_childcrashed(); + switch(wait_exitcode(wstat)) + { + case 111: _exit(111); + case 0: break; + default: _exit(100); + } + +} +/* end -- quota handling warning and bounce */ + void maildir(fn) char *fn; { int child; int wstat; + /* quota handling maildir */ + struct stat mailst; + int perc; + quota_t q; + unsigned long mailsize; + + if( quotastring && *quotastring ) { + if (fstat(0, &mailst) != 0) + strerr_die3x(111,"Can not stat mail for quota: ",error_str(errno),". (LDAP-ERR #2.4.1)"); + mailsize = mailst.st_size; + quota_get(&q, quotastring); + if ( quota_calc(fn, &msfd, &q) == -1 ) { + /* second chance */ + sleep(3); + /* XXX fd can be -1 when retval = 0 quota_add/rm take care of that */ + if ( quota_calc(fn, &msfd, &q) == -1 ) { + strerr_die1x(111,"Temporary race condition while calculating quota. (LDAP-ERR #2.4.2)"); + } + } + + if ( quota_check(&q, mailsize, 1, &perc) ) /* 0 if OK */ + if ( quota_recalc(fn, &msfd, &q, mailsize, 1, &perc) ) + quota_bounce("mailfolder"); + if ( perc > QUOTA_WARNING_LEVEL ) + /* drop a warning when mailbox is around 80% full */ + quota_warning(fn); + } + + /* end -- quota handling maildir */ + if (seek_begin(0) == -1) temp_rewind(); switch(child = fork()) @@ -162,6 +296,11 @@ case 2: strerr_die1x(111,"Unable to chdir to maildir. (#4.2.1)"); case 3: strerr_die1x(111,"Timeout on maildir delivery. (#4.3.0)"); case 4: strerr_die1x(111,"Unable to read message. (#4.3.0)"); +#ifdef AUTOMAILDIRMAKE + case 5: strerr_die1x(111,"Temporary error on maildir creation. (LDAP-ERR #2.5.1)"); + case 6: strerr_die3x(111,"Unable to create maildir '", fn, "' (LDAP-ERR #2.5.2)"); + case 7: strerr_die3x(111,"The maildir '", fn, "' seems to be corrupted. (LDAP-ERR #2.5.3)"); +#endif default: strerr_die1x(111,"Temporary error on maildir delivery. (#4.3.0)"); } } @@ -176,6 +315,35 @@ seek_pos pos; int flaglocked; + /* quota handling mbox */ + struct stat filest, mailst; + long int totalsize; + quota_t q; + + if (seek_begin(0) == -1) temp_rewind(); + + if( quotastring && *quotastring ) { + quota_get(&q, quotastring); + if (stat(fn, &filest) == -1) { + filest.st_size = 0; /* size of nonexisting mailfile */ + if ( errno != error_noent) { /* FALSE if file doesn't exist */ + strerr_die5x(111,"Unable to quota ", fn, ": ",error_str(errno), ". (LDAP-ERR #2.4.5)"); + } + } + if (fstat(0, &mailst) != 0) + strerr_die3x(111,"Unable to quota mail: ",error_str(errno), ". (LDAP-ERR #2.4.6)"); + + totalsize = (long) filest.st_size + (long) mailst.st_size; + if ( totalsize > q.quota_size ) { + quota_bounce("mailbox"); + } else if ( totalsize*100/q.quota_size > QUOTA_WARNING_LEVEL) { + /* drop a warning when mailbox is around 80% full */ + quota_warning(fn); + } + } + + /* end -- quota handling mbox */ + if (seek_begin(0) == -1) temp_rewind(); fd = open_append(fn); @@ -444,6 +612,25 @@ substdio_putsflush(subfdoutsmall,"\n"); } +/* char replacement */ +unsigned int replace(s, len, f, r) +char *s; +register unsigned int len; +register char f; +register char r; +{ + register char *t; + register int count = 0; + + t=s; + for(;;) { + if (!len) return count; if (*t == f) { *t=r; count++; } ++t; --len; + if (!len) return count; if (*t == f) { *t=r; count++; } ++t; --len; + if (!len) return count; if (*t == f) { *t=r; count++; } ++t; --len; + if (!len) return count; if (*t == f) { *t=r; count++; } ++t; --len; + } +} + void main(argc,argv) int argc; char **argv; @@ -459,6 +646,18 @@ int flagforwardonly; char *x; + /* set up the variables for qmail-ldap */ + int slen; + int qmode; + int mboxdelivery; + int localdelivery; + int ldapprogdelivery; + char *s; + char *rt; + + mboxdelivery = 1; localdelivery = 0; ldapprogdelivery = 0; + + umask(077); sig_pipeignore(); @@ -487,8 +686,34 @@ if (*argv) usage(); if (homedir[0] != '/') usage(); - if (chdir(homedir) == -1) + if (chdir(homedir) == -1) { +#ifdef AUTOHOMEDIRMAKE + s = env_get(ENV_HOMEDIRMAKE); + if ( errno == error_noent && s && *s ) { + /* do the auto homedir creation */ + if ( make_homedir(homedir, aliasempty, s ) != 0 ) { + if ( qldap_errno == ERRNO ) { + strerr_die5x(111,"Error while running automatic dirmaker:",s,": ", + error_str(errno),". (LDAP-ERR #2.2.1)"); + } else { + strerr_die3x(111,s,qldap_errno == MAILDIR_CRASHED? + ": is crashed" : ": exited non zero", + ". (LDAP-ERR #2.2.2)"); + } + } + if (chdir(homedir) == -1) { + strerr_die5x(111,"Unable to switch to ",homedir, + " even after running dirmaker: ",error_str(errno), + ". (LDAP-ERR #2.2.3)"); + } + } else { + strerr_die5x(111,"Unable to switch to ",homedir,": ",error_str(errno), + ". (LDAP_ERR #2.2.4)"); + } +#else strerr_die5x(111,"Unable to switch to ",homedir,": ",error_str(errno),". (#4.3.0)"); +#endif + } checkhome(); if (!env_put2("HOST",host)) temp_nomem(); @@ -583,38 +808,177 @@ if (!env_put2("HOST4",foo.s)) temp_nomem(); flagforwardonly = 0; - qmesearch(&fd,&flagforwardonly); - if (fd == -1) - if (*dash) - strerr_die1x(100,"Sorry, no mailbox here by that name. (#5.1.1)"); - if (!stralloc_copys(&ueo,sender)) temp_nomem(); - if (str_diff(sender,"")) - if (str_diff(sender,"#@[]")) - if (qmeox("-owner") == 0) - { - if (qmeox("-owner-default") == 0) - { - if (!stralloc_copys(&ueo,local)) temp_nomem(); - if (!stralloc_cats(&ueo,"-owner-@")) temp_nomem(); - if (!stralloc_cats(&ueo,host)) temp_nomem(); - if (!stralloc_cats(&ueo,"-@[]")) temp_nomem(); - } - else - { - if (!stralloc_copys(&ueo,local)) temp_nomem(); - if (!stralloc_cats(&ueo,"-owner@")) temp_nomem(); - if (!stralloc_cats(&ueo,host)) temp_nomem(); - } + /* quota, dotmode and forwarding handling - part 1 */ + /* setting the quota */ + if ( ( quotastring = env_get(ENV_QUOTA) ) && *quotastring ) { + if (!flagdoit) sayit("quota defined as: ",quotastring,str_len(quotastring) ); + } else { + if (!flagdoit) sayit("unlimited quota",quotastring,0 ); + } + + if ( s = env_get(ENV_DOTMODE) ) { + case_lowers(s); + if ( !str_diff(DOTMODE_LDAPONLY, s) ) { + if (!flagdoit) sayit("DOTMODE_LDAPONLY ",s,0); + qmode = DO_LDAP; + } else if ( !str_diff(DOTMODE_LDAPWITHPROG, s) ) { + if (!flagdoit) sayit("DOTMODE_LDAPWITHPROG ",s,0); + qmode = DO_LDAP; + ldapprogdelivery = 1; + } else if ( !str_diff(DOTMODE_DOTONLY, s) ) { + if (!flagdoit) sayit("DOTMODE_DOTONLY ",s,0); + qmode = DO_DOT; + } else if ( !str_diff(DOTMODE_BOTH, s) ) { + if (!flagdoit) sayit("DOTMODE_BOTH ",s,0); + qmode = DO_BOTH; + ldapprogdelivery = 1; + } else if ( !str_diff(DOTMODE_NONE, s) ){ + ++count_file; + if (!stralloc_copys(&foo,aliasempty)) temp_nomem(); + if (!stralloc_0(&foo)) temp_nomem(); + if (foo.s[foo.len - 2] == '/') + if (flagdoit) maildir(foo.s); + else sayit("maildir ",foo.s, foo.len); + else + if (flagdoit) mailfile(foo.s); + else sayit("mbox ",foo.s, foo.len); + count_print(); + _exit(0); + } else { + strerr_die3x(100,"Error: No valid dot-mode found: ",s,". (LDAP-ERR #2.0.2)"); } - if (!stralloc_0(&ueo)) temp_nomem(); - if (!env_put2("NEWSENDER",ueo.s)) temp_nomem(); - + } else qmode = DO_DOT; /* no qmailmode, so I use standard .qmail */ + + /* prepare the cmds string to hold all the commands from the + * ldap server and the .qmail file */ if (!stralloc_ready(&cmds,0)) temp_nomem(); cmds.len = 0; - if (fd != -1) - if (slurpclose(fd,&cmds,256) == -1) temp_nomem(); + + if ( qmode & DO_LDAP ) { + /* get the infos from the ldap server (environment) */ + /* setting the NEWSENDER so echo and forward will work */ + if (!stralloc_copys(&ueo,sender)) temp_nomem(); + if (!stralloc_0(&ueo)) temp_nomem(); + if (!env_put2("NEWSENDER",ueo.s)) temp_nomem(); + + if ( s = env_get(ENV_MODE) ) { + case_lowers(s); + if (!stralloc_copys(&foo, s)) temp_nomem(); + if (!stralloc_0(&foo)) temp_nomem(); + + i = replace(foo.s, foo.len, ',', '\0') + 1; + s = foo.s; + slen = foo.len-1; + for( ; i > 0; i--) { + if ( !str_diff(MODE_FORWARD, s) ) { + if (!flagdoit) sayit("forwardonly ",s,0); + flagforwardonly = 0; + } else if ( !str_diff(MODE_REPLY, s) ) { + if( *sender ) { + ++count_forward; + if ( rt = env_get(ENV_REPLYTEXT) ) { + if ( flagdoit ) { + mailprogram("qmail-reply"); + } else { + sayit("reply to ",sender,str_len(sender)); + sayit("replytext ",rt,str_len(rt)); + } + } else { + strerr_warn1("Error: Reply mode is on but there is no reply text (ignored). (LDAP-ERR #2.1.1)", 0); + } + } + } else if ( !str_diff(MODE_ECHO, s) ) { + if (*sender) { + ++count_forward; + recips = (char **) alloc(2 * sizeof(char *)); + recips[0] = sender; + recips[1] = 0; + if (flagdoit) { + mailforward(recips); + } else sayit("echo to ",sender,str_len(sender)); + } + count_print(); + _exit(0); + } else if ( !str_diff(MODE_NOMBOX, s) ) { + if (!flagdoit) sayit("no mbox delivery ",s,0); + mboxdelivery = 0; + } else if ( !str_diff(MODE_NORMAL, s) ) { + if (!flagdoit) sayit("reseting delivery to normal",s,0); + mboxdelivery = 1; + flagforwardonly = 0; + localdelivery = 0; + } else if ( !str_diff(MODE_LDELIVERY, s) ) { + if (!flagdoit) sayit("force local delivery ",s,0); + localdelivery = 1; + } else strerr_warn1("Error: undefined mail mode (ignored). (LDAP-ERR #2.1.2)", 0); + + j = byte_chr(s,slen,0); if (j++ == slen) break; s += j; slen -= j; + } + } + if ( localdelivery ) { + if (!stralloc_cats(&cmds,aliasempty)) temp_nomem(); + if (!stralloc_cats(&cmds, "\n")) temp_nomem(); + } + if ( s = env_get(ENV_FORWARDS) ) { + if (!stralloc_copys(&foo, s)) temp_nomem(); + if (!stralloc_0(&foo)) temp_nomem(); + replace(foo.s, foo.len, ',', '\0'); + s = foo.s; + slen = foo.len-1; + for (;;) { + if (!stralloc_cats(&cmds, "&")) temp_nomem(); + if (!stralloc_cats(&cmds, s)) temp_nomem(); + if (!stralloc_cats(&cmds, "\n")) temp_nomem(); + j = byte_chr(s,slen,0); if (j++ == slen) break; s += j; slen -= j; + } + } + if ( ldapprogdelivery && (s = env_get(ENV_PROGRAM)) ) { + if (!stralloc_copys(&foo, s)) temp_nomem(); + if (!stralloc_0(&foo)) temp_nomem(); + replace(foo.s, foo.len, ',', '\0'); + s = foo.s; + slen = foo.len-1; + for (;;) { + if (!stralloc_cats(&cmds, "|")) temp_nomem(); + if (!stralloc_cats(&cmds, s)) temp_nomem(); + if (!stralloc_cats(&cmds, "\n")) temp_nomem(); + j = byte_chr(s,slen,0); if (j++ == slen) break; s += j; slen -= j; + } + } + + } + if ( qmode & DO_DOT ) { /* start dotqmail */ + qmesearch(&fd,&flagforwardonly); + if (fd == -1) + if (*dash) + if ( qmode == DO_DOT ) /* XXX: OK ??? */ + strerr_die1x(100,"Sorry, no mailbox here by that name. (#5.1.1)"); + + if (!stralloc_copys(&ueo,sender)) temp_nomem(); + if (str_diff(sender,"")) + if (str_diff(sender,"#@[]")) + if (qmeox("-owner") == 0) { + if (qmeox("-owner-default") == 0) { + if (!stralloc_copys(&ueo,local)) temp_nomem(); + if (!stralloc_cats(&ueo,"-owner-@")) temp_nomem(); + if (!stralloc_cats(&ueo,host)) temp_nomem(); + if (!stralloc_cats(&ueo,"-@[]")) temp_nomem(); + } else { + if (!stralloc_copys(&ueo,local)) temp_nomem(); + if (!stralloc_cats(&ueo,"-owner@")) temp_nomem(); + if (!stralloc_cats(&ueo,host)) temp_nomem(); + } + } + + if (!stralloc_0(&ueo)) temp_nomem(); + if (!env_put2("NEWSENDER",ueo.s)) temp_nomem(); + + if (fd != -1) + if (slurpclose(fd,&cmds,256) == -1) temp_nomem(); + } else if (! qmode & DO_LDAP ) /* XXX: If non of DO_LDAP, DO-DOT */ + strerr_die1x(100,"Error: No valid delivery mode selected. (LDAP-ERR #2.0.3)"); if (!cmds.len) { if (!stralloc_copys(&cmds,aliasempty)) temp_nomem(); @@ -656,6 +1020,7 @@ break; case '.': case '/': + if (! mboxdelivery ) break; ++count_file; if (flagforwardonly) strerr_die1x(111,"Uh-oh: .qmail has file delivery but has x bit set. (#4.7.0)"); if (cmds.s[k - 1] == '/') diff -uN qmail-1.03/qmail-lspawn.c qmail-ldap/qmail-lspawn.c --- qmail-1.03/qmail-lspawn.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/qmail-lspawn.c Sun Sep 30 14:58:57 2001 @@ -14,14 +14,87 @@ #include "auto_uids.h" #include "qlx.h" +#include "qmail-ldap.h" +#include "qldap-ldaplib.h" +#include "qldap-errno.h" +#include "qldap-debug.h" +#include "alloc.h" +#include "env.h" +#include "fmt.h" +#include "check.h" +#include "sig.h" +#include "auto_usera.h" +#include "auto_uids.h" +#include "auto_break.h" +#include "byte.h" +#include "open.h" +#include "readwrite.h" +#include "str.h" +#include +#include +#ifdef QLDAP_CLUSTER +#include "constmap.h" +#include "seek.h" +#include "getln.h" +#endif + char *aliasempty; +/* initialize the string arrays, this uses DJB's libs */ +extern stralloc qldap_me; +extern stralloc qldap_objectclass; +stralloc qldap_defdotmode = {0}; +stralloc qldap_defaultquota = {0}; +stralloc qldap_quotawarning = {0}; +stralloc qldap_dirmaker = {0}; +int qldap_localdelivery; +int qldap_cluster; + +stralloc foo = {0}; + +/* init done */ + +#ifdef QLDAP_CLUSTER +extern struct constmap qldap_mailhosts; + +/* declaration of the mail forwarder function */ +void forward_mail(char *host, stralloc *to, char *from, int fdmess); +#endif + +/* this is a simple wrapper for the signal handler */ +void get_qldap_controls() +{ + if ( init_ldap( &qldap_localdelivery, &qldap_cluster, 0, &qldap_dirmaker, + &qldap_defdotmode, &qldap_defaultquota, &qldap_quotawarning ) == -1 ) + _exit(1); + + if ( qldap_dirmaker.len != 0 ) { + if ( !env_put2(ENV_HOMEDIRMAKE, qldap_dirmaker.s )) _exit(QLX_NOMEM); + } else { + if ( !env_unset(ENV_HOMEDIRMAKE) ) _exit(QLX_NOMEM); + } + + if ( qldap_quotawarning.len != 0 ) { + if ( !env_put2(ENV_QUOTAWARNING, qldap_quotawarning.s )) _exit(QLX_NOMEM); + } else { + if ( !env_unset(ENV_QUOTAWARNING) ) _exit(QLX_NOMEM); + } +} + +/* here it is not possible to log something */ void initialize(argc,argv) int argc; char **argv; { - aliasempty = argv[1]; - if (!aliasempty) _exit(100); + aliasempty = argv[1]; + if (!aliasempty) { + _exit(100); + } + + /* read the control files */ + get_qldap_controls(); + sig_hangupcatch(get_qldap_controls); + sig_hangupunblock(); } int truncreport = 3000; @@ -32,58 +105,577 @@ char *s; int len; { +#ifdef DEBUG +#define REPORT_RETURN for (i = 0;i < len;++i) if (!s[i]) break; substdio_put(ss,s,i); return +#else +#define REPORT_RETURN return +#endif int i; - if (wait_crashed(wstat)) - { substdio_puts(ss,"Zqmail-local crashed.\n"); return; } - switch(wait_exitcode(wstat)) - { + if (wait_crashed(wstat)) { + substdio_puts(ss,"Zqmail-local crashed.\n"); + REPORT_RETURN; + } + switch(wait_exitcode(wstat)) { case QLX_CDB: - substdio_puts(ss,"ZTrouble reading users/cdb in qmail-lspawn.\n"); return; + substdio_puts(ss,"ZTrouble reading users/cdb in qmail-lspawn.\n"); + REPORT_RETURN; + case QLX_NOMEM: - substdio_puts(ss,"ZOut of memory in qmail-lspawn.\n"); return; + substdio_puts(ss,"ZOut of memory in qmail-lspawn.\n"); + REPORT_RETURN; + case QLX_SYS: - substdio_puts(ss,"ZTemporary failure in qmail-lspawn.\n"); return; + substdio_puts(ss,"ZTemporary failure in qmail-lspawn.\n"); + REPORT_RETURN; + case QLX_NOALIAS: - substdio_puts(ss,"ZUnable to find alias user!\n"); return; + substdio_puts(ss,"ZUnable to find alias user!\n"); + REPORT_RETURN; + case QLX_ROOT: - substdio_puts(ss,"ZNot allowed to perform deliveries as root.\n"); return; + substdio_puts(ss,"ZNot allowed to perform deliveries as root.\n"); + REPORT_RETURN; + case QLX_USAGE: - substdio_puts(ss,"ZInternal qmail-lspawn bug.\n"); return; + substdio_puts(ss,"ZInternal qmail-lspawn bug.\n"); + REPORT_RETURN; + case QLX_NFS: - substdio_puts(ss,"ZNFS failure in qmail-local.\n"); return; + substdio_puts(ss,"ZNFS failure in qmail-local.\n"); + REPORT_RETURN; + case QLX_EXECHARD: - substdio_puts(ss,"DUnable to run qmail-local.\n"); return; + substdio_puts(ss,"DUnable to run qmail-local.\n"); + REPORT_RETURN; + case QLX_EXECSOFT: - substdio_puts(ss,"ZUnable to run qmail-local.\n"); return; + substdio_puts(ss,"ZUnable to run qmail-local.\n"); + REPORT_RETURN; + case QLX_EXECPW: - substdio_puts(ss,"ZUnable to run qmail-getpw.\n"); return; + substdio_puts(ss,"ZUnable to run qmail-getpw.\n"); + REPORT_RETURN; + case 111: case 71: case 74: case 75: - substdio_put(ss,"Z",1); break; + substdio_put(ss,"Z",1); + break; + case 0: - substdio_put(ss,"K",1); break; + substdio_put(ss,"K",1); + break; + + /* report LDAP errors */ + case 198: /* XXX */ + substdio_puts(ss, "DInternal qmail-ldap-lspawn bug. (LDAP-ERR #198)\n"); + REPORT_RETURN; + + case 199: /* XXX */ + substdio_puts(ss, "ZMissing ~control/ldapserver. (LDAP-ERR #199)\n"); + REPORT_RETURN; + + case 200: /* XXX */ + substdio_puts(ss, "DReceipient email address is not a valid email address. (LDAP-ERR #200)\n"); + REPORT_RETURN; + + case 201: + substdio_puts(ss, "DInternal error initializing LDAP structure (LDAP-ERR #201).\n"); + REPORT_RETURN; + + case 202: /* XXX */ + substdio_puts(ss, "DInternal error in ldap_set_option. (LDAP-ERR #202)\n"); + REPORT_RETURN; + + case 203: + substdio_puts(ss, "ZUnable to login into LDAP server. (bad username/password?). (LDAP-ERR #203)\n"); + REPORT_RETURN; + + case 204: /* XXX */ + substdio_puts(ss, "DInternal error in ldap_search_ext_s. (LDAP-ERR #204)\n"); + REPORT_RETURN; + + case 205: + substdio_puts(ss, "ZUnable to contact LDAP server (bad server address or server down?). (LDAP-ERR #205)"); + REPORT_RETURN; + + case 206: + substdio_puts(ss, "ZTimeout while performing search on LDAP server (server overloaded?). (LDAP-ERR #206)"); + REPORT_RETURN; + + case 210: + substdio_puts(ss, "DLDAP attribute qmailUser contains illegal characters. (LDAP-ERR #210)\n"); + REPORT_RETURN; + + case 211: + substdio_puts(ss, "DLDAP attribute qmailUID is too high/low or not numeric. (LDAP-ERR #211)\n"); + REPORT_RETURN; + + case 212: + substdio_puts(ss, "DLDAP attribute qmailGID is too high/low or not numeric. (LDAP-ERR #212)\n"); + REPORT_RETURN; + + case 213: + substdio_puts(ss, "DLDAP attribute mailMessageStore contains illegal characters. (LDAP-ERR #213)\n"); + REPORT_RETURN; + + case 214: /* XXX */ + substdio_puts(ss, "ZLDAP attribute mailMessageStore in ~control/ldapmessagestore contains illegal characters. (LDAP-ERR #214)\n"); + REPORT_RETURN; + + case 215: /* XXX */ + substdio_puts(ss, "DLDAP attribute mailMessageStore is not given but mandatory. (LDAP-ERR #215)\n"); + REPORT_RETURN; + + case 220: /* XXX */ + substdio_puts(ss, "DLDAP attribute mailForwardingAddress contains illegal characters. (LDAP-ERR #220)\n"); + REPORT_RETURN; + + case 221: /* XXX */ + substdio_puts(ss, "DLDAP attribute deliveryProgramPath contains illegal characters. (LDAP-ERR #221)\n"); + REPORT_RETURN; + + case 222: /* XXX */ + substdio_puts(ss, "ZError while reading ~control files. (LDAP-ERR #222)\n"); + REPORT_RETURN; + + case 225: + substdio_puts(ss, "DMailaddress is administrativley disabled. (LDAP-ERR #220)\n"); + REPORT_RETURN; + + case 230: /* XXX */ + substdio_puts(ss, "ZConfiguration file ~control/ldapusername is missing/empty and LDAP qmailUser is not given. (LDAP-ERR #230)\n"); + REPORT_RETURN; + + case 231: + substdio_puts(ss, "ZConfiguration file ~control/ldapusername contains illegal characters. (LDAP-ERR #231)\n"); + REPORT_RETURN; + + case 232: /* XXX */ + substdio_puts(ss, "ZConfiguration file ~control/ldapuid is missing/empty and LDAP qmailUID is not given. (LDAP-ERR #232)\n"); + REPORT_RETURN; + + case 233: /* XXX */ + substdio_puts(ss, "ZConfiguration file ~control/ldapuid is too high/low or not numeric. (LDAP-ERR #233)\n"); + REPORT_RETURN; + + case 234: /* XXX */ + substdio_puts(ss, "ZConfiguration file ~control/ldapgid is missing/empty and LDAP qmailGID is not given. (LDAP-ERR #234)\n"); + REPORT_RETURN; + + case 235: /* XXX */ + substdio_puts(ss, "ZConfiguration file ~control/ldapgid is too high/low or not numeric. (LDAP-ERR #235)\n"); + REPORT_RETURN; + + case 236: /* XXX */ + substdio_puts(ss, "ZConfiguration file ~control/ldapmessagestore does not begin with an / or is emtpy. (LDAP-ERR #236)\n"); + REPORT_RETURN; + + case 237: /* XXX */ + substdio_puts(ss, "ZConfiguration file ~control/ldapmessagestore does not end with an / or is empty. (LDAP-ERR #237)\n"); + REPORT_RETURN; + + case 238: + substdio_puts(ss, "Zqmail-qmqpc (as mail forwarder) crashed (LDAP-ERR #238)\n"); + REPORT_RETURN; + +#ifdef QLDAP_CLUSTER + case 239: + substdio_puts(ss, "ZTemporary error in qmail-qmqpc (as mail forwarder) (LDAP-ERR #239)\n"); + REPORT_RETURN; + + case 240: + substdio_puts(ss, "DPermanent error in qmail-qmqpc (as mail forwarder) (LDAP-ERR #240)\n"); + REPORT_RETURN; + + case 241: + substdio_puts(ss, "DThis message is looping: it already has my Delivered-To line. (LDAP-ERR #241 CLUSTERLOOP)\n"); + REPORT_RETURN; +#endif /* QLDAP_CLUSTER */ +/* end -- report LDAP errors */ + case 100: default: - substdio_put(ss,"D",1); break; + substdio_put(ss,"D",1); + break; } - for (i = 0;i < len;++i) if (!s[i]) break; - substdio_put(ss,s,i); + for (i = 0;i < len;++i) + if (!s[i]) + break; + + substdio_put(ss,s,i); } -stralloc lower = {0}; + stralloc nughde = {0}; + +/* LDAP server query routines */ + +int qldap_get( stralloc *mail, char *from, int fdmess) +{ + userinfo info; + extrainfo extra[7]; + searchinfo search; + char *attrs[] = { /* LDAP_MAIL, */ /* not needed */ + /* LDAP_MAILALTERNATE, */ + LDAP_UID, /* the first 6 attrs are the default ones */ + LDAP_QMAILUID, + LDAP_QMAILGID, + LDAP_ISACTIVE, + LDAP_MAILHOST, + LDAP_MAILSTORE, + LDAP_HOMEDIR, + LDAP_QUOTA, /* the last 6 are extra infos */ + LDAP_FORWARDS, + LDAP_PROGRAM, + LDAP_MODE, + LDAP_REPLYTEXT, + LDAP_DOTMODE, 0 }; + int ret; + int at; + int i; + int len; + int force_forward; + char *s; + stralloc filter = {0}; + unsigned long tid; + + /* check the mailaddress for illegal characters * + * escape '*', ,'\', '(' and ')' with a preceding '\' */ + if (!escape_forldap(mail) ) _exit(QLX_NOMEM); + + ret = qldap_open(); + if ( ret != 0 ) goto ldap_fail; + + at = 0; + s = mail->s; + len = mail->len; + + for (at = len - 1; s[at] != '@' && at >= 0 ; at--) ; + /* handels also mail with 2 @ */ + /* at = index to last @ sign in mail address */ + /* s = mailaddress, len = lenght of address */ + /* i = position of current '-' */ + i = at; + do { + /* this handles the "catch all" and "-default" extension */ + /* but also the normal eMail address */ + + /* build the search string for the email address */ + if (!stralloc_copys(&filter,"(" ) ) _exit(QLX_NOMEM); + /* optional objectclass */ + if ( qldap_objectclass.len ) { + if (!stralloc_cats(&filter,"&(")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_OBJECTCLASS)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"=")) _exit(QLX_NOMEM); + if (!stralloc_cat(&filter,&qldap_objectclass)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,")(")) _exit(QLX_NOMEM); + } /* end */ + + /* mail address */ + if (!stralloc_cats(&filter,"|(")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_MAIL)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"=")) _exit(QLX_NOMEM); + /* username till current '-' */ + if (!stralloc_catb(&filter,s, i)) _exit(QLX_NOMEM); + if ( i != at ) { /* do not append catchall in the first round */ + /* catchall or default */ + if ( i != 0 ) /* add '-' */ + if (!stralloc_cats(&filter,auto_break)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_CATCH_ALL)) _exit(QLX_NOMEM); + } + /* @damin.com */ + if (!stralloc_catb(&filter,s+at, len-at)) _exit(QLX_NOMEM); + + /* mailalternate address */ + if (!stralloc_cats(&filter,")(")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_MAILALTERNATE)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"=")) _exit(QLX_NOMEM); + /* username till current '-' */ + if (!stralloc_catb(&filter,s, i)) _exit(QLX_NOMEM); + if ( i != at ) { /* do not append catchall in the first round */ + /* catchall or default */ + if ( i != 0 ) /* add '-' */ + if (!stralloc_cats(&filter,auto_break)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_CATCH_ALL)) _exit(QLX_NOMEM); + } + /* @damin.com */ + if (!stralloc_catb(&filter,s+at, len-at)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"))")) _exit(QLX_NOMEM); + + /* optional objectclass */ + if ( qldap_objectclass.len ) { + if (!stralloc_cats(&filter,")")) _exit(QLX_NOMEM); + } /* end */ + if (!stralloc_0(&filter)) _exit(QLX_NOMEM); + + log(16, "ldapfilter: '%s'\n", filter.s); + search.filter = filter.s; + search.bindpw = 0; /* rebind off */ + + /* initalize the different objects */ + extra[0].what = LDAP_QUOTA; + extra[1].what = LDAP_FORWARDS; + extra[2].what = LDAP_PROGRAM; + extra[3].what = LDAP_MODE; + extra[4].what = LDAP_REPLYTEXT; + extra[5].what = LDAP_DOTMODE; + extra[6].what = 0; + + /* do the search for the email address */ + ret = qldap_lookup(&search, attrs, &info, extra); + + if ( ret == 0 || i == 0 ) break; /* something found or nothing found */ +#ifdef DASH_EXT + /* XXX if mail starts with a - it will probably not work as expected */ + while ( i != 0 ) { + i--; + if ( s[i] == *auto_break ) break; + } +#else + /* normal qmail-ldap behavior test for username@domain.com and + catchall@domain.com */ + i = 0; +#endif + + } while ( ret != 0 && qldap_errno == LDAP_NOSUCH ); + + alloc_free(filter.s); filter.s = 0; + +ldap_fail: + qldap_close(); /* now close the ldap (TCP) connection */ + if ( ret != 0 ) { + switch(qldap_errno) { + case LDAP_INIT: + return 11; + break; + case LDAP_BIND: + return 13; + break; + case LDAP_BIND_UNREACH: + return 15; + break; + case LDAP_SEARCH_TIMEOUT: + return 16; + break; + default: + return 1; + break; + } + return 1; /* just in case... */ + } + + /* go through the attributes and set the proper args for qmail-local * + * this can probably done with some sort of loop, but hey, how cares? */ + log(32, "found: user='%s' uid=%s gid=%s homedir='%s' mms='%s' host='%s' status=%i\n", + info.user, info.uid, info.gid, info.homedir, + info.mms, info.host, info.status); + + /* check if the ldap entry is active */ + if ( info.status == STATUS_BOUNCE ) { + log(2, "warning: %s's accountsatus is bounce\n", info.user); + _exit(225); + } + +#ifdef QLDAP_CLUSTER + /* check if the I'm the right host */ + if ( qldap_cluster && info.host && + str_diff(qldap_me.s, info.host) && + !constmap(&qldap_mailhosts, info.host, str_len(info.host)) ) { + /* hostname is different, so I reconnect */ + forward_mail(info.host, mail, from, fdmess); + /* that's it. Function does not return */ + } +#endif + + if (!chck_users(info.user) ) return 20; + /* set the value for qmail-local... */ + if (!stralloc_copys(&nughde, info.user) ) _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + alloc_free(info.user); + + /* get the UID for delivery on the local system */ + scan_ulong(info.uid, &tid); + if (UID_MIN > tid || tid > UID_MAX ) return 21; + if (!stralloc_cats(&nughde, info.uid)) _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + alloc_free(info.uid); + + /* get the GID for delivery on the local system */ + scan_ulong(info.gid, &tid); + if (GID_MIN > tid || tid > GID_MAX ) return 22; + if (!stralloc_cats(&nughde, info.gid)) _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + alloc_free(info.gid); + + /* get the path of the maildir or mbox */ + force_forward = 0; + if ( info.homedir ) { + if (!chck_paths(info.homedir) ) return 23; + if (!stralloc_cats(&nughde, info.homedir)) _exit(QLX_NOMEM); + alloc_free(info.homedir); + if ( info.mms ) { + if (!chck_paths(info.mms) ) return 23; + aliasempty = info.mms; + } + } else if ( info.mms ) { + if (!chck_paths(info.mms) ) return 23; + if (!stralloc_cats(&nughde, info.mms)) _exit(QLX_NOMEM); + alloc_free(info.mms); + } else { + /* XXX nothing defined use ~alias as home and + * XXX ALIASDEVNULL as aliasempty */ + struct passwd *pw; + pw = getpwnam(auto_usera); + if (!pw) { + _exit(QLX_NOALIAS); + } + if (!stralloc_cats(&nughde, pw->pw_dir)) _exit(QLX_NOMEM); + aliasempty = ALIASDEVNULL; + force_forward = 1; + } + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + + /* At the moment we ignore the dash-field and the extension field * + * so we fill up the nughde structure with '\0' */ + if ( i < at && i != 0 ) + if (!stralloc_cats(&nughde,"-")) _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + if ( i < at && i != 0 ) { + if (!stralloc_catb(&nughde,s+i+1,at-i-1)) _exit(QLX_NOMEM); + } + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + + /* get the quota for the user of that maildir mbox */ + if ( extra[0].vals != 0 ) { + log(32, "%s: %s\n", ENV_QUOTA, extra[0].vals[0]); + if ( !env_put2(ENV_QUOTA, extra[0].vals[0] ) ) _exit(QLX_NOMEM); + } else { + if ( qldap_defaultquota.s ) { + log(32, "%s: %s\n", ENV_QUOTA, qldap_defaultquota.s); + if ( !env_put2(ENV_QUOTA, qldap_defaultquota.s )) _exit(QLX_NOMEM); + } else { + log(32, "no quota set\n"); + if ( !env_unset(ENV_QUOTA) ) _exit(QLX_NOMEM); + } + } + ldap_value_free(extra[0].vals); + + /* get the forwarding addresses and build a list * + * equals to &jdoe@heaven.af.mil in .qmail */ + if ( extra[1].vals != 0 ) { + if (!stralloc_copys(&foo, "")) _exit(QLX_NOMEM); + for ( i = 0; extra[1].vals[i] != 0; i++ ) { + if (!stralloc_cats(&foo, extra[1].vals[i])) _exit(QLX_NOMEM); + if (extra[1].vals[i+1] == 0 ) break; + if (!stralloc_cats(&foo, ",") ) _exit(QLX_NOMEM); + } + if (!stralloc_0(&foo) ) _exit(QLX_NOMEM); + log(32, "%s: %s\n", ENV_FORWARDS, foo.s ); + if ( !env_put2(ENV_FORWARDS, foo.s) ) _exit(QLX_NOMEM); + } else { + /* default */ + if ( !env_unset(ENV_FORWARDS) ) _exit(QLX_NOMEM); + } + ldap_value_free(extra[1].vals); + + /* get the path of the local delivery program * + * equals to |/usr/bin/program in .qmail */ + if ( extra[2].vals != 0 ) { + if (!stralloc_copys(&foo, "")) _exit(QLX_NOMEM); + for ( i = 0; extra[2].vals[i] != 0; i++ ) { + /* append */ + if (!chck_progs(extra[2].vals[i]) ) return 31; /* XXX */ + if (!stralloc_cats(&foo, extra[2].vals[i])) _exit(QLX_NOMEM); + if (extra[2].vals[i+1] == 0 ) break; + if (!stralloc_cats(&foo, ",") ) _exit(QLX_NOMEM); + } + if (!stralloc_0(&foo) ) _exit(QLX_NOMEM); + log(32, "%s: %s\n", ENV_PROGRAM, foo.s ); + if ( !env_put2(ENV_PROGRAM, foo.s) ) _exit(QLX_NOMEM); + } else { + /* default */ + if ( !env_unset(ENV_PROGRAM) ) _exit(QLX_NOMEM); + } + ldap_value_free(extra[2].vals); + + /* prefetch the reply text so we can remove it if no deliverymode + * is set. */ + if ( extra[4].vals != 0 ) { + log(32, "%s: %s\n", ENV_REPLYTEXT, extra[4].vals[0] ); + if ( !env_put2(ENV_REPLYTEXT, extra[4].vals[0]) ) _exit(QLX_NOMEM); + } else { + if ( !env_unset(ENV_REPLYTEXT) ) _exit(QLX_NOMEM); + } + ldap_value_free(extra[4].vals); + + /* get the deliverymode of the mailbox: * + * reply, echo, forwardonly, normal, nombox, localdelivery */ + if ( extra[3].vals != 0 ) { + if (!stralloc_copys(&foo, "")) _exit(QLX_NOMEM); + for ( i = 0; extra[3].vals[i] != 0; i++ ) { + /* append */ + case_lowers(extra[3].vals[i]); + if (!stralloc_cats(&foo, extra[3].vals[i])) _exit(QLX_NOMEM); + if (extra[3].vals[i+1] == 0 ) break; + if (!stralloc_cats(&foo, ",") ) _exit(QLX_NOMEM); + } + if (!stralloc_0(&foo) ) _exit(QLX_NOMEM); + log(32, "%s: %s\n", ENV_MODE, foo.s ); + if ( !env_put2(ENV_MODE, foo.s) ) _exit(QLX_NOMEM); + } else { + /* default */ + if ( !env_unset(ENV_MODE) ) _exit(QLX_NOMEM); + if ( !env_unset(ENV_REPLYTEXT) ) _exit(QLX_NOMEM); + } + ldap_value_free(extra[3].vals); + + /* get the mode of the .qmail interpretion: ldaponly, dotonly, both, none */ + if ( extra[5].vals != 0 ) { + case_lowers(extra[5].vals[0]); + if ( !str_diff(DOTMODE_LDAPONLY, extra[5].vals[0]) ) { + if ( !env_put2(ENV_DOTMODE, DOTMODE_LDAPONLY) ) _exit(QLX_NOMEM); + } else if ( !str_diff(DOTMODE_LDAPWITHPROG, extra[5].vals[0]) ) { + if ( !env_put2(ENV_DOTMODE, DOTMODE_LDAPWITHPROG) ) _exit(QLX_NOMEM); + } else if ( !str_diff(DOTMODE_DOTONLY, extra[5].vals[0]) ) { + if ( !env_put2(ENV_DOTMODE, DOTMODE_DOTONLY) ) _exit(QLX_NOMEM); + } else if ( !str_diff(DOTMODE_BOTH, extra[5].vals[0]) ) { + if ( !env_put2(ENV_DOTMODE, DOTMODE_BOTH) ) _exit(QLX_NOMEM); + } else if ( !str_diff(DOTMODE_NONE, extra[5].vals[0]) ) { + if ( !env_put2(ENV_DOTMODE, DOTMODE_NONE) ) _exit(QLX_NOMEM); + } else { + if ( !env_put2(ENV_DOTMODE, qldap_defdotmode.s) ) _exit(QLX_NOMEM); + } + } else { + /* default */ + if ( !env_put2(ENV_DOTMODE, qldap_defdotmode.s) ) _exit(QLX_NOMEM); + } + log(32, "%s: %s\n", ENV_DOTMODE, env_get(ENV_DOTMODE) ); + ldap_value_free(extra[5].vals); + + if ( force_forward ) { + /* XXX forcing forward only for useres with no homedir */ + if ( !env_put2(ENV_DOTMODE, DOTMODE_LDAPONLY) ) _exit(QLX_NOMEM); + if ( !env_put2(ENV_MODE, MODE_FORWARD) ) _exit(QLX_NOMEM); + } + /* ok, we finished, lets clean up and disconnect from the LDAP server */ + /* XXX qldap_ldapclose() */ + return 0; +} +/* end -- LDAP server query routines */ + +stralloc lower = {0}; stralloc wildchars = {0}; void nughde_get(local) char *local; { char *(args[3]); - int pi[2]; - int gpwpid; - int gpwstat; - int r; - int fd; - int flagwild; + int pi[2], + gpwpid, + gpwstat, + r, + fd, + flagwild; if (!stralloc_copys(&lower,"!")) _exit(QLX_NOMEM); if (!stralloc_cats(&lower,local)) _exit(QLX_NOMEM); @@ -97,8 +689,7 @@ if (errno != error_noent) _exit(QLX_CDB); - if (fd != -1) - { + if (fd != -1) { uint32 dlen; unsigned int i; @@ -111,20 +702,17 @@ i = lower.len; flagwild = 0; - do - { + do { /* i > 0 */ - if (!flagwild || (i == 1) || (byte_chr(wildchars.s,wildchars.len,lower.s[i - 1]) < wildchars.len)) - { + if (!flagwild || (i == 1) || (byte_chr(wildchars.s,wildchars.len,lower.s[i - 1]) < wildchars.len)) { r = cdb_seek(fd,lower.s,i,&dlen); if (r == -1) _exit(QLX_CDB); - if (r == 1) - { + if (r == 1) { if (!stralloc_ready(&nughde,(unsigned int) dlen)) _exit(QLX_NOMEM); nughde.len = dlen; if (cdb_bread(fd,nughde.s,nughde.len) == -1) _exit(QLX_CDB); if (flagwild) - if (!stralloc_cats(&nughde,local + i - 1)) _exit(QLX_NOMEM); + if (!stralloc_cats(&nughde,local + i - 1)) _exit(QLX_NOMEM); if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); close(fd); return; @@ -132,8 +720,7 @@ } --i; flagwild = 1; - } - while (i); + } while (i); close(fd); } @@ -142,10 +729,10 @@ args[0] = "bin/qmail-getpw"; args[1] = local; args[2] = 0; - switch(gpwpid = vfork()) - { + switch(gpwpid = vfork()) { case -1: _exit(QLX_SYS); + case 0: if (prot_gid(auto_gidn) == -1) _exit(QLX_USAGE); if (prot_uid(auto_uidp) == -1) _exit(QLX_USAGE); @@ -158,8 +745,7 @@ if (slurpclose(pi[0],&nughde,128) == -1) _exit(QLX_SYS); - if (wait_pid(&gpwstat,gpwpid) != -1) - { + if (wait_pid(&gpwstat,gpwpid) != -1) { if (wait_crashed(gpwstat)) _exit(QLX_SYS); if (wait_exitcode(gpwstat) != 0) _exit(wait_exitcode(gpwstat)); } @@ -171,22 +757,81 @@ { int f; - if (!(f = fork())) - { + if (!(f = fork())) { char *(args[11]); unsigned long u; - int n; - int uid; - int gid; + int n, + uid, + gid; char *x; unsigned int xlen; + + stralloc ra = {0}; + int rv; + log_init(fdout, -1, 1); + + sig_hangupdefault(); /* clear the hup sig handler for the child */ + + /* copy the whole email address before the @ gets destroyed */ + if (!stralloc_copys(&ra,r)) _exit(QLX_NOMEM); + log(16, "mailaddr: %S\n", &ra); + /* end -- save the @ */ + r[at] = 0; if (!r[0]) _exit(0); /* <> */ if (chdir(auto_qmail) == -1) _exit(QLX_USAGE); - nughde_get(r); + /* do the address lookup */ + rv = qldap_get(&ra, s, fdmess); + switch( rv ) { + case 0: + log(16, "LDAP lookup succeeded\n"); + break; + + case 1: + if (!stralloc_copys(&nughde,"")) _exit(QLX_NOMEM); + if ( qldap_localdelivery == 1 ) { + /* do the address lookup local */ + /* this is the standart qmail lookup funktion */ + log(4, "LDAP lookup failed using local db\n"); + nughde_get(r); + + /* the alias-user handling for LDAP only mode */ + } else { + struct passwd *pw; + char num[FMT_ULONG]; + + log(4, "LDAP lookup failed using alias (no local db)\n"); + pw = getpwnam(auto_usera); + if (!pw) { + _exit(QLX_NOALIAS); + } + + if (!stralloc_copys(&nughde, pw->pw_name)) _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + if (!stralloc_catb(&nughde,num,fmt_ulong(num, (long) pw->pw_uid))) + _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + if (!stralloc_catb(&nughde,num,fmt_ulong(num, (long) pw->pw_gid))) + _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + if (!stralloc_cats(&nughde, pw->pw_dir)) _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + if (!stralloc_cats(&nughde,"-")) _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + if (!stralloc_cats(&nughde,r)) _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + } + /* end -- alias-user handling */ + break; + + default: + log(2, "warning: ldap lookup failed (%i)\n", rv); + _exit(190 + rv); + break; + } /* end switch */ x = nughde.s; xlen = nughde.len; @@ -194,31 +839,41 @@ args[0] = "bin/qmail-local"; args[1] = "--"; args[2] = x; + n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n; scan_ulong(x,&u); uid = u; - n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n; + + n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(198); x += n; xlen -= n; scan_ulong(x,&u); gid = u; - n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n; + + n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(198); x += n; xlen -= n; args[3] = x; - n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n; + + n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(198); x += n; xlen -= n; args[4] = r; + args[5] = x; - n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n; + + n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(198); x += n; xlen -= n; args[6] = x; - n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n; + n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(198); x += n; xlen -= n; args[7] = r + at + 1; args[8] = s; args[9] = aliasempty; args[10] = 0; + log(8, "executing 'qmail-local -- %s %s %s %s %s %s %s %s' under uid=%i, gid=%i\n", + args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], + uid, gid); + if (fd_move(0,fdmess) == -1) _exit(QLX_SYS); if (fd_move(1,fdout) == -1) _exit(QLX_SYS); if (fd_copy(2,1) == -1) _exit(QLX_SYS); @@ -232,3 +887,98 @@ } return f; } + + +#ifdef QLDAP_CLUSTER +stralloc dtline = {0}; + +void bouncexf(int fdmess) +{ + int match; + char buf[1024]; + substdio ss; + + if (seek_begin(fdmess) == -1) _exit(QLX_SYS); + substdio_fdbuf(&ss,read,fdmess,buf,sizeof(buf)); + for (;;) + { + if (getln(&ss,&foo,&match,'\n') != 0) _exit(QLX_SYS); + if (!match) break; + if (foo.len <= 1) + break; + if (foo.len == dtline.len) + if (!str_diffn(foo.s,dtline.s,dtline.len)) + _exit(241); + } +} + +void forward_mail(char *host, stralloc *to, char* from, int fdmess) +{ + char *(args[3]); + int pi[2]; + int wstat; + int child; + int i; + char buf[256]; + substdio ss; + + if (!stralloc_copys(&dtline, "Delivered-To: CLUSTERHOST ")) _exit(QLX_NOMEM); + if (!stralloc_catb(&dtline, qldap_me.s, qldap_me.len - 1 )) _exit(QLX_NOMEM); + if (!stralloc_cats(&dtline, " ")) _exit(QLX_NOMEM); + if (!stralloc_cat(&dtline, to)) _exit(QLX_NOMEM); + for (i = 0;i < dtline.len;++i) if (dtline.s[i] == '\n') dtline.s[i] = '_'; + if (!stralloc_cats(&dtline,"\n")) _exit(QLX_NOMEM); + + bouncexf(fdmess); + + if (seek_begin(fdmess) == -1) _exit(QLX_SYS); + if (pipe(pi) == -1) _exit(QLX_SYS); + + switch( child = fork() ) { + case -1: + if (error_temp(errno)) _exit(QLX_EXECSOFT); + _exit(QLX_EXECHARD); + case 0: + close(pi[1]); + if (fd_move(0,fdmess) == -1) _exit(QLX_SYS); + if (fd_move(1,pi[0]) == -1) _exit(QLX_SYS); + args[0]="bin/qmail-qmqpc"; args[1]=host; args[2]=0; + sig_pipedefault(); + execv(*args,args); + _exit(QLX_EXECHARD); + } + + log(8, "Forwarding to %S at host %s from %s ", to, host, from); + close(pi[0]); + substdio_fdbuf(&ss,write,pi[1],buf,sizeof(buf)); + substdio_put(&ss, "F",1); + substdio_put(&ss, from, str_len(from)); + substdio_put(&ss, "",1); + substdio_put(&ss, "T",1); + substdio_put(&ss, to->s, to->len); + substdio_put(&ss, "", 1); + substdio_put(&ss, "", 1); + substdio_put(&ss, "H",1); + substdio_put(&ss, qldap_me.s, qldap_me.len); + substdio_put(&ss, "", 1); + substdio_flush(&ss); + close(pi[1]); + wait_pid(&wstat,child); + if (wait_crashed(wstat)) { + _exit(238); + } + + switch(i=wait_exitcode(wstat)) { + case 0: + log(8, "was successful\n"); + _exit(0); + case 31: case 61: + log(8, "failed (hard error %i)/n", i); + _exit(240); + default: + log(8, "failed (soft error %i)/n", i); + _exit(239); + } +} +#endif + diff -uN qmail-1.03/qmail-pop3d.c qmail-ldap/qmail-pop3d.c --- qmail-1.03/qmail-pop3d.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/qmail-pop3d.c Fri Dec 1 02:03:07 2000 @@ -17,6 +17,16 @@ #include "timeoutread.h" #include "timeoutwrite.h" +/* qmail-ldap stuff */ +#ifdef AUTOMAILDIRMAKE +#include "error.h" +#endif + +#include "maildir++.h" +#include "env.h" +int qfd; +/* end qmail-ldap stuff */ + void die() { _exit(0); } int saferead(fd,buf,len) int fd; char *buf; int len; @@ -63,6 +73,9 @@ void die_nomem() { err("out of memory"); die(); } void die_nomaildir() { err("this user has no $HOME/Maildir"); die(); } +#ifdef AUTOMAILDIRMAKE +void die_maildir() { err("this user has a defective Maildir"); die(); } +#endif void die_scan() { err("unable to scan $HOME/Maildir"); die(); } void err_syntax() { err("syntax error"); } @@ -150,11 +163,16 @@ { int i; unsigned long total; + unsigned int count; total = 0; - for (i = 0;i < numm;++i) if (!m[i].flagdeleted) total += m[i].size; + count = 0; + for (i = 0;i < numm;++i) if (!m[i].flagdeleted) { + total += m[i].size; + count += 1; + } puts("+OK "); - put(strnum,fmt_uint(strnum,numm)); + put(strnum,fmt_uint(strnum,count)); puts(" "); put(strnum,fmt_ulong(strnum,total)); puts("\r\n"); @@ -164,6 +182,7 @@ void pop3_rset() { int i; + for (i = 0;i < numm;++i) m[i].flagdeleted = 0; last = 0; okay(); @@ -180,8 +199,16 @@ void pop3_quit() { int i; + quota_t q; + +/* qmail-ldap stuff */ +/* this is just minimal support, because pop3 can not produce new mail */ + quota_get(&q, 0); + quota_calc(".",&qfd, &q); for (i = 0;i < numm;++i) if (m[i].flagdeleted) { + if ( qfd != -1 ) quota_rm(qfd, m[i].size, 1); +/* end qmail-ldap stuff */ if (unlink(m[i].fn) == -1) err_nounlink(); } else @@ -193,6 +220,7 @@ rename(m[i].fn,line.s); /* if it fails, bummer */ } okay(); + if ( qfd != -1 ) close(qfd); die(); } @@ -257,6 +285,9 @@ int i; unsigned long limit; int fd; +#ifdef MAKE_NETSCAPE_WORK /* Based on a patch by sven@megabit.net */ + char foo[40]; /* should be enough to hold 2^128 - 1 in decimal, plus \0 */ +#endif i = msgno(arg); if (i == -1) return; @@ -267,7 +298,18 @@ fd = open_read(m[i].fn); if (fd == -1) { err_nosuch(); return; } + +#ifdef MAKE_NETSCAPE_WORK /* Based on a patch by sven@megabit.net */ + puts("+OK "); + foo[fmt_uint(foo,m[i].size)] = 0; + puts(foo); + + puts(" octets \r\n"); + flush(); +#else okay(); +#endif + substdio_fdbuf(&ssmsg,read,fd,ssmsgbuf,sizeof(ssmsgbuf)); blast(&ssmsg,limit); close(fd); @@ -291,12 +333,61 @@ int argc; char **argv; { +/* qmail-ldap stuff */ + char *env; + sig_alarmcatch(die); sig_pipeignore(); - + + /* if MAILDIR is defined us this as Maildir and not the argument */ + if ( (env = env_get("MAILDIR") ) && *env ) argv[1] = env; + if (!argv[1]) die_nomaildir(); - if (chdir(argv[1]) == -1) die_nomaildir(); - + if (chdir(argv[1]) == -1) { +#ifdef AUTOMAILDIRMAKE + if (errno == error_noent) { + umask(077); + if (mkdir(argv[1],0700) == -1) die_nomaildir(); + if (chdir(argv[1]) == -1) die_nomaildir(); + if (mkdir("tmp",0700) == -1) die_maildir(); + if (mkdir("new",0700) == -1) die_maildir(); + if (mkdir("cur",0700) == -1) die_maildir(); + } else +#endif + die_nomaildir(); + } +#ifdef AUTOMAILDIRMAKE + if ( !str_diff(argv[1], "./") ) { + struct stat st; + + umask(077); + if (stat("new", &st) == -1) { + if (errno == error_noent) { + if (mkdir("new",0700) == -1) die_maildir(); + } else { + die_maildir(); + } + } else if (! S_ISDIR(st.st_mode) ) die_maildir(); + + if (stat("cur", &st) == -1) { + if (errno == error_noent) { + if (mkdir("cur",0700) == -1) die_maildir(); + } else { + die_maildir(); + } + } else if (! S_ISDIR(st.st_mode) ) die_maildir(); + + if (stat("tmp", &st) == -1) { + if (errno == error_noent) { + if (mkdir("tmp",0700) == -1) die_maildir(); + } else { + die_maildir(); + } + } else if (! S_ISDIR(st.st_mode) ) die_maildir(); + } +#endif +/* qmail-ldap stuff */ + getlist(); okay(); diff -uN qmail-1.03/qmail-popup.c qmail-ldap/qmail-popup.c --- qmail-1.03/qmail-popup.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/qmail-popup.c Mon Jan 17 16:51:36 2000 @@ -62,6 +62,28 @@ void die_childcrashed() { err("aack, child crashed"); } void die_badauth() { err("authorization failed"); } +/* checkpassword error exit codes: + * 1 = error in server configuration + * 2 = unable to contact authorization server + * 25= user record incorrect + * 3 = authorization failed + * 4 = account disabled + * 5 = mailhost is unreachable + * 6 = mailbox is corrupted + * 7 = unable to start subprogram + * 8 = out of memory + */ + +void die_1() { err("error in server configuration"); die(); } +void die_2() { err("unable to contact authorization server"); die(); } +void die_25() { err("user record incorrect"); die(); } +void die_3() { err("authorization failed"); die(); } +void die_4() { err("account disabled"); die(); } +void die_5() { err("mailhost is unreachable"); die(); } +void die_6() { err("mailbox is corrupted"); die(); } +void die_7() { err("unable to start subprogram"); die(); } +void die_unknown() { err("temporary error"); die(); } + void err_syntax() { err("syntax error"); } void err_wantuser() { err("USER first"); } void err_authoriz() { err("authorization first"); } @@ -88,7 +110,9 @@ int wstat; int pi[2]; +#ifndef DEBUG if (fd_copy(2,1) == -1) die_pipe(); +#endif close(3); if (pipe(pi) == -1) die_pipe(); if (pi[0] != 3) die_pipe(); @@ -115,7 +139,19 @@ byte_zero(upbuf,sizeof upbuf); if (wait_pid(&wstat,child) == -1) die(); if (wait_crashed(wstat)) die_childcrashed(); - if (wait_exitcode(wstat)) die_badauth(); + switch (wait_exitcode(wstat)) { + case 0: die(); + case 1: die_1(); + case 2: die_2(); + case 25: die_25(); + case 3: die_3(); + case 4: die_4(); + case 5: die_5(); + case 6: die_6(); + case 7: die_7(); + case 8: die_nomem(); + default: die_unknown(); + } die(); } void pop3_greet() diff -uN qmail-1.03/qmail-qmqpc.c qmail-ldap/qmail-qmqpc.c --- qmail-1.03/qmail-qmqpc.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/qmail-qmqpc.c Fri Dec 1 02:03:07 2000 @@ -18,7 +18,10 @@ #include "control.h" #include "fmt.h" +#ifndef PORT_QMQP /* this is for testing purposes, so you can overwrite + this port via a simple -D argument */ #define PORT_QMQP 628 +#endif void die_success() { _exit(0); } void die_perm() { _exit(31); } @@ -56,6 +59,8 @@ /* WARNING: can use only one of these at a time! */ stralloc beforemessage = {0}; +stralloc toline = {0}; +stralloc dtline = {0}; stralloc message = {0}; stralloc aftermessage = {0}; @@ -65,6 +70,7 @@ void getmess() { int match; + int i; if (slurpclose(0,&message,1024) == -1) die_read(); @@ -95,7 +101,29 @@ if (!stralloc_cats(&aftermessage,":")) nomem(); if (!stralloc_catb(&aftermessage,line.s + 1,line.len - 2)) nomem(); if (!stralloc_cats(&aftermessage,",")) nomem(); + /* only use the last (and only) TO address */ + if (!stralloc_copyb(&toline,line.s + 1,line.len - 2)) nomem(); } + /* extension to qmail-qmqpc for clustering mode, add Delivered-To: CLUSTERHOST $HOST * + * at the top of the mail */ + if (getln(&envelope,&line,&match,'\0') == -1) die_read(); + if (!match) { + dtline.len = 0; /* just set the lenght to 0 */ + dtline.s = 0; /* just to be sure */ + return; + } + if (line.len < 2) die_format(); + if (line.s[0] != 'H') die_format(); + if (!stralloc_copys(&dtline, "Delivered-To: CLUSTERHOST ")) nomem(); + if (!stralloc_catb(&dtline, line.s + 1,line.len - 2 )) nomem(); + if (!stralloc_cats(&dtline, " ")) nomem(); + if (!stralloc_cat(&dtline, &toline)) nomem(); + for (i = 0;i < dtline.len;++i) if (dtline.s[i] == '\n') dtline.s[i] = '_'; + if (!stralloc_cats(&dtline,"\n")) nomem(); + strnum[fmt_ulong(strnum,(unsigned long) message.len+dtline.len)] = 0; + if (!stralloc_copys(&beforemessage,strnum)) nomem(); + if (!stralloc_cats(&beforemessage,":")) nomem(); + } void doit(server) @@ -116,10 +144,12 @@ return; } - strnum[fmt_ulong(strnum,(unsigned long) (beforemessage.len + message.len + aftermessage.len))] = 0; + strnum[fmt_ulong(strnum, (unsigned long) + (beforemessage.len + dtline.len + message.len + aftermessage.len))] = 0; substdio_puts(&to,strnum); substdio_puts(&to,":"); substdio_put(&to,beforemessage.s,beforemessage.len); + substdio_put(&to,dtline.s,dtline.len); substdio_put(&to,message.s,message.len); substdio_put(&to,aftermessage.s,aftermessage.len); substdio_puts(&to,","); @@ -135,7 +165,14 @@ stralloc servers = {0}; -main() +#include "dns.h" +#include "ipalloc.h" + +ipalloc ia = {0}; + +void main(argc,argv) +int argc; +char **argv; { int i; int j; @@ -144,6 +181,20 @@ if (chdir(auto_qmail) == -1) die_home(); if (control_init() == -1) die_control(); + if ( argv[1] ) { + char temp[IPFMT]; + if (!stralloc_copys(&servers,argv[1])) nomem(); + dns_init(0); + switch (dns_ip(&ia,&servers)) { + case DNS_HARD: die_perm(); + case DNS_SOFT: die_temp(); + case DNS_MEM: nomem(); + } + + temp[ip_fmt(temp,&ia.ix[0].ip)]=0; + if (!stralloc_copys(&servers, temp)) nomem(); + if (!stralloc_0(&servers)) nomem(); + } else if (control_readfile(&servers,"control/qmqpservers",0) != 1) die_control(); getmess(); diff -uN qmail-1.03/qmail-qmqpd.c qmail-ldap/qmail-qmqpd.c --- qmail-1.03/qmail-qmqpd.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/qmail-qmqpd.c Fri Apr 27 12:14:47 2001 @@ -8,6 +8,7 @@ #include "now.h" #include "fmt.h" #include "env.h" +#include "str.h" void resources() { _exit(111); } @@ -78,7 +79,7 @@ if (!local) local = env_get("TCPLOCALIP"); if (!local) local = "unknown"; - received(&qq,"QMQP",local,remoteip,remotehost,remoteinfo,(char *) 0); + received(&qq,"QMQP",local,remoteip,remotehost,remoteinfo,(char *) 0,(char *) 0,(char *) 0); } char buf[1000]; diff -uN qmail-1.03/qmail-qmtpd.c qmail-ldap/qmail-qmtpd.c --- qmail-1.03/qmail-qmtpd.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/qmail-qmtpd.c Sat Oct 2 17:57:09 1999 @@ -130,7 +130,7 @@ else if (ch == 13) flagdos = 1; else badproto(); - received(&qq,"QMTP",local,remoteip,remotehost,remoteinfo,(char *) 0); + received(&qq,"QMTP",local,remoteip,remotehost,remoteinfo,(char *) 0,(char *) 0,(char *) 0); /* XXX: check for loops? only if len is big? */ diff -uN qmail-1.03/qmail-quotawarn.c qmail-ldap/qmail-quotawarn.c --- qmail-1.03/qmail-quotawarn.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qmail-quotawarn.c Fri Mar 10 23:11:48 2000 @@ -0,0 +1,338 @@ +#include +#include +#include +#include "readwrite.h" +#include "sig.h" +#include "byte.h" +#include "case.h" +#include "datetime.h" +#include "env.h" +#include "error.h" +#include "exit.h" +#include "newfield.h" +#include "open.h" +#include "seek.h" +#include "str.h" +#include "strerr.h" +#include "stralloc.h" +#include "substdio.h" +#include "wait.h" +#include "getln.h" +#include "lock.h" +#include "now.h" +#include "fmt.h" +#include "myctime.h" +#include "qmail-ldap.h" + +/* global vars */ +stralloc warning={0}; +stralloc to={0}; +stralloc from={0}; +stralloc host={0}; +stralloc dtline={0}; +stralloc ufline={0}; +stralloc rpline={0}; +stralloc temp={0}; + +char buf[1024]; + +void temp_nomem() { strerr_die1x(111,"Out of memory. (LDAP-ERR #5.5.0)"); } +void temp_qmail(fn) char *fn; +{ strerr_die5x(111,"Unable to open ",fn,": ",error_str(errno),". (LDAP-ERR #5.5.1)"); } +void temp_rewind() { strerr_die1x(111,"Unable to rewind message. (LDAP-ERR #5.5.2)"); } +void temp_slowlock() +{ strerr_die1x(111,"File has been locked for 30 seconds straight. (#4.3.0)"); } + +void check_maildir(void); +void write_maildir(char* fn); +void check_mailfile(char* fn); +void write_mailfile(char* fn); + +int main (int argc, char **argv) +{ + char *s; + char *fn; + + if (!env_init()) temp_nomem(); + + if( !argv[1] || argv[2] ) + strerr_die3x(111,"Usage: ", argv[0], " mailbox (LDAP-ERR #5.0.1)"); + + fn = argv[1]; + + if (! (s = env_get(ENV_QUOTAWARNING) ) ) + strerr_die2x(111,ENV_QUOTAWARNING, " not present (LDAP-ERR #5.1.1)"); + if (!stralloc_copys(&warning,s)) temp_nomem(); + + if (! (s = env_get("HOST") ) ) + strerr_die1x(111,"ARRG: HOST not present (LDAP-ERR #5.1.3)"); + if (!stralloc_copys(&host,s)) temp_nomem(); + + if ( fn[str_len(fn)-1] == '/' ) { + write_maildir(fn); + } else { + check_mailfile(fn); + write_mailfile(fn); + } + /* should never get here */ + return 7; +} + + +/* a match function */ +static int wild_matchb(register char* pattern, register unsigned int pat_len, + register char* string, unsigned int len) +{ + register unsigned int i; + register unsigned int t; + + t = len-pat_len; + for(i=0; i < t; i++) { + if (!str_diffn( pattern, string+i, pat_len) ) + return 0; + } + return 1; +} + + +void check_maildir(void) +{ + char *(dirs[3]); + DIR *folder; + struct dirent *entry; + int i; + + dirs[0]="new"; dirs[1]="cur"; dirs[2]="tmp"; + for (i=0; i<3; i++ ) { + /* checking for old mail */ + if ( (folder = opendir(dirs[i])) == 0 ) + strerr_die1x(111,"Error while checking for QUOTA_WARNING file (LDAP-ERR #5.2.2)"); + while ((entry = readdir(folder)) != 0) { + if (!str_diffn("QUOTA_WARNING", entry->d_name, str_len( "QUOTA_WARNING"))) + _exit(0); + } + closedir(folder); + } + +} + +char fntmptph[30]; +char fnnewtph[30]; +void tryunlinktmp() { unlink(fntmptph); } +void sigalrm() + { tryunlinktmp(); strerr_die1x(111,"Timeout on quota-warning delivery. (LDAP-ERR #5.2.9)"); } + +void write_maildir(char* fn) +{ + char *s; + char *t; + int loop; + struct stat st; + int fd; + datetime_sec starttime; + substdio ssout; + + sig_alarmcatch(sigalrm); + if (chdir(fn) == -1) { + if (error_temp(errno)) + strerr_die1x(111,"Temporary error on qmail-warning delivery. (LDAP_ERR #5.2.8)"); + strerr_die1x(111,"Unable to chdir to maildir. (LDAP-ERR #5.2.1)"); + } + + check_maildir(); + + /* set To: From: Delivered-to: Return-Path: UFLINE Date: Message-ID: */ + if (! (t = env_get("RECIPIENT") ) ) + strerr_die1x(111,"ARRG: RECIPIENT not present (LDAP-ERR #5.1.2)"); + if (!stralloc_copys(&to,"To: ")) temp_nomem(); + if (!stralloc_cats(&to,t)) temp_nomem(); + if (!stralloc_cats(&to,"\n")) temp_nomem(); + + if (!stralloc_copys(&from,"From: Qmail-QUOTAGUARD \n")) temp_nomem(); + + if (! (t = env_get("DTLINE") ) ) + strerr_die1x(111,"ARRG: DTLINE not present (LDAP-ERR #5.1.4)"); + if (!stralloc_copys(&dtline,t)) temp_nomem(); + + if (!stralloc_copys(&rpline,"Return-Path: <>\n")) temp_nomem(); + + starttime = now(); + if (!newfield_datemake(starttime)) temp_nomem(); + if (!newfield_msgidmake(host.s,host.len,starttime)) temp_nomem(); + + + for (loop = 0;;++loop) { + s = fntmptph; + s += fmt_str(s,"tmp/"); + s += fmt_strn(s,"QUOTA_WARNING",sizeof("QUOTA_WARNING")); *s++ = 0; + if (stat(fntmptph,&st) == -1) if (errno == error_noent) break; + /* really should never get to this point */ + if (loop == 2) strerr_die1x(111,"Temporary error on qmail-warning delivery. (LDAP_ERR #5.2.8)"); + sleep(2); + } + str_copy(fnnewtph,fntmptph); + byte_copy(fnnewtph,3,"new"); + + alarm(86400); + fd = open_excl(fntmptph); + if (fd == -1) strerr_die1x(111,"Temporary error on qmail-warning delivery. (LDAP_ERR #5.2.8)"); + + substdio_fdbuf(&ssout,write,fd,buf,sizeof(buf)); + if (substdio_put(&ssout,rpline.s,rpline.len) == -1) goto fail; + if (substdio_put(&ssout,dtline.s,dtline.len) == -1) goto fail; + /* Received: line */ + if (substdio_puts(&ssout,"Received: (directly through the qmail-quota-warning program);\n\t")) + goto fail; + if (substdio_puts(&ssout,myctime(starttime))) goto fail; + /* Qmail-QUOTAWARNING: line */ + if (substdio_puts(&ssout,"Qmail-QuotaWarning: ")) goto fail; + if (substdio_put(&ssout,host.s,host.len)) goto fail; + if (substdio_puts(&ssout,"\n")) goto fail; + /* message-id and date line */ + if (substdio_put(&ssout,newfield_msgid.s,newfield_msgid.len)) goto fail; + if (substdio_put(&ssout,newfield_date.s,newfield_date.len)) goto fail; + /* To: From: and Subject: */ + if (substdio_put(&ssout,to.s,to.len)) goto fail; + if (substdio_put(&ssout,from.s,from.len)) goto fail; + if (substdio_puts(&ssout,"Subject: QUOTA-WARNING !\n")) goto fail; + /* don't forget the single \n */ + if (substdio_puts(&ssout,"\n")) goto fail; + /* the Warning */ + if (substdio_put(&ssout,warning.s,warning.len)) goto fail; + if (warning.s[warning.len-1] == '\n') + if (substdio_bputs(&ssout,"\n")) goto fail; + + + if (substdio_flush(&ssout) == -1) goto fail; + if (fsync(fd) == -1) goto fail; + if (close(fd) == -1) goto fail; /* NFS dorks */ + + if (link(fntmptph,fnnewtph) == -1) /* if error_exist unlink and exit(0), strange things can happen */ + if ( errno != error_exist) goto fail; + tryunlinktmp(); _exit(0); + + fail: + tryunlinktmp(); + strerr_die1x(111,"Temporary error on qmail-warning delivery. (LDAP_ERR #5.2.8)"); + +} + +void check_mailfile(char* fn) +{ + int fd; + int len; + int match; + substdio ss; + + fd = open_read(fn); + if (seek_begin(fd) == -1) temp_rewind(); + + substdio_fdbuf(&ss, read, fd, buf, sizeof(buf) ); + do { + if( getln(&ss, &temp, &match, '\n') != 0 ) { + strerr_warn3("Unable to read message: ",error_str(errno),". (LDAP-ERR #5.3.1)",0); + break; /* something bad happend, but we ignore it :-( */ + } + case_lowerb(temp.s, (len = byte_chr(temp.s,temp.len,':') ) ); + if( !str_diffn("qmail-quotawarning:", temp.s, len+1) ) { + if (!wild_matchb(host.s, host.len, temp.s+len+1, temp.len-len-2) ) { + /* quota warning allready in mailbox */ + close(fd); + _exit(0); + } + } + } while (match); + /* no quota warning found */ + close(fd); + return; +} + + +void write_mailfile(char* fn) +{ + int fd; + substdio ssout; + seek_pos pos; + int flaglocked; + char *t; + datetime_sec starttime; + + /* set To: From: Delivered-to: Return-Path: UFLINE Date: Message-ID: */ + if (! (t = env_get("RECIPIENT") ) ) + strerr_die1x(111,"ARRG: RECIPIENT not present (LDAP-ERR #5.1.2)"); + if (!stralloc_copys(&to,"To: ")) temp_nomem(); + if (!stralloc_cats(&to,t)) temp_nomem(); + if (!stralloc_cats(&to,"\n")) temp_nomem(); + + if (!stralloc_copys(&from,"From: Qmail-QUOTAGUARD \n")) temp_nomem(); + + if (! (t = env_get("DTLINE") ) ) + strerr_die1x(111,"ARRG: DTLINE not present (LDAP-ERR #5.1.4)"); + if (!stralloc_copys(&dtline,t)) temp_nomem(); + + if (!stralloc_copys(&rpline,"Return-Path: <>\n")) temp_nomem(); + + if (!stralloc_copys(&ufline,"From ")) temp_nomem(); + if (!stralloc_cats(&ufline,"MAILER-DAEMON")) temp_nomem(); + if (!stralloc_cats(&ufline," ")) temp_nomem(); + starttime = now(); + if (!stralloc_cats(&ufline,myctime(starttime))) temp_nomem(); + + if (!newfield_datemake(starttime)) temp_nomem(); + if (!newfield_msgidmake(host.s,host.len,starttime)) temp_nomem(); + + fd = open_append(fn); + if (fd == -1) + strerr_die5x(111,"Unable to open ",fn,": ",error_str(errno),". (LDAP-ERR #5.3.5)"); + + sig_alarmcatch(temp_slowlock); + alarm(30); + flaglocked = (lock_ex(fd) != -1); + alarm(0); + sig_alarmdefault(); + + seek_end(fd); + pos = seek_cur(fd); + + substdio_fdbuf(&ssout,write,fd,buf,sizeof(buf)); + if (substdio_put(&ssout,ufline.s,ufline.len)) goto writeerrs; + if (substdio_put(&ssout,rpline.s,rpline.len)) goto writeerrs; + if (substdio_put(&ssout,dtline.s,dtline.len)) goto writeerrs; + /* Received: line */ + if (substdio_puts(&ssout,"Received: (directly through the qmail-quota-warning program);\n\t")) + goto writeerrs; + if (substdio_puts(&ssout,myctime(starttime))) goto writeerrs; + /* Qmail-QUOTAWARNING: line */ + if (substdio_puts(&ssout,"Qmail-QuotaWarning: ")) goto writeerrs; + if (substdio_put(&ssout,host.s,host.len)) goto writeerrs; + if (substdio_puts(&ssout,"\n")) goto writeerrs; + /* message-id and date line */ + if (substdio_put(&ssout,newfield_msgid.s,newfield_msgid.len)) goto writeerrs; + if (substdio_put(&ssout,newfield_date.s,newfield_date.len)) goto writeerrs; + /* To: From: and Subject: */ + if (substdio_put(&ssout,to.s,to.len)) goto writeerrs; + if (substdio_put(&ssout,from.s,from.len)) goto writeerrs; + if (substdio_puts(&ssout,"Subject: QUOTA-WARNING !\n")) goto writeerrs; + /* don't forget the single \n */ + if (substdio_puts(&ssout,"\n")) goto writeerrs; + /* the Warning */ + if (substdio_put(&ssout,warning.s,warning.len)) goto writeerrs; + if (warning.s[warning.len-1] == '\n') + if (substdio_bputs(&ssout,"\n")) goto writeerrs; + if (substdio_bputs(&ssout,"\n")) goto writeerrs; + if (substdio_flush(&ssout)) goto writeerrs; + if (fsync(fd) == -1) goto writeerrs; + close(fd); + _exit(0); + + writeerrs: + strerr_warn5("Unable to write ",fn,": ",error_str(errno),". (LDAP-ERR #5.3.6)",0); + if (flaglocked) seek_trunc(fd,pos); + close(fd); + _exit(111); +} + diff -uN qmail-1.03/qmail-remote.c qmail-ldap/qmail-remote.c --- qmail-1.03/qmail-remote.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/qmail-remote.c Fri Dec 1 02:03:07 2000 @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "sig.h" #include "stralloc.h" @@ -26,12 +27,25 @@ #include "tcpto.h" #include "readwrite.h" #include "timeoutconn.h" +#ifndef TLS #include "timeoutread.h" #include "timeoutwrite.h" +#endif + +#ifdef TLS +#include +#include + +SSL *ssl = 0; +char *fqdn = 0; +#endif #define HUGESMTPTEXT 5000 +#ifndef PORT_SMTP /* this is for testing purposes, so you can overwrite + this port via a simple -D argument */ #define PORT_SMTP 25 /* silly rabbit, /etc/services is for users */ +#endif unsigned long port = PORT_SMTP; GEN_ALLOC_typedef(saa,stralloc,sa,len,a) @@ -107,17 +121,57 @@ int smtpfd; int timeout = 1200; +#ifdef TLS +int flagtimedout = 0; +void sigalrm() +{ + flagtimedout = 1; +} +int ssl_timeoutread(timeout,fd,buf,n) int timeout; int fd; char *buf; int n; +{ + int r; int saveerrno; + if (flagtimedout) { errno = error_timeout; return -1; } + alarm(timeout); + if (ssl) r = SSL_read(ssl,buf,n); else r = read(fd,buf,n); + saveerrno = errno; + alarm(0); + if (flagtimedout) { errno = error_timeout; return -1; } + errno = saveerrno; + return r; +} +int ssl_timeoutwrite(timeout,fd,buf,n) int timeout; int fd; char *buf; int n; +{ + int r; int saveerrno; + if (flagtimedout) { errno = error_timeout; return -1; } + alarm(timeout); + if (ssl) r = SSL_write(ssl,buf,n); else r = write(fd,buf,n); + saveerrno = errno; + alarm(0); + if (flagtimedout) { errno = error_timeout; return -1; } + errno = saveerrno; + return r; +} +#endif + int saferead(fd,buf,len) int fd; char *buf; int len; { int r; +#ifdef TLS + r = ssl_timeoutread(timeout,smtpfd,buf,len); +#else r = timeoutread(timeout,smtpfd,buf,len); +#endif if (r <= 0) dropped(); return r; } int safewrite(fd,buf,len) int fd; char *buf; int len; { int r; +#ifdef TLS + r = ssl_timeoutwrite(timeout,smtpfd,buf,len); +#else r = timeoutwrite(timeout,smtpfd,buf,len); +#endif if (r <= 0) dropped(); return r; } @@ -179,6 +233,33 @@ char *prepend; char *append; { +/* TAG */ +#if defined(TLS) && defined(DEBUG) +#define ONELINE_NAME(X) X509_NAME_oneline(X,NULL,0) + + if(ssl){ + X509 *peer; + + out("STARTTLS proto="); out(SSL_get_version(ssl)); + out("; cipher="); out(SSL_CIPHER_get_name(SSL_get_current_cipher(ssl))); + + /* we want certificate details */ + peer=SSL_get_peer_certificate(ssl); + if (peer != NULL) { + char *str; + + str=ONELINE_NAME(X509_get_subject_name(peer)); + out("; subject="); out(str); + Free(str); + str=ONELINE_NAME(X509_get_issuer_name(peer)); + out("; issuer="); out(str); + Free(str); + X509_free(peer); + } + out(";\n"); + } +#endif + substdio_putsflush(&smtpto,"QUIT\r\n"); /* waiting for remote side is just too ridiculous */ out(prepend); @@ -221,15 +302,147 @@ unsigned long code; int flagbother; int i; - +#ifdef TLS + int needtlsauth = 0; + SSL_CTX *ctx; + int saveerrno, r; +#ifdef DEBUG + char buf[1024]; +#endif + stralloc servercert = {0}; + struct stat st; + + if( fqdn && *fqdn ) { + if(!stralloc_copys(&servercert, "control/tlshosts/")) temp_nomem(); + if(!stralloc_cats(&servercert, fqdn)) temp_nomem(); + if(!stralloc_cats(&servercert, ".pem")) temp_nomem(); + if(!stralloc_0(&servercert)) temp_nomem(); + if (stat(servercert.s,&st) == 0) needtlsauth = 1; + } +#endif + if (smtpcode() != 220) quit("ZConnected to "," but greeting failed"); +#ifdef TLS + substdio_puts(&smtpto,"EHLO "); +#else substdio_puts(&smtpto,"HELO "); +#endif substdio_put(&smtpto,helohost.s,helohost.len); substdio_puts(&smtpto,"\r\n"); substdio_flush(&smtpto); +#ifdef TLS + if (smtpcode() != 250){ + substdio_puts(&smtpto,"HELO "); + substdio_put(&smtpto,helohost.s,helohost.len); + substdio_puts(&smtpto,"\r\n"); + substdio_flush(&smtpto); + if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected"); + } +#else if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected"); - +#endif + +#ifdef TLS + i = 0; + while((i += str_chr(smtptext.s+i,'\n') + 1) && (i+12 < smtptext.len) && + str_diffn(smtptext.s+i+4,"STARTTLS\n",9)); + if (i+12 < smtptext.len) + { + substdio_puts(&smtpto,"STARTTLS\r\n"); + substdio_flush(&smtpto); + if (smtpcode() == 220) + { +#ifdef DEBUG + SSL_load_error_strings(); +#endif + SSLeay_add_ssl_algorithms(); + if(!(ctx=SSL_CTX_new(SSLv23_client_method()))) +#ifdef DEBUG + {out("ZTLS not available: error initializing ctx"); + out(": "); + out(ERR_error_string(ERR_get_error(), buf)); + out("\n"); +#else + {out("ZTLS not available: error initializing ctx\n"); +#endif + out("\n"); + zerodie();} + + SSL_CTX_use_RSAPrivateKey_file(ctx, "control/cert.pem", SSL_FILETYPE_PEM); + SSL_CTX_use_certificate_file(ctx, "control/cert.pem", SSL_FILETYPE_PEM); + /*SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);*/ + + if (needtlsauth){ + if (!SSL_CTX_load_verify_locations(ctx, servercert.s, NULL)) + {out("ZTLS unable to load "); out(servercert.s); out("\n"); + zerodie();} + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + } + + if(!(ssl=SSL_new(ctx))) +#ifdef DEBUG + {out("ZTLS not available: error initializing ssl"); + out(": "); + out(ERR_error_string(ERR_get_error(), buf)); +#else + {out("ZTLS not available: error initializing ssl"); +#endif + out("\n"); + zerodie();} + SSL_set_fd(ssl,smtpfd); + + alarm(timeout); + r = SSL_connect(ssl); saveerrno = errno; + alarm(0); + if (flagtimedout) + {out("ZTLS not available: connect timed out\n"); + zerodie();} + errno = saveerrno; + if (r<=0) + {if (needtlsauth && (r=SSL_get_verify_result(ssl)) != X509_V_OK) + {out("ZTLS unable to verify server with "); + out(servercert.s); out(": "); + out(X509_verify_cert_error_string(r)); out("\n");} + else +#ifdef DEBUG + {out("ZTLS not available: connect failed"); + out(": "); + out(ERR_error_string(ERR_get_error(), buf)); + out("\n");} +#else + out("ZTLS not available: connect failed\n"); +#endif + zerodie();} + if (needtlsauth) + /* should also check alternate names */ + {char commonName[256]; + X509_NAME_get_text_by_NID(X509_get_subject_name( + SSL_get_peer_certificate(ssl)), + NID_commonName, commonName, 256); + if (case_diffs(fqdn,commonName)){ + out("ZTLS connection to "); out(fqdn); + out(" wanted, certificate for "); out(commonName); + out(" received\n"); + zerodie();} + } + + substdio_puts(&smtpto,"EHLO "); + substdio_put(&smtpto,helohost.s,helohost.len); + substdio_puts(&smtpto,"\r\n"); + substdio_flush(&smtpto); + + if (smtpcode() != 250) + { + quit("ZTLS connected to "," but my name was rejected"); + } + } + } + if ((!ssl) && needtlsauth) + {out("ZNo TLS achieved while "); out(servercert.s); out(" exists.\n"); + zerodie();} +#endif + substdio_puts(&smtpto,"MAIL FROM:<"); substdio_put(&smtpto,sender.s,sender.len); substdio_puts(&smtpto,">\r\n"); @@ -332,13 +545,17 @@ { static ipalloc ip = {0}; int i; + int tcpnodelay = 1; unsigned long random; char **recips; unsigned long prefme; int flagallaliases; int flagalias; char *relayhost; - + +#ifdef TLS + sig_alarmcatch(sigalrm); +#endif sig_pipeignore(); if (argc < 4) perm_usage(); if (chdir(auto_qmail) == -1) temp_chdir(); @@ -413,10 +630,16 @@ smtpfd = socket(AF_INET,SOCK_STREAM,0); if (smtpfd == -1) temp_oserr(); + + /* performace hack to send TCP ACK's without delay */ + setsockopt(smtpfd, IPPROTO_TCP, TCP_NODELAY, &tcpnodelay, sizeof(tcpnodelay)); if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) { tcpto_err(&ip.ix[i].ip,0); partner = ip.ix[i].ip; +#ifdef TLS + fqdn = ip.ix[i].fqdn; +#endif smtp(); /* does not return */ } tcpto_err(&ip.ix[i].ip,errno == error_timeout); diff -uN qmail-1.03/qmail-reply.c qmail-ldap/qmail-reply.c --- qmail-1.03/qmail-reply.c Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qmail-reply.c Tue Apr 17 00:31:23 2001 @@ -0,0 +1,215 @@ +#include "auto_qmail.h" +#include "case.h" +#include "env.h" +#include "error.h" +#include "exit.h" +#include "getln.h" +#include "qlx.h" +#include "readwrite.h" +#include "seek.h" +#include "sig.h" +#include "str.h" +#include "strerr.h" +#include "stralloc.h" +#include "substdio.h" +#include "wait.h" +#include "byte.h" +#include "fd.h" +#include "qmail-ldap.h" + +/* some error-handling funktions */ +void temp_nomem() { strerr_die1x(111,"Out of memory. (LDAP-ERR #4.5.0)"); } +void temp_rewind() { strerr_die1x(111,"Unable to rewind message. (LDAP-ERR #4.5.0)"); } +void temp_childcrashed() { strerr_die1x(111,"Aack, child crashed. (LDAP-ERR #4.5.0)"); } +void temp_fork() { strerr_die3x(111,"Unable to fork: ",error_str(errno),". (LDAP-ERR #4.5.0)"); } +void temp_read() { strerr_die3x(111,"Unable to read message: ",error_str(errno),". (LDAP-ERR #4.5.0)"); } + +/* function prototypes */ +void check_header_and_get_subject(void); +void send_reply(void); + +/* global vars */ +char buf[1024]; +char *(ignore[]) = { /* needs to be lowercase */ + "root", + "-request@", + "daemon", + "postmaster", + "mailer-daemon", + "mailer", + 0 } ; + +stralloc subject={0}; +stralloc replytext={0}; +stralloc to={0}; +stralloc from={0}; +stralloc dtline={0}; +stralloc prog={0}; +stralloc line = {0}; + +/* a match function */ +static int wild_matchb(register char* pattern, register unsigned int pat_len, \ + register char* string, unsigned int len) +{ + register unsigned int i; + register unsigned int t; + + if ( len < pat_len ) return 1; + + t = len-pat_len+1; + for(i=0; i < t; i++) { + if (!str_diffn( pattern, string+i, pat_len) ) + return 0; + } + return 1; +} + + +int main() +{ + char *s; + unsigned int i; + + if (!env_init()) temp_nomem(); + + if ( s = env_get("DTLINE") ) { + if (!stralloc_copys(&dtline,s)) temp_nomem(); + } else { + strerr_die1x(111,"DTLINE not present (LDAP-ERR #4.1.1)"); + } + + if ( s = env_get(ENV_REPLYTEXT) ) { + if (!stralloc_copys(&replytext,s)) temp_nomem(); + } else { + strerr_die2x(111,ENV_REPLYTEXT, " not present (LDAP-ERR #4.1.2)"); + } + + if ( s = env_get("SENDER") ) { + if (!stralloc_copys(&to,s)) temp_nomem(); + case_lowers(s); + for ( i=0; ignore[i]; i++ ) { + if (!wild_matchb(ignore[i], str_len(ignore[i]), s, str_len(s) ) ) { + exit(0); + } + } + } else { + strerr_die1x(111,"SENDER not present (LDAP-ERR #4.1.3)"); + } + if ( s = env_get("RECIPIENT") ) { + if (!stralloc_copys(&from,s)) temp_nomem(); + } else { + strerr_die1x(111,"RECIPIENT not present (LDAP-ERR #4.1.4)"); + } + + check_header_and_get_subject(); + + send_reply(); + + return 0; +} + + +/* get the subject, for replymode */ +void check_header_and_get_subject(void) +{ + substdio ss; + int match; + int len; + int subj_set; + + subj_set = 0; + if (seek_begin(0) == -1) temp_rewind(); + substdio_fdbuf(&ss, read, 0, buf, sizeof(buf) ); + do { + if( getln(&ss, &line, &match, '\n') != 0 ) { + strerr_warn3("Unable to read message: ",error_str(errno),". (LDAP-ERR #4.3.0)",0); + break; /* something bad happend, but we ignore it :-( */ + } + if ( line.len == 0 ) /* something is wrong, bad message */ + break; + + if ( !str_diffn("\n", line.s, 1) ) { + if ( subj_set == 0 ) { + if (!stralloc_copys(&subject, "Your mail")) temp_nomem(); + } + return; + } + case_lowerb(line.s, (len = byte_chr(line.s,line.len,':') ) ); + if ( !str_diffn("subject:", line.s, len+1) ) { + if (line.len-len-1 > 1 ) { /* subject has to be more than 1 char (normaly a \n) */ + if (!stralloc_copyb(&subject, line.s+len+1, line.len-len-1)) temp_nomem(); + subj_set=1; + } + } + if ( !str_diffn("mailing-list:", line.s, len+1) ) exit(0); /* don't send to mailing-lists */ + if ( !str_diffn("precedence:", line.s, len+1) ) { /* exit if bulk, junk, list */ + case_lowerb(line.s, line.len); + if ( !wild_matchb("list", 4, line.s+len+1, line.len-len-1) ) { + exit(0); + } + if ( !wild_matchb("bulk", 4, line.s+len+1, line.len-len-1) ) { + exit(0); + } + if ( !wild_matchb("junk", 4, line.s+len+1, line.len-len-1) ) { + exit(0); + } + } + } while (match); + strerr_warn1("Premature end of header. This message has no body. (LDAP-WARN #4.5.0) ignored",0); + if ( subj_set == 0 ) { + if (!stralloc_copys(&subject, "Your mail")) temp_nomem(); + } +} + +/* reply function */ +void send_reply(void) +{ + char *(args[3]); + int child; + int pi[2]; + int wstat; + + if (!stralloc_copys(&prog, auto_qmail)) temp_nomem(); + if (!stralloc_cats(&prog, "/bin/datemail")) temp_nomem(); + if (!stralloc_0(&prog)) temp_nomem(); + + if (pipe(pi) == -1) _exit(QLX_SYS); + switch( child = fork() ) + { + case -1: + temp_fork(); + case 0: + close(pi[1]); + if(fd_move(0,pi[0]) == -1) _exit(QLX_SYS); + args[0]=prog.s; args[1]="-t"; args[2]=0; + sig_pipedefault(); + execv(*args,args); + strerr_die5x(111,"Unable to run ",prog.s,": ",error_str(errno),". (LDAP-ERR #4.4.0)"); + } + + close(pi[0]); + write(pi[1],dtline.s,dtline.len); + write(pi[1],"Precedence: junk\n", 17); + write(pi[1],"To: ", 4); + write(pi[1],to.s, to.len); + write(pi[1], "\nFrom: ", 7); + write(pi[1], from.s, from.len); + write(pi[1], " (via the qmail-reply program)", 30); + write(pi[1], "\nSubject: ", 10); + write(pi[1], "[Auto-Reply] ", 13); + write(pi[1], subject.s, subject.len); + write(pi[1], "\n", 1); + write(pi[1],replytext.s,replytext.len); + close(pi[1]); + wait_pid(&wstat,child); + if(wait_crashed(wstat)) + temp_childcrashed(); + switch(wait_exitcode(wstat)) + { + case 100: + case 64: case 65: case 70: case 76: case 77: case 78: case 112: _exit(100); + case 0: break; + default: _exit(111); + } + +} diff -uN qmail-1.03/qmail-send.c qmail-ldap/qmail-send.c --- qmail-1.03/qmail-send.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/qmail-send.c Tue Sep 4 00:19:34 2001 @@ -56,6 +56,23 @@ stralloc doublebounceto = {0}; stralloc doublebouncehost = {0}; +stralloc custombouncetext = {0}; + +/* char replacement */ +unsigned int replace(char *s, register unsigned int len, char f, char r) +{ + register char *t; + register int count = 0; + + t=s; + for(;;) { + if (!len) return count; if (*t == f) { *t=r; count++; } ++t; --len; + if (!len) return count; if (*t == f) { *t=r; count++; } ++t; --len; + if (!len) return count; if (*t == f) { *t=r; count++; } ++t; --len; + if (!len) return count; if (*t == f) { *t=r; count++; } ++t; --len; + } +} + char strnum2[FMT_ULONG]; char strnum3[FMT_ULONG]; @@ -262,6 +279,8 @@ while (!stralloc_copys(&comm_buf[c],"")) nomem(); ch = delnum; while (!stralloc_append(&comm_buf[c],&ch)) nomem(); + ch = delnum >> 8; + while (!stralloc_append(&comm_buf[c],&ch)) nomem(); fnmake_split(id); while (!stralloc_cats(&comm_buf[c],fn.s)) nomem(); while (!stralloc_0(&comm_buf[c])) nomem(); @@ -716,6 +735,12 @@ \n\ "); + if (custombouncetext.len) + { + qmail_put(&qqt,custombouncetext.s,custombouncetext.len-1); + qmail_puts(&qqt,"\n\n"); + } + fd = open_read(fn2.s); if (fd == -1) qmail_fail(&qqt); @@ -906,44 +931,51 @@ dline[c].len = REPORTMAX; /* qmail-lspawn and qmail-rspawn are responsible for keeping it short */ /* but from a security point of view, we don't trust rspawn */ - if (!ch && (dline[c].len > 1)) + if (!ch && (dline[c].len > 2)) { delnum = (unsigned int) (unsigned char) dline[c].s[0]; + delnum += (unsigned int) ((unsigned int) dline[c].s[1]) << 8; if ((delnum < 0) || (delnum >= concurrency[c]) || !d[c][delnum].used) log1("warning: internal error: delivery report out of range\n"); else { strnum3[fmt_ulong(strnum3,d[c][delnum].delid)] = 0; - if (dline[c].s[1] == 'Z') + if (dline[c].s[2] == 'Z') if (jo[d[c][delnum].j].flagdying) { - dline[c].s[1] = 'D'; + dline[c].s[2] = 'D'; --dline[c].len; while (!stralloc_cats(&dline[c],"I'm not going to try again; this message has been in the queue too long.\n")) nomem(); while (!stralloc_0(&dline[c])) nomem(); } - switch(dline[c].s[1]) + switch(dline[c].s[2]) { case 'K': log3("delivery ",strnum3,": success: "); - logsafe(dline[c].s + 2); + logsafe(dline[c].s + 3); log1("\n"); markdone(c,jo[d[c][delnum].j].id,d[c][delnum].mpos); --jo[d[c][delnum].j].numtodo; break; case 'Z': log3("delivery ",strnum3,": deferral: "); - logsafe(dline[c].s + 2); + logsafe(dline[c].s + 3); log1("\n"); break; case 'D': log3("delivery ",strnum3,": failure: "); - logsafe(dline[c].s + 2); + logsafe(dline[c].s + 3); log1("\n"); - addbounce(jo[d[c][delnum].j].id,d[c][delnum].recip.s,dline[c].s + 2); + addbounce(jo[d[c][delnum].j].id,d[c][delnum].recip.s,dline[c].s + 3); markdone(c,jo[d[c][delnum].j].id,d[c][delnum].mpos); --jo[d[c][delnum].j].numtodo; break; + case 'L': + log3("delivery ",strnum3,": log: "); + logsafe(dline[c].s + 3); + log1("\n"); + dline[c].len = 0; + return; default: log3("delivery ",strnum3,": report mangled, will defer\n"); } @@ -1453,6 +1485,9 @@ if (!stralloc_cats(&doublebounceto,"@")) return 0; if (!stralloc_cat(&doublebounceto,&doublebouncehost)) return 0; if (!stralloc_0(&doublebounceto)) return 0; + if (control_readfile(&custombouncetext,"control/custombouncetext",0) == -1) return 0; + replace(custombouncetext.s, custombouncetext.len, '\0', '\n'); + if (!stralloc_0(&custombouncetext) ) return 0; if (control_readfile(&locals,"control/locals",1) != 1) return 0; if (!constmap_init(&maplocals,locals.s,locals.len,0)) return 0; switch(control_readfile(&percenthack,"control/percenthack",0)) @@ -1544,15 +1579,21 @@ numjobs = 0; for (c = 0;c < CHANNELS;++c) { - char ch; + char ch, ch1; int u; int r; do r = read(chanfdin[c],&ch,1); while ((r == -1) && (errno == error_intr)); if (r < 1) + { log1("alert: cannot start qmail-lspawn or it had an error! Check if ~control/ldapserver exists.\n"); _exit(111); } + do + r = read(chanfdin[c],&ch1,1); + while ((r == -1) && (errno == error_intr)); + if (r < 1) { log1("alert: cannot start: hath the daemon spawn no fire?\n"); _exit(111); } u = (unsigned int) (unsigned char) ch; + u += (unsigned int) ((unsigned char) ch1) << 8; if (concurrency[c] > u) concurrency[c] = u; numjobs += concurrency[c]; } diff -uN qmail-1.03/qmail-showctl.c qmail-ldap/qmail-showctl.c --- qmail-1.03/qmail-showctl.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/qmail-showctl.c Sun Sep 30 14:58:57 2001 @@ -19,6 +19,9 @@ stralloc me = {0}; int meok; +stralloc ldapserver = {0}; +int ldapok; + stralloc line = {0}; char num[FMT_ULONG]; @@ -213,6 +216,17 @@ substdio_flush(subfdout); _exit(111); } + ldapok = control_readline(&ldapserver,"ldapserver"); + if (ldapok == -1) { + substdio_puts(subfdout,"Oops! Trouble reading control/ldapserver."); + substdio_flush(subfdout); + _exit(111); + } + substdio_puts(subfdout,"me: My name is "); + substdio_put(subfdout, me.s, me.len); + substdio_puts(subfdout,"\nldapserver: My ldap server is "); + substdio_put(subfdout, ldapserver.s, ldapserver.len); + substdio_puts(subfdout,"\n\n"); do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM."); do_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is "); @@ -262,6 +276,35 @@ do_int("timeoutsmtpd","1200","SMTP server data timeout is "," seconds"); do_lst("virtualdomains","No virtual domains.","Virtual domain: ",""); + + substdio_puts(subfdout,"\nnow the qmail-ldap specific files\n"); + do_str("ldapserver",0,"undefined! Uh-oh","My LDAP Server is "); + do_str("ldapbasedn",0,"NULL","LDAP basedn: "); + do_str("ldaplogin",0,"NULL","LDAP login: "); + do_str("ldappassword",0,"NULL","LDAP password: "); + do_str("ldapuid",0,"not defined","Default UID is: "); + do_str("ldapgid",0,"not defined","Default GID is: "); + do_str("ldapmessagestore",0,"not defined","Prefix for non absolute paths: "); + do_str("ldapdefaultdotmode",0,"not defined","Default dot mode for ldap users: "); + do_str("ldapdefaultquota",0,"not defined","Default quota for ldap users: "); + do_str("dirmaker",0,"not defined","Location of program to create homedirs: "); + do_int("ldaplocaldelivery","1","local passwd lookup is "," (1 = on, 0 = off)"); + do_int("ldaprebind","0","ldap rebinding is "," (1 = on, 0 = off)"); + do_int("ldapcluster","0","clustering is "," (1 = on, 0 = off)"); + do_lst("ldapclusterhosts","No alternate MailHosts for clustering listed.", "Alternate MailHosts for clustering: ", ""); + + do_lst("quotawarning","No quotawarning.","",""); + do_lst("custombouncetext","No custombouncetext.","",""); + do_int("maxrcptcount","0",""," RCPT TOs are accepted before sending 553 (0 = off)"); + do_int("tarpitcount","0",""," RCPT TOs are accepted before tarpitting (0 = off)"); + do_int("tarpitdelay","5",""," seconds of delay to introduce after each subsequent RCPT TO"); + do_lst("badrcptto","Any RCPT TO is allowed.",""," not accepted in RCPT TO"); + do_lst("relaymailfrom","Relaymailfrom not enabled.","Envelope senders allowed to relay: ","."); + do_lst("rbllist","No RBL listed.","RBL to check: ","."); + + substdio_puts(subfdout,"\n"); + + while (d = readdir(dir)) { if (str_equal(d->d_name,".")) continue; if (str_equal(d->d_name,"..")) continue; @@ -296,7 +339,33 @@ if (str_equal(d->d_name,"timeoutremote")) continue; if (str_equal(d->d_name,"timeoutsmtpd")) continue; if (str_equal(d->d_name,"virtualdomains")) continue; - substdio_puts(subfdout,"\n"); + if (str_equal(d->d_name,"ldapserver")) continue; + if (str_equal(d->d_name,"ldapbasedn")) continue; + if (str_equal(d->d_name,"ldaplogin")) continue; + if (str_equal(d->d_name,"ldappassword")) continue; + if (str_equal(d->d_name,"ldaplocaldelivery")) continue; + if (str_equal(d->d_name,"ldaprebind")) continue; + if (str_equal(d->d_name,"ldapcluster")) continue; + if (str_equal(d->d_name,"ldapdefaultquota")) continue; + if (str_equal(d->d_name,"ldapdefaultdotmode")) continue; + if (str_equal(d->d_name,"ldapmessagestore")) continue; + if (str_equal(d->d_name,"ldapuid")) continue; + if (str_equal(d->d_name,"ldapgid")) continue; + if (str_equal(d->d_name,"custombouncetext")) continue; + if (str_equal(d->d_name,"quotawarning")) continue; + if (str_equal(d->d_name,"tarpitcount")) continue; + if (str_equal(d->d_name,"tarpitdelay")) continue; + if (str_equal(d->d_name,"badrcptto")) continue; + if (str_equal(d->d_name,"dirmaker")) continue; + if (str_equal(d->d_name,"ldapclusterhosts")) continue; + if (str_equal(d->d_name,"ldappasswdappend")) { + substdio_puts(subfdout,"ldappasswdappend: No longer used, please remove.\n"); + continue; + } + if (str_equal(d->d_name,"ldapusername")) { + substdio_puts(subfdout,"ldapusername: No longer used, please remove.\n"); + continue; + } substdio_puts(subfdout,d->d_name); substdio_puts(subfdout,": I have no idea what this file does.\n"); } diff -uN qmail-1.03/qmail-smtpd.c qmail-ldap/qmail-smtpd.c --- qmail-1.03/qmail-smtpd.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/qmail-smtpd.c Fri May 4 20:58:43 2001 @@ -2,6 +2,7 @@ #include "readwrite.h" #include "stralloc.h" #include "substdio.h" +#include "subfd.h" #include "alloc.h" #include "auto_qmail.h" #include "control.h" @@ -20,18 +21,62 @@ #include "now.h" #include "exit.h" #include "rcpthosts.h" +#ifndef TLS #include "timeoutread.h" #include "timeoutwrite.h" +#endif #include "commands.h" +#include "dns.h" +#ifdef TLS +#include +SSL *ssl = NULL; +stralloc clientcert = {0}; +#endif #define MAXHOPS 100 unsigned int databytes = 0; int timeout = 1200; +#ifdef TLS +int flagtimedout = 0; +void sigalrm() +{ + flagtimedout = 1; +} +int ssl_timeoutread(timeout,fd,buf,n) int timeout; int fd; char *buf; int n; +{ + int r; int saveerrno; + if (flagtimedout) { errno = error_timeout; return -1; } + alarm(timeout); + if (ssl) r = SSL_read(ssl,buf,n); else r = read(fd,buf,n); + saveerrno = errno; + alarm(0); + if (flagtimedout) { errno = error_timeout; return -1; } + errno = saveerrno; + return r; +} +int ssl_timeoutwrite(timeout,fd,buf,n) int timeout; int fd; char *buf; int n; +{ + int r; int saveerrno; + if (flagtimedout) { errno = error_timeout; return -1; } + alarm(timeout); + if (ssl) r = SSL_write(ssl,buf,n); else r = write(fd,buf,n); + saveerrno = errno; + alarm(0); + if (flagtimedout) { errno = error_timeout; return -1; } + errno = saveerrno; + return r; +} +#endif + int safewrite(fd,buf,len) int fd; char *buf; int len; { int r; +#ifdef TLS + r = ssl_timeoutwrite(timeout,fd,buf,len); +#else r = timeoutwrite(timeout,fd,buf,len); +#endif if (r <= 0) _exit(1); return r; } @@ -42,25 +87,78 @@ void flush() { substdio_flush(&ssout); } void out(s) char *s; { substdio_puts(&ssout,s); } -void die_read() { _exit(1); } -void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); } -void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); } -void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); } -void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); } -void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); } +/* level 0 = no logging + 1 = fatal errors + 2 = connection setup and warnings + 3 = verbose */ + +int loglevel = 0; + +void logpid(level) int level; +{ + char pidstring[FMT_ULONG]; + if (level > loglevel) return; + substdio_puts(subfderr,"qmail-smtpd "); + pidstring[fmt_ulong(pidstring,(unsigned long) getpid())] = 0; + substdio_puts(subfderr,pidstring); + substdio_puts(subfderr,": "); +} -void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); } +void logline(level,string) int level; char *string; +{ + if (level > loglevel) return; + logpid(level); + substdio_puts(subfderr,string); + substdio_puts(subfderr,"\n"); + substdio_flush(subfderr); +} + +void logstring(level,string) int level; char *string; +{ + if (level > loglevel) return; + substdio_puts(subfderr,string); + substdio_puts(subfderr," "); +} + +void logflush(level) int level; +{ + if (level > loglevel) return; + substdio_puts(subfderr,"\n"); + substdio_flush(subfderr); +} + +void die_read() { logline(1,"read error, connection closed"); _exit(1); } +void die_alarm() { out("451 timeout (#4.4.2)\r\n"); logline(1,"connection timed out, closing connection"); flush(); _exit(1); } +void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); logline(1,"out of memory, closing connection"); flush(); _exit(1); } +void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); logline(1,"unable to real controls, closing connection"); flush(); _exit(1); } +void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); logline(1,"unable to figure out my IP address, closing connection"); flush(); _exit(1); } +void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); logline(1,"stray new line detected, closing connection"); flush(); _exit(1); } + +void err_bmf() { out("553 syntax error, please forward to your postmaster (#5.7.1)\r\n"); } +void err_hard(arg) char *arg; { out("554 syntax error, "); out(arg); out(" (#5.5.4)\r\n"); } +void err_rbl(arg) char *arg; { out("553 sorry, your mailserver is listed in "); out(arg); out(", mail from your location is not accepted here (#5.7.1)\r\n"); } +void err_maxrcpt() { out("553 sorry, too many recipients (#5.7.1)\r\n"); } void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); } -void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); } +#ifdef TLS +void err_nogwcert() { out("553 no valid cert for gatewaying (#5.7.1)\r\n"); } +#endif +void err_unimpl(arg) char *arg; { out("502 unimplemented (#5.5.1)\r\n"); logpid(3); logstring(3,"unrecognized command ="); logstring(3,arg); logflush(3); } +void err_size() { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); logline(3,"message denied because of 'SMTP SIZE' argument"); } void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); } -void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); } -void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); } -void err_noop() { out("250 ok\r\n"); } -void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); } +void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); logline(3,"'mail from' first"); } +void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); logline(3,"'rcpt to' first"); } +void err_noop() { out("250 ok\r\n"); logline(3,"'noop'"); } +void err_vrfy(arg) char *arg; { out("252 send some mail, i'll try my best\r\n"); logpid(3); logstring(3,"vrfy for ="); logstring(3,arg); logflush(3); } void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); } +void err_dns() { out("451 DNS temporary failure, try again later (#4.3.0)\r\n"); } +void err_spam() { out("553 sorry, mail from your location is not accepted here (#5.7.1)\r\n"); } +void err_badrcptto() { out("553 sorry, mail to that recipient is not accepted on this system (#5.7.1)\r\n"); } stralloc greeting = {0}; +int brtok = 0; +stralloc brt = {0}; +struct constmap mapbadrcptto; void smtp_greet(code) char *code; { @@ -70,10 +168,14 @@ void smtp_help() { out("214 qmail home page: http://pobox.com/~djb/qmail.html\r\n"); + out("214 qmail-ldap patch home page: http://www.nrg4u.com\r\n"); + logline(3,"help requested"); } void smtp_quit() { - smtp_greet("221 "); out("\r\n"); flush(); _exit(0); + smtp_greet("221 "); out("\r\n"); + logline(3,"quit, closing connection"); + flush(); _exit(0); } char *remoteip; @@ -81,6 +183,11 @@ char *remoteinfo; char *local; char *relayclient; +char *relayok; +char *denymail; +char *rblenabled; +char *rblonlyheader; +int spamflag = 0; stralloc helohost = {0}; char *fakehelo; /* pointer into helohost, or 0 */ @@ -96,27 +203,76 @@ int bmfok = 0; stralloc bmf = {0}; struct constmap mapbmf; +int rmfok = 0; +stralloc rmf = {0}; +struct constmap maprmf; +int rblok = 0; +int rblohok = 0; +stralloc rbl = {0}; +stralloc rblmessage = {0}; +int tarpitcount = 0; +int tarpitdelay = 5; +int maxrcptcount = 0; void setup() { - char *x; - unsigned long u; - + char *x, *l; + unsigned long u, v; + + l = env_get("LOGLEVEL"); + if (l) { scan_ulong(l,&v); loglevel = v; }; + if (control_init() == -1) die_control(); if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1) die_control(); liphostok = control_rldef(&liphost,"control/localiphost",1,(char *) 0); if (liphostok == -1) die_control(); + if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control(); if (timeout <= 0) timeout = 1; + if (control_readint(&tarpitcount,"control/tarpitcount") == -1) die_control(); + if (tarpitcount < 0) tarpitcount = 0; + x = env_get("TARPITCOUNT"); + if (x) { scan_ulong(x,&u); tarpitcount = u; }; + if (control_readint(&tarpitdelay,"control/tarpitdelay") == -1) die_control(); + if (tarpitdelay < 0) tarpitdelay = 0; + x = env_get("TARPITDELAY"); + if (x) { scan_ulong(x,&u); tarpitdelay = u; }; + + if (control_readint(&maxrcptcount,"control/maxrcptcount") == -1) die_control(); + if (maxrcptcount < 0) maxrcptcount = 0; + x = env_get("MAXRCPTCOUNT"); + if (x) { scan_ulong(x,&u); maxrcptcount = u; }; + if (rcpthosts_init() == -1) die_control(); bmfok = control_readfile(&bmf,"control/badmailfrom",0); if (bmfok == -1) die_control(); if (bmfok) if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem(); - + + rmfok = control_readfile(&rmf,"control/relaymailfrom",0); + if (rmfok == -1) die_control(); + if (rmfok) + if (!constmap_init(&maprmf,rmf.s,rmf.len,0)) die_nomem(); + + brtok = control_readfile(&brt,"control/badrcptto",0); + if (brtok == -1) die_control(); + if (brtok) + if (!constmap_init(&mapbadrcptto,brt.s,brt.len,0)) die_nomem(); + + rblok = control_readfile(&rbl,"control/rbllist",0); + if (rblok == -1) die_control(); + if (rblok) { + rblenabled = env_get("RBL"); + + rblohok = control_readint(&rblonlyheader,"control/rblonlyheader",0); + if (rblohok == -1) die_control(); + rblonlyheader = env_get("RBLONLYHEADER"); + if (rblonlyheader) logline(2,"Log RBL match only in header, do not reject message"); + } + if (control_readint(&databytes,"control/databytes") == -1) die_control(); x = env_get("DATABYTES"); if (x) { scan_ulong(x,&u); databytes = u; } @@ -124,13 +280,23 @@ remoteip = env_get("TCPREMOTEIP"); if (!remoteip) remoteip = "unknown"; - local = env_get("TCPLOCALHOST"); - if (!local) local = env_get("TCPLOCALIP"); - if (!local) local = "unknown"; + logpid(2); logstring(2,"connection from"); logstring(2,remoteip); remotehost = env_get("TCPREMOTEHOST"); if (!remotehost) remotehost = "unknown"; + logstring(2,"("); logstring(2,remotehost); remoteinfo = env_get("TCPREMOTEINFO"); - relayclient = env_get("RELAYCLIENT"); + if (remoteinfo) { logstring(2,","); logstring(2,remoteinfo); } + logstring(2,") to"); + + local = env_get("TCPLOCALHOST"); + if (!local) local = env_get("TCPLOCALIP"); + if (!local) local = "unknown"; + logstring(2,local); + + relayok = relayclient = env_get("RELAYCLIENT"); + if (relayclient) { logstring(2,", relayclient set"); } + denymail = env_get("DENYMAIL"); + logflush(2); dohelo(remotehost); } @@ -197,6 +363,162 @@ return 1; } +int badmxcheck(dom) char *dom; +{ + ipalloc checkip = {0}; + int ret = 0; + stralloc checkhost = {0}; + + if (!*dom) return (DNS_HARD); + if (!stralloc_copys(&checkhost,dom)) return (DNS_SOFT); + + switch (dns_mxip(&checkip,&checkhost,1)) + { + case DNS_MEM: + case DNS_SOFT: + ret=DNS_SOFT; + break; + + case DNS_HARD: + ret=DNS_HARD; + break; + + case 1: + if (checkip.len <= 0) ret=DNS_HARD; + break; + + default: + ret=0; + break; + } + return (ret); +} + +/* RBL */ + +stralloc ip_reverse; + +void rbl_init() +{ + unsigned int i; + unsigned int j; + char *ip_env; + + ip_env = remoteip; + if (!ip_env) ip_env = ""; + + if (!stralloc_copys(&ip_reverse,"")) die_nomem(); + + i = str_len(ip_env); + while (i) { + for (j = i;j > 0;--j) if (ip_env[j - 1] == '.') break; + if (!stralloc_catb(&ip_reverse,ip_env + j,i - j)) die_nomem(); + if (!stralloc_cats(&ip_reverse,".")) die_nomem(); + if (!j) break; + i = j - 1; + } +} + +stralloc rbl_tmp; + +int rbl_lookup(char *base) +{ + ipalloc rblsa = {0}; + + if (!*base) return 2; + + if (!stralloc_copys(&rbl_tmp,"")) die_nomem(); + + if (!stralloc_copy(&rbl_tmp,&ip_reverse)) die_nomem(); + if (!stralloc_cats(&rbl_tmp,base)) die_nomem(); + + switch (dns_ip(&rblsa,&rbl_tmp)) + { + case DNS_MEM: + case DNS_SOFT: + return 2; /* soft error */ + break; + + case DNS_HARD: + return 0; /* found no match */ + break; + + default: + return 1; /* found match */ + break; + } + return 1; /* should never get here */ +} + +int rblcheck() +{ + int r = 1; + char *p; + + rbl_init(); + + p = &rbl.s[0]; + while(p < &rbl.s[0]+rbl.len) + { + logpid(2); logstring(2,"RBL check with '"); logstring(2,p); logstring(2,"':"); + r = rbl_lookup(p); + if (r == 2) + { + logstring(2,"temporary DNS error"); logflush(2); + return 2; + } + if (r == 1) + { + logstring(2,"found match, sender is blocked"); logflush(2); + stralloc_copys(&rblmessage,p); + stralloc_0(&rblmessage); + return 1; + } + /* continue */ + logstring(2,"no match found, continue"); logflush(2); + p = p+strlen(p); + p++; + } + return r; +} + +/* RBL */ + +int sizelimit(arg) +char *arg; +{ + int i; + long r; + unsigned long sizebytes = 0; + + i = str_chr(arg,'<'); + if (arg[i]) + arg += i + 1; + else { + arg += str_chr(arg,':'); + if (*arg == ':') ++arg; + while (*arg == ' ') ++arg; + } + + arg += str_chr(arg,' '); + if (*arg == ' ') while (*arg == ' ') ++arg; + else return 1; + + i = str_chr(arg,'='); + arg[i] = 0; + if (case_equals(arg,"SIZE")) { + arg += i; + while (*++arg && *arg > 47 && *arg < 58) { + sizebytes *= 10; + sizebytes += *arg - 48; + } + r = databytes - sizebytes; + if (r < 0) return 0; + } + return 1; +} + + int bmfcheck() { int j; @@ -204,63 +526,345 @@ if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1; j = byte_rchr(addr.s,addr.len,'@'); if (j < addr.len) + { if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1; + if (constmap(&mapbmf,addr.s, j + 1)) return 1; + } + return 0; +} + +int seenmail = 0; +int flagbarf; /* defined if seenmail */ +stralloc mailfrom = {0}; +stralloc rcptto = {0}; +int rcptcount; + +int rmfcheck() +{ + int j; + if (!rmfok) return 0; + if (constmap(&maprmf,addr.s,addr.len - 1)) return 1; + j = byte_rchr(addr.s,addr.len,'@'); + if (j < addr.len) + if (constmap(&maprmf,addr.s + j,addr.len - j - 1)) return 1; return 0; } int addrallowed() { - int r; + int r,j; + j = byte_rchr(addr.s,addr.len,'@'); + if (brtok) + if (constmap(&mapbadrcptto, addr.s, addr.len - 1) || + constmap(&mapbadrcptto, addr.s + j, addr.len - j - 1)) + { logpid(2); logstring(2,addr.s); logflush(2); return 2; } r = rcpthosts(addr.s,str_len(addr.s)); if (r == -1) die_control(); return r; } - -int seenmail = 0; -int flagbarf; /* defined if seenmail */ -stralloc mailfrom = {0}; -stralloc rcptto = {0}; - void smtp_helo(arg) char *arg; { smtp_greet("250 "); out("\r\n"); seenmail = 0; dohelo(arg); + logpid(3); logstring(3,"remote helo ="); logstring(3,arg); logflush(3); } +char smtpsize[FMT_ULONG]; void smtp_ehlo(arg) char *arg; { - smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); + smtp_greet("250-"); + smtpsize[fmt_ulong(smtpsize,(unsigned long) databytes)] = 0; +#ifdef TLS + if (ssl) { + out("\r\n250-PIPELINING\r\n"); + out("250-SIZE "); out(smtpsize); out("\r\n"); + out("250 8BITMIME\r\n"); + } + else { +#endif + out("\r\n250-PIPELINING\r\n"); +#ifdef TLS + out("250-STARTTLS\r\n"); +#endif + out("250-SIZE "); out(smtpsize); out("\r\n"); + out("250 8BITMIME\r\n"); +#ifdef TLS + } +#endif seenmail = 0; dohelo(arg); + logpid(3); logstring(3,"remote ehlo ="); logstring(3,arg); logflush(3); + logpid(3); logstring(3,"max msg size ="); logstring(3,smtpsize); logflush(3); } void smtp_rset() { seenmail = 0; out("250 flushed\r\n"); + logline(3,"remote rset"); } + +struct qmail qqt; + void smtp_mail(arg) char *arg; { - if (!addrparse(arg)) { err_syntax(); return; } + int i,j; + char *why; + logpid(3); logstring(3,"remote sent 'mail from' ="); logstring(3,arg); logflush(3); + if (!addrparse(arg)) + { + err_syntax(); + logpid(2); logstring(2,"RFC821 syntax error in mail from ="); logstring(2,arg); logflush(2); + return; + } + if (databytes && !sizelimit(arg)) { err_size(); return; } + logpid(3); logstring(3,"mail from ="); logstring(3,addr.s); logflush(3); flagbarf = bmfcheck(); + if (flagbarf) + { + err_bmf(); + logpid(2); logstring(2,"bad mail from ="); logstring(2,arg); logflush(2); + return; + } + + /* Allow relaying based on envelope sender address */ + if (!relayok) + { + if (rmfcheck()) + { + relayclient = ""; + logline(2,"relaying allowed for envelope sender"); + } + else relayclient = 0; + } + + /* Check RBL only if relayclient is not set */ + if (rblenabled && !relayclient) + { + logline(3,"RBL checking enabled, going through list of RBLs"); + switch(rblcheck()) + { + case 2: /* soft error lookup */ + err_dns(); + return; + case 1: /* host is listed in RBL */ + if (rblonlyheader) + rblheader(qqt,remoteip,rblmessage.s); + else { + err_rbl(rblmessage.s); + return; + } + default: /* ok, go ahead */ + logline(3,"RBL checking completed without match or listed in header"); + } + } + + /* DENYMAIL is set for this session from this client, so heavy checking + * of mailfrom is done. If one of the following is set: + * SPAM -> refuse all mail + * NOBOUNCE -> refuse null mailfrom + * DNSCHECK -> validate Mailfrom domain + */ + if (denymail) + { + if (!str_diff("SPAM", denymail)) + { + flagbarf=1; + spamflag=1; + why = "refused to accept SPAM"; + } + else + { + if (!addr.s[0] || !str_diff("#@[]", addr.s)) /* if (!addr.s[0]) */ + { + if (!str_diff("NOBOUNCE", denymail)) + { + why = "refused to accept RFC821 bounce from remote"; + flagbarf=1; + } + } + else + { + /* Invalid Mailfrom */ + if ((i=byte_rchr(addr.s,addr.len,'@')) >= addr.len) + { + why = "refused 'mail from' without @"; + flagbarf=1; + } + else + { + /* money!@domain.TLD */ + if (addr.s[i-1] == '!') + { + why = "refused 'mail from' with !@"; + flagbarf=1; + } + + /* check syntax, visual */ + if ((j = byte_rchr(addr.s+i, addr.len-i, '.')) >= addr.len-i) + { + why = "refused 'mail from' without . in domain"; + flagbarf=1; /* curious no '.' in domain.TLD */ + } + + j = addr.len-(i+1+j+1); + if (j < 2 || j > 6) + { + /* XXX: This needs adjustment when new TLD's are constituded. + * OK, now after the candidates are nominated we know new TLD's + * may contain up to six characters. + */ + why = "refused 'mail from' without country or top level domain"; + flagbarf=1; + } + + if (!flagbarf) + { + if (!str_diff("DNSCHECK", denymail)) + { + /* check syntax, via DNS */ + switch (badmxcheck(&addr.s[i+1])) + { + case 0: + break; /*valid*/ + case DNS_SOFT: + flagbarf=2; /*fail tmp*/ + why = "refused 'mail from' because return MX lookup failed temporarly"; + break; + case DNS_HARD: + default: + flagbarf=1; + why = "refused 'mail from' because return MX does not exist"; + break; + } + } /* DNSCHECK */ + } /* if !flagbarf */ + } /* without @ */ + } /* bounce */ + } /* SPAM */ + + if (flagbarf) + { + logpid(2); logstring(2,why); logstring(2,"for ="); logstring(2,addr.s); logflush(2); + if (flagbarf==2) + err_dns(); + else if (spamflag) + err_spam(); + else + err_hard(why); + return; + } + } /* denymail */ + seenmail = 1; if (!stralloc_copys(&rcptto,"")) die_nomem(); if (!stralloc_copys(&mailfrom,addr.s)) die_nomem(); if (!stralloc_0(&mailfrom)) die_nomem(); + rcptcount = 0; out("250 ok\r\n"); } + void smtp_rcpt(arg) char *arg; { if (!seenmail) { err_wantmail(); return; } - if (!addrparse(arg)) { err_syntax(); return; } - if (flagbarf) { err_bmf(); return; } + logpid(3); logstring(3,"remote sent 'rcpt to' ="); logstring(3,arg); logflush(3); + if (!addrparse(arg)) + { + err_syntax(); + logpid(2); logstring(2,"syntax error in 'rcpt to' ="); logstring(2,arg); logflush(2); + return; + } + logpid(3); logstring(3,"rcpt to ="); logstring(3,addr.s); logflush(3); if (relayclient) { --addr.len; if (!stralloc_cats(&addr,relayclient)) die_nomem(); if (!stralloc_0(&addr)) die_nomem(); } - else - if (!addrallowed()) { err_nogateway(); return; } + else { + if (addrallowed()==2) + { + err_badrcptto(); + logpid(2); logstring(2,"'rcpt to' not allowed ="); logstring(2,arg); logflush(2); + return; + } +#ifndef TLS + if (!addrallowed()) + { + err_nogateway(); + logpid(2); logstring(2,"no mail relay for 'rcpt to' ="); logstring(2,arg); logflush(2); + return; + } +#else + if (!addrallowed()) + { + if (ssl) + { STACK_OF(X509_NAME) *sk; + X509 *peercert; + stralloc tlsclients = {0}; + struct constmap maptlsclients; + + SSL_set_verify(ssl, + SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, + NULL); + if ((sk = SSL_load_client_CA_file("control/clientca.pem")) == NULL) + { + err_nogateway(); + logpid(2); logstring(2,"unable to read ~control/clientca.pem, no mail relay for 'rcpt to' ="); logstring(2,arg); logflush(2); + return; + } + SSL_set_client_CA_list(ssl, sk); + if((control_readfile(&tlsclients,"control/tlsclients",0) != 1) || + !constmap_init(&maptlsclients,tlsclients.s,tlsclients.len,0)) + { + err_nogateway(); + logpid(2); logstring(2,"unable to read or process ~control/tlsclients, no mail relay for 'rcpt to' ="); logstring(2,arg); logflush(2); + return; + } + + SSL_renegotiate(ssl); + SSL_do_handshake(ssl); + ssl->state = SSL_ST_ACCEPT; + SSL_do_handshake(ssl); + if ((SSL_get_verify_result(ssl) == X509_V_OK) && + (peercert = SSL_get_peer_certificate(ssl))) + { + if (!constmap(&maptlsclients,clientcert.s,clientcert.len)) + { + err_nogwcert(); + logpid(2); logstring(2,"client cert no found, no mail relay for 'rcpt to' ="); logstring(2,arg); logflush(2); + return; + } + relayclient = 0; + } + else + { + err_nogwcert(); + logpid(2); logstring(2,"either not X509 or no certificate presented, no mail relay for 'rcpt to' ="); logstring(2,arg); logflush(2); + return; + } + } + else + { + err_nogateway(); + logpid(2); logstring(2,"no mail relay for 'rcpt to' ="); logstring(2,arg); logflush(2); + return; + } + } +#endif + + } + ++rcptcount; + if (maxrcptcount && rcptcount > maxrcptcount) + { + err_maxrcpt(); + logline(1,"message denied because of more 'RCPT TO' than allowed by MAXRCPTCOUNT"); + return; + } if (!stralloc_cats(&rcptto,"T")) die_nomem(); if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); if (!stralloc_0(&rcptto)) die_nomem(); + if (tarpitcount && rcptcount >= tarpitcount) + { + logline(2,"tarpitting"); + while (sleep(tarpitdelay)); + } out("250 ok\r\n"); } @@ -269,7 +873,11 @@ { int r; flush(); +#ifdef TLS + r = ssl_timeoutread(timeout,fd,buf,len); +#else r = timeoutread(timeout,fd,buf,len); +#endif if (r == -1) if (errno == error_timeout) die_alarm(); if (r <= 0) die_read(); return r; @@ -278,8 +886,8 @@ char ssinbuf[1024]; substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); -struct qmail qqt; unsigned int bytestooverflow = 0; +unsigned int bytesreceived = 0; void put(ch) char *ch; @@ -288,6 +896,7 @@ if (!--bytestooverflow) qmail_fail(&qqt); qmail_put(&qqt,ch,1); + ++bytesreceived; } void blast(hops) @@ -359,41 +968,142 @@ out("250 ok "); accept_buf[fmt_ulong(accept_buf,(unsigned long) when)] = 0; out(accept_buf); + logpid(2); logstring(2,"message queued ="); logstring(2,accept_buf); out(" qp "); accept_buf[fmt_ulong(accept_buf,qp)] = 0; out(accept_buf); out("\r\n"); + logstring(2,"qp"); logstring(2,accept_buf); logflush(2); } +char receivedbytes[FMT_ULONG]; void smtp_data() { int hops; unsigned long qp; char *qqx; +/* char buf[FMT_ULONG]; */ +#ifdef TLS + stralloc protocolinfo = {0}; +#endif + logline(3,"smtp data"); if (!seenmail) { err_wantmail(); return; } if (!rcptto.len) { err_wantrcpt(); return; } seenmail = 0; if (databytes) bytestooverflow = databytes + 1; - if (qmail_open(&qqt) == -1) { err_qqt(); return; } + if (qmail_open(&qqt) == -1) { err_qqt(); logline(1,"failed to start qmail-queue"); return; } qp = qmail_qp(&qqt); - out("354 go ahead\r\n"); - - received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo); + out("354 go ahead\r\n"); logline(3,"go ahead"); + +#ifdef TLS + if(ssl){ + if (!stralloc_copys(&protocolinfo, SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)))) die_nomem(); + if (!stralloc_catb(&protocolinfo, " encrypted SMTP", 15)) die_nomem(); + if (clientcert.len){ + if (!stralloc_catb(&protocolinfo," cert ", 6)) die_nomem(); + if (!stralloc_catb(&protocolinfo,clientcert.s, clientcert.len)) die_nomem(); + } + if (!stralloc_0(&protocolinfo)) die_nomem(); + } else if (!stralloc_copyb(&protocolinfo,"SMTP",5)) die_nomem(); + received(&qqt,protocolinfo.s,local,remoteip,remotehost,remoteinfo,fakehelo,mailfrom.s,&rcptto.s[1]); +#else + received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo,mailfrom.s,&rcptto.s[1]); +#endif blast(&hops); + + receivedbytes[fmt_ulong(receivedbytes,(unsigned long) bytesreceived)] = 0; + logpid(3); logstring(3,"data bytes received ="); logstring(3,receivedbytes); logflush(3); + hops = (hops >= MAXHOPS); - if (hops) qmail_fail(&qqt); + if (hops) { logline(2,"hop count exceeded"); qmail_fail(&qqt); } qmail_from(&qqt,mailfrom.s); qmail_put(&qqt,rcptto.s,rcptto.len); qqx = qmail_close(&qqt); if (!*qqx) { acceptmessage(qp); return; } if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; } - if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; } - if (*qqx == 'D') out("554 "); else out("451 "); + if (databytes) if (!bytestooverflow) + { + out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); + logline(2,"datasize limit exceeded"); + return; + } + logpid(1); + if (*qqx == 'D') { out("554 "); logstring(1,"message not accepted because ="); } + else { out("451 "); logstring(1,"message not accepted because ="); } out(qqx + 1); + logstring(1,qqx+1); logflush(1); out("\r\n"); } +#ifdef TLS +RSA *tmp_rsa_cb(ssl,export,keylength) SSL *ssl; int export; int keylength; +{ + RSA* rsa; + BIO* in; + + if (!export || keylength == 512) + if (in=BIO_new(BIO_s_file_internal())) + if (BIO_read_filename(in,"control/rsa512.pem") > 0) + if (rsa=PEM_read_bio_RSAPrivateKey(in,NULL,NULL,NULL)) + return rsa; + return (RSA_generate_key(export?keylength:512,RSA_F4,NULL,NULL)); +} + +void smtp_tls(arg) char *arg; +{ + SSL_CTX *ctx; + + if (*arg) + { + out("501 Syntax error (no parameters allowed) (#5.5.4)\r\n"); + logstring(1,"aborting TLS negotiations, no parameters to starttls allowed"); + return; + } + + SSLeay_add_ssl_algorithms(); + if(!(ctx=SSL_CTX_new(SSLv23_server_method()))) + { + out("454 TLS not available: unable to initialize ctx (#4.3.0)\r\n"); + logstring(1,"aborting TLS negotiations, unable to initialize local SSL context"); + return; + } + if(!SSL_CTX_use_RSAPrivateKey_file(ctx, "control/cert.pem", SSL_FILETYPE_PEM)) + { + out("454 TLS not available: missing RSA private key (#4.3.0)\r\n"); + logstring(1,"aborting TLS negotiations, RSA private key invalid or unable to read ~control/cert.pem"); + return; + } + if(!SSL_CTX_use_certificate_file(ctx, "control/cert.pem", SSL_FILETYPE_PEM)) + { + out("454 TLS not available: missing certificate (#4.3.0)\r\n"); + logstring(1,"aborting TLS negotiations, local cert invalid or unable to read ~control/cert.pem"); + return; + } + SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb); + SSL_CTX_load_verify_locations(ctx, "control/clientca.pem",NULL); + + out("220 ready for tls\r\n"); flush(); + + if(!(ssl=SSL_new(ctx))) + { + logstring(2,"aborting TLS connection, unable to set up SSL session"); + die_read(); + } + SSL_set_fd(ssl,0); + if(SSL_accept(ssl)<=0) + { + logstring(2,"aborting TLS connection, unable to finish SSL accept"); + die_read(); + } + substdio_fdbuf(&ssout,SSL_write,ssl,ssoutbuf,sizeof(ssoutbuf)); + + remotehost = env_get("TCPREMOTEHOST"); + if (!remotehost) remotehost = "unknown"; + dohelo(remotehost); +} +#endif + struct commands smtpcommands[] = { { "rcpt", smtp_rcpt, 0 } , { "mail", smtp_mail, 0 } @@ -403,6 +1113,9 @@ , { "ehlo", smtp_ehlo, flush } , { "rset", smtp_rset, 0 } , { "help", smtp_help, flush } +#ifdef TLS +, { "starttls", smtp_tls, flush } +#endif , { "noop", err_noop, flush } , { "vrfy", err_vrfy, flush } , { 0, err_unimpl, flush } @@ -410,6 +1123,9 @@ void main() { +#ifdef TLS + sig_alarmcatch(sigalrm); +#endif sig_pipeignore(); if (chdir(auto_qmail) == -1) die_control(); setup(); diff -uN qmail-1.03/qmail.schema qmail-ldap/qmail.schema --- qmail-1.03/qmail.schema Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qmail.schema Tue Apr 17 00:25:22 2001 @@ -0,0 +1,103 @@ +# +# qmail-ldap v3 directory schema +# +# The offical qmail-ldap OID assigned by IANA is 7914 +# +# Created by: David E. Storey +# Modified and included into qmail-ldap by Andre Oppermann +# +# I've gone through this schema and I think it is now correct but I'm +# not 100% certain. The next release will clear it up. +# +# This schema depends on: +# - core.schema +# - cosine.schema +# - nis.schema +# + +# Attribute Type Definitions + +attributetype ( 1.3.6.1.4.1.7914.1.2.1.1 NAME 'qmailUID' + DESC 'UID of the user on the mailsystem' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7914.1.2.1.2 NAME 'qmailGID' + DESC 'GID of the user on the mailsystem' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7914.1.2.1.3 NAME 'mailMessageStore' + DESC 'Path to the maildir/mbox on the mail system' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7914.1.2.1.4 NAME 'mailAlternateAddress' + DESC 'Secondary (alias) mailaddresses for the same user' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.7914.1.2.1.5 NAME 'mailQuota' + DESC 'The amount of space the user can use until all further messages get bounced.' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7914.1.2.1.6 NAME 'mailHost' + DESC 'On which qmail server the messagestore of this user is located.' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7914.1.2.1.7 NAME 'mailForwardingAddress' + DESC 'Address(es) to forward all incoming messages to.' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.7914.1.2.1.8 NAME 'deliveryProgramPath' + DESC 'Program to execute for all incoming mails.' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7914.1.2.1.9 NAME 'qmailDotMode' + DESC 'Interpretation of .qmail files: both, dotonly, ldaponly, ldapwithprog, none' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7914.1.2.1.10 NAME 'deliveryMode' + DESC 'multi field entries of: normal, forwardonly, nombox, localdelivery, reply, echo' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 ) + +attributetype ( 1.3.6.1.4.1.7914.1.2.1.11 NAME 'mailReplyText' + DESC 'A reply text for every incoming message' + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{4096} + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7914.1.2.1.12 NAME 'accountStatus' + DESC 'The status of a user account: active, nopop, disabled, deleted' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7914.1.2.1.14 NAME 'qmailAccountPurge' + DESC 'The earliest date when a mailMessageStore will be purged' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 + SINGLE-VALUE ) + +# Object Class Definitions + +objectclass ( 1.3.6.1.4.1.7914.1.2.2.1 NAME 'qmailUser' + DESC 'QMail-LDAP User' SUP top AUXILIARY + MUST ( mail $ uid ) + MAY ( mailMessageStore $ homeDirectory $ userPassword $ + mailAlternateAddress $ qmailUID $ qmailGID $ mailQuota $ + mailHost $ mailForwardingAddress $ deliveryProgramPath $ + qmailDotMode $ deliveryMode $ mailReplyText $ + accountStatus $ qmailAccountPurge ) ) + diff -uN qmail-1.03/qmailAccountPurge.sh qmail-ldap/qmailAccountPurge.sh --- qmail-1.03/qmailAccountPurge.sh Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qmailAccountPurge.sh Fri Apr 20 23:35:56 2001 @@ -0,0 +1,22 @@ +#!/bin/sh + +case "$1" in + +show) + + /usr/local/bin/ldapsearch \ + -u -F "=" \ + -h "`cat /var/qmail/control/ldapserver`" \ + -b "`cat /var/qmail/control/ldapbasedn`" \ + -S "mail" \ + "(&(accountStatus=deleted)(qmailAccountPurge=<`/var/qmail/bin/gettimeofday`))" \ + mail mailAlternateAddress uid mailMessageStore mailHost + + ;; + +purge) + + ;; + +esac + diff -uN qmail-1.03/received.c qmail-ldap/received.c --- qmail-1.03/received.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/received.c Thu Apr 26 17:18:53 2001 @@ -37,7 +37,8 @@ /* "Received: from relay1.uu.net (HELO uunet.uu.net) (7@192.48.96.5)\n" */ /* " by silverton.berkeley.edu with SMTP; 26 Sep 1995 04:46:54 -0000\n" */ -void received(qqt,protocol,local,remoteip,remotehost,remoteinfo,helo) +void +received(qqt,protocol,local,remoteip,remotehost,remoteinfo,helo,mailfrom,rcptto) struct qmail *qqt; char *protocol; char *local; @@ -45,6 +46,8 @@ char *remotehost; char *remoteinfo; char *helo; +char *mailfrom; +char *rcptto; { struct datetime dt; @@ -60,12 +63,36 @@ safeput(qqt,remoteinfo); qmail_puts(qqt,"@"); } + qmail_puts(qqt,"["); safeput(qqt,remoteip); - qmail_puts(qqt,")\n by "); + qmail_puts(qqt,"])"); + + qmail_puts(qqt," (envelope-sender <"); + if (mailfrom) safeput(qqt,mailfrom); + qmail_puts(qqt,">)\n by "); + safeput(qqt,local); - qmail_puts(qqt," with "); + qmail_puts(qqt," (qmail-ldap-1.03) with "); qmail_puts(qqt,protocol); - qmail_puts(qqt,"; "); + + qmail_puts(qqt,"\n for <"); + if (rcptto) safeput(qqt,rcptto); + qmail_puts(qqt,">; "); + datetime_tai(&dt,now()); qmail_put(qqt,buf,date822fmt(buf,&dt)); } + +void +rblheader(qqt,remoteip,rbl) +struct qmail *qqt; +char *remoteip; +char *rbl; +{ + qmail_puts(qqt,"X-RBL-Check: "); + if (*remoteip) safeput(qqt,remoteip); + qmail_puts(qqt," is listed by "); + if (*rbl) safeput(qqt,rbl); + qmail_puts(qqt,"\n"); +} + diff -uN qmail-1.03/received.h qmail-ldap/received.h --- qmail-1.03/received.h Mon Jun 15 12:53:16 1998 +++ qmail-ldap/received.h Fri Apr 20 22:14:25 2001 @@ -2,5 +2,6 @@ #define RECEIVED_H extern void received(); +extern void rblheader(); #endif diff -uN qmail-1.03/spawn.c qmail-ldap/spawn.c --- qmail-1.03/spawn.c Mon Jun 15 12:53:16 1998 +++ qmail-ldap/spawn.c Tue Sep 4 00:19:34 2001 @@ -28,6 +28,9 @@ int wstat; /* if !pid: status of child */ int fdout; /* pipe output, -1 if !pid; delays eof until after death */ stralloc output; +#ifdef DEBUG + stralloc log; +#endif } ; @@ -63,7 +66,7 @@ int flagreading = 1; char outbuf[1024]; substdio ssout; -int stage = 0; /* reading 0:delnum 1:messid 2:sender 3:recip */ +int stage = 0; /* reading 0:delnum 1:delnum2 2:messid 3:sender 4:recip */ int flagabort = 0; /* if 1, everything except delnum is garbage */ int delnum; stralloc messid = {0}; @@ -73,6 +76,7 @@ void err(s) char *s; { char ch; ch = delnum; substdio_put(&ssout,&ch,1); + ch = delnum >> 8; substdio_put(&ssout,&ch,1); substdio_puts(&ssout,s); substdio_putflush(&ssout,"",1); } @@ -155,16 +159,19 @@ { case 0: delnum = (unsigned int) (unsigned char) ch; - messid.len = 0; stage = 1; break; + stage = 1; break; case 1: + delnum += (unsigned int) ((unsigned int) ch) << 8; + messid.len = 0; stage = 2; break; + case 2: if (!stralloc_append(&messid,&ch)) flagabort = 1; if (ch) break; - sender.len = 0; stage = 2; break; - case 2: + sender.len = 0; stage = 3; break; + case 3: if (!stralloc_append(&sender,&ch)) flagabort = 1; if (ch) break; - recip.len = 0; stage = 3; break; - case 3: + recip.len = 0; stage = 4; break; + case 4: if (!stralloc_append(&recip,&ch)) flagabort = 1; if (ch) break; docmd(); @@ -201,7 +208,8 @@ initialize(argc,argv); - ch = auto_spawn; substdio_putflush(&ssout,&ch,1); + ch = auto_spawn; substdio_put(&ssout,&ch,1); + ch = auto_spawn >> 8; substdio_putflush(&ssout,&ch,1); for (i = 0;i < auto_spawn;++i) { d[i].used = 0; d[i].output.s = 0; } @@ -236,13 +244,78 @@ continue; /* read error on a readable pipe? be serious */ if (r == 0) { - ch = i; substdio_put(&ssout,&ch,1); + char ch; ch = i; substdio_put(&ssout,&ch,1); + ch = i >> 8; substdio_put(&ssout,&ch,1); report(&ssout,d[i].wstat,d[i].output.s,d[i].output.len); substdio_put(&ssout,"",1); substdio_flush(&ssout); close(d[i].fdin); d[i].used = 0; continue; } +#ifdef DEBUG +# define IS_LOG(x) ( d[(x)].used & 0x8 ) +# define LOGON(x) ( d[(x)].used |= 0x8 ) +# define LOGOFF(x) ( d[(x)].used = 1 ) + { + int j; + int b; + int t; + for ( j=0, b=0; j 100) + if (d[i].log.len > truncreport) + { + char *truncmess = "\nError report too long, sorry.\n"; + d[i].log.len = truncreport - str_len(truncmess) - 3; + stralloc_cats(&d[i].log,truncmess); + } + ch = i; substdio_put(&ssout,&ch,1); + ch = i >> 8; substdio_put(&ssout,&ch,1); + ch = 'L'; substdio_put(&ssout,&ch,1); + for (t = 0;t < d[i].log.len; ++t) if (!d[i].log.s[t]) break; + substdio_put(&ssout,d[i].log.s,t); + substdio_put(&ssout,"",1); + substdio_flush(&ssout); + d[i].log.len = 0; + } + } + if (b == r) continue; + if ( IS_LOG(i) ) + { + while (!stralloc_readyplus(&d[i].log,r-b)) sleep(10); /*XXX*/ + byte_copy(d[i].log.s + d[i].log.len,r-b,inbuf+b); + d[i].log.len += r-b; + } + else + { + while (!stralloc_readyplus(&d[i].output,r-b)) sleep(10); /*XXX*/ + byte_copy(d[i].output.s + d[i].output.len,r-b,inbuf+b); + d[i].output.len += r-b; + if (truncreport > 100) + if (d[i].output.len > truncreport) + { + char *truncmess = "\nError report too long, sorry.\n"; + d[i].output.len = truncreport - str_len(truncmess) - 3; + stralloc_cats(&d[i].output,truncmess); + } + } + } +#else while (!stralloc_readyplus(&d[i].output,r)) sleep(10); /*XXX*/ byte_copy(d[i].output.s + d[i].output.len,r,inbuf); d[i].output.len += r; @@ -253,6 +326,7 @@ d[i].output.len = truncreport - str_len(truncmess) - 3; stralloc_cats(&d[i].output,truncmess); } +#endif } } }