diff -u -N qmail-1.03-orig/ANTISPAM test/ANTISPAM --- qmail-1.03-orig/ANTISPAM Thu Jan 1 01:00:00 1970 +++ test/ANTISPAM Thu Mar 1 23:58:54 2001 @@ -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 -u -N qmail-1.03-orig/FILES test/FILES --- qmail-1.03-orig/FILES Mon Jun 15 12:53:16 1998 +++ test/FILES Thu Mar 1 23:58:55 2001 @@ -431,3 +431,46 @@ tcp-environ.5 constmap.h constmap.c +QLDAPINSTALL +base64.c +base64.h +check.c +check.h +checkpassword.c +compatibility.h +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 diff -u -N qmail-1.03-orig/FILES.orig test/FILES.orig --- qmail-1.03-orig/FILES.orig Thu Jan 1 01:00:00 1970 +++ test/FILES.orig Thu Mar 1 23:58:55 2001 @@ -0,0 +1,433 @@ +BLURB +BLURB2 +BLURB3 +BLURB4 +README +FAQ +INSTALL +INSTALL.alias +INSTALL.ctl +INSTALL.ids +INSTALL.maildir +INSTALL.mbox +INSTALL.vsm +REMOVE.sendmail +REMOVE.binmail +TEST.deliver +TEST.receive +UPGRADE +THOUGHTS +TODO +THANKS +CHANGES +SECURITY +INTERNALS +SENDMAIL +PIC.local2alias +PIC.local2ext +PIC.local2local +PIC.local2rem +PIC.local2virt +PIC.nullclient +PIC.relaybad +PIC.relaygood +PIC.rem2local +FILES +VERSION +SYSDEPS +TARGETS +Makefile +BIN.README +BIN.Makefile +idedit.c +conf-break +auto_break.h +conf-spawn +auto_spawn.h +chkspawn.c +conf-split +auto_split.h +conf-patrn +auto_patrn.h +conf-users +conf-groups +auto_uids.h +auto_usera.h +extra.h +addresses.5 +except.1 +bouncesaying.1 +condredirect.1 +dot-qmail.9 +envelopes.5 +forgeries.7 +forward.1 +maildir2mbox.1 +maildirmake.1 +maildirwatch.1 +mailsubj.1 +mbox.5 +preline.1 +qbiff.1 +qmail-clean.8 +qmail-command.8 +qmail-control.9 +qmail-getpw.9 +qmail-header.5 +qmail-inject.8 +qmail-limits.9 +qmail-local.8 +qmail-log.5 +qmail-lspawn.8 +qmail-newmrh.9 +qmail-newu.9 +qmail-pop3d.8 +qmail-popup.8 +qmail-pw2u.9 +qmail-qmqpc.8 +qmail-qmqpd.8 +qmail-qmtpd.8 +qmail-qread.8 +qmail-qstat.8 +qmail-queue.8 +qmail-remote.8 +qmail-rspawn.8 +qmail-send.9 +qmail-showctl.8 +qmail-smtpd.8 +qmail-start.9 +qmail-tcpok.8 +qmail-tcpto.8 +qmail-users.9 +qmail.7 +qreceipt.1 +splogger.8 +tcp-env.1 +config.sh +config-fast.sh +qmail-clean.c +qmail-getpw.c +qmail-inject.c +qmail-local.c +qmail-lspawn.c +qmail-newmrh.c +qmail-newu.c +qmail-pop3d.c +qmail-popup.c +qmail-pw2u.c +qmail-qmqpc.c +qmail-qmqpd.c +qmail-qmtpd.c +qmail-qread.c +qmail-qstat.sh +qmail-queue.c +qmail-remote.c +qmail-rspawn.c +qmail-send.c +qmail-showctl.c +qmail-smtpd.c +qmail-start.c +qmail-tcpok.c +qmail-tcpto.c +spawn.c +dnscname.c +dnsfq.c +dnsip.c +dnsmxip.c +dnsptr.c +hostname.c +ipmeprint.c +tcp-env.c +sendmail.c +qreceipt.c +qsmhook.c +qbiff.c +forward.c +preline.c +predate.c +except.c +bouncesaying.c +condredirect.c +maildirmake.c +maildir2mbox.c +maildirwatch.c +splogger.c +qail.sh +elq.sh +pinq.sh +qmail-upq.sh +datemail.sh +mailsubj.sh +qlx.h +rcpthosts.h +rcpthosts.c +commands.h +commands.c +dnsdoe.h +dnsdoe.c +fmtqfn.h +fmtqfn.c +gfrom.h +gfrom.c +myctime.h +myctime.c +newfield.h +newfield.c +qsutil.h +qsutil.c +readsubdir.h +readsubdir.c +received.h +received.c +tcpto.h +tcpto.c +tcpto_clean.c +trigger.h +trigger.c +triggerpull.h +triggerpull.c +trynpbg1.c +trysyslog.c +conf-cc +conf-ld +home.sh +home+df.sh +proc.sh +proc+df.sh +binm1.sh +binm2.sh +binm3.sh +binm1+df.sh +binm2+df.sh +binm3+df.sh +find-systype.sh +make-compile.sh +make-load.sh +make-makelib.sh +trycpp.c +warn-auto.sh +auto-str.c +auto-int.c +auto-int8.c +auto-gid.c +auto-uid.c +hier.c +install.c +instcheck.c +install-big.c +alloc.3 +alloc.h +alloc.c +alloc_re.c +case.3 +case.h +case_diffb.c +case_diffs.c +case_lowerb.c +case_lowers.c +case_starts.c +cdb.3 +cdb.h +cdb_hash.c +cdb_seek.c +cdb_unpack.c +cdbmake.h +cdbmake_add.c +cdbmake_hash.c +cdbmake_pack.c +cdbmss.h +cdbmss.c +coe.3 +coe.h +coe.c +fd.h +fd_copy.3 +fd_copy.c +fd_move.3 +fd_move.c +fifo_make.3 +fifo.h +fifo.c +trymkffo.c +fork.h1 +fork.h2 +tryvfork.c +now.3 +now.h +now.c +open.h +open_append.c +open_excl.c +open_read.c +open_trunc.c +open_write.c +seek.h +seek_cur.c +seek_end.c +seek_set.c +seek_trunc.c +conf-qmail +auto_qmail.h +qmail.h +qmail.c +gen_alloc.h +gen_allocdefs.h +stralloc.3 +stralloc.h +stralloc_eady.c +stralloc_pend.c +stralloc_copy.c +stralloc_opyb.c +stralloc_opys.c +stralloc_cat.c +stralloc_catb.c +stralloc_cats.c +stralloc_arts.c +strerr.h +strerr_sys.c +strerr_die.c +substdio.h +substdio.c +substdi.c +substdo.c +substdio_copy.c +subfd.h +subfderr.c +subfdouts.c +subfdout.c +subfdins.c +subfdin.c +readwrite.h +exit.h +timeoutconn.h +timeoutconn.c +timeoutread.h +timeoutread.c +timeoutwrite.h +timeoutwrite.c +remoteinfo.h +remoteinfo.c +uint32.h1 +uint32.h2 +tryulong32.c +wait.3 +wait.h +wait_pid.c +wait_nohang.c +trywaitp.c +sig.h +sig_alarm.c +sig_block.c +sig_catch.c +sig_pause.c +sig_pipe.c +sig_child.c +sig_term.c +sig_hup.c +sig_misc.c +sig_bug.c +trysgact.c +trysgprm.c +env.3 +env.h +env.c +envread.c +byte.h +byte_chr.c +byte_copy.c +byte_cr.c +byte_diff.c +byte_rchr.c +byte_zero.c +str.h +str_chr.c +str_cpy.c +str_diff.c +str_diffn.c +str_len.c +str_rchr.c +str_start.c +lock.h +lock_ex.c +lock_exnb.c +lock_un.c +tryflock.c +getln.3 +getln.h +getln.c +getln2.3 +getln2.c +sgetopt.3 +sgetopt.h +sgetopt.c +subgetopt.3 +subgetopt.h +subgetopt.c +error.3 +error_str.3 +error_temp.3 +error.h +error.c +error_str.c +error_temp.c +fmt.h +fmt_str.c +fmt_strn.c +fmt_uint.c +fmt_uint0.c +fmt_ulong.c +scan.h +scan_ulong.c +scan_8long.c +slurpclose.h +slurpclose.c +quote.h +quote.c +hfield.h +hfield.c +headerbody.h +headerbody.c +token822.h +token822.c +control.h +control.c +datetime.3 +datetime.h +datetime.c +datetime_un.c +prioq.h +prioq.c +date822fmt.h +date822fmt.c +dns.h +dns.c +trylsock.c +tryrsolv.c +ip.h +ip.c +ipalloc.h +ipalloc.c +select.h1 +select.h2 +trysysel.c +ndelay.h +ndelay.c +ndelay_off.c +direntry.3 +direntry.h1 +direntry.h2 +trydrent.c +prot.h +prot.c +chkshsgr.c +warn-shsgr +tryshsgr.c +ipme.h +ipme.c +trysalen.c +maildir.5 +maildir.h +maildir.c +tcp-environ.5 +constmap.h +constmap.c diff -u -N qmail-1.03-orig/Makefile test/Makefile --- qmail-1.03-orig/Makefile Mon Jun 15 12:53:16 1998 +++ test/Makefile Thu Mar 1 23:59:20 2001 @@ -1,8 +1,74 @@ +# 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 use cleartext passwords (a bad idea on production systems) add +# -DCLEARTEXTPASSWD to the LDAPFLAGS +LDAPFLAGS=-DQLDAP_CLUSTER -DMXPS -DSMTP_AFTER_POP -DDASH_EXT + +# 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 added like this: +#LDAPLIBS=-L/opt/OpenLDAP/lib -lldap -llber -lresolv +# 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 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 +86,43 @@ 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 + ./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 + ./load auth_imap checkpassword.o check.o control.o qldap-ldaplib.o \ + qldap-debug.o auto_qmail.o dns.o timeoutconn.o timeoutread.o ip.o \ + ipalloc.o getln.a open.a env.a stralloc.a alloc.a substdio.a str.a \ + base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \ + 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 + ./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 + ./load auth_pop checkpassword.o check.o control.o qldap-ldaplib.o \ + qldap-debug.o auto_qmail.o dns.o timeoutconn.o timeoutread.o ip.o \ + ipalloc.o getln.a open.a env.a stralloc.a alloc.a substdio.a str.a \ + base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \ + 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 +239,10 @@ compile auto_usera.c ./compile auto_usera.c +base64.o: \ +compile base64.c base64.h + ./compile $(LDAPFLAGS) base64.c + binm1: \ binm1.sh conf-qmail cat binm1.sh \ @@ -280,9 +387,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 \ +compatibility.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) checkpassword.c + chkshsgr: \ load chkshsgr.o ./load chkshsgr @@ -386,6 +504,32 @@ 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 + ./load digest digest_md4.o digest_md5.o digest_rmd160.o \ + digest_sha1.o base64.o + +digest.o: \ +compile digest.c compatibility.h + ./compile $(LDAPFLAGS) digest.c + +digest_md4.o: \ +compile endian digest_md4.c digest_md4.h compatibility.h + ./compile $(LDAPFLAGS) `./endian` digest_md4.c + +digest_md5.o: \ +compile endian digest_md5.c digest_md5.h compatibility.h + ./compile $(LDAPFLAGS) `./endian` digest_md5.c + +digest_rmd160.o: \ +compile endian digest_rmd160.c digest_rmd160.h compatibility.h + ./compile $(LDAPFLAGS) `./endian` digest_rmd160.c + +digest_sha1.o: \ +compile endian digest_sha1.c digest_sha1.h compatibility.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 +548,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 +576,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 +588,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 +601,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 +636,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 +855,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 +907,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 +931,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 +947,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 +958,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 +993,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 + ./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 \ @@ -1074,6 +1232,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 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 + ./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} 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 +1353,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 +1371,45 @@ 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 + ./load qmail-ldaplookup qldap-ldaplib.o control.o error.a \ + getln.a stralloc.a qldap-debug.o qldap-errno.o check.o fs.a \ + open.a env.a strerr.a substdio.a str.a alloc.a \ + base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \ + auto_qmail.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 compatibility.h digest_md4.h \ +digest_md5.h digest_rmd160.h digest_sha1.h open.h + ./compile $(LDAPFLAGS) $(SHADOWOPTS) 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 + ./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 \ + 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 $(LDAPLIBS) qmail-lspawn.0: \ qmail-lspawn.8 @@ -1213,8 +1418,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 + ./compile $(LDAPFLAGS) $(HDIRMAKE) $(LDAPINCLUDES) qmail-lspawn.c qmail-newmrh: \ load qmail-newmrh.o cdbmss.o getln.a open.a cdbmake.a seek.a case.a \ @@ -1268,12 +1475,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 +1491,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 +1510,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 +1546,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 +1556,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 +1645,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 +1669,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 +1681,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 +1745,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 +1772,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 +1790,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 +1979,7 @@ ./compile sendmail.c setup: \ -it man +it man qldap ./install sgetopt.o: \ @@ -2139,3 +2375,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 -u -N qmail-1.03-orig/Makefile.orig test/Makefile.orig --- qmail-1.03-orig/Makefile.orig Thu Jan 1 01:00:00 1970 +++ test/Makefile.orig Thu Mar 1 23:58:55 2001 @@ -0,0 +1,2398 @@ +# 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 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 added like this: +#LDAPLIBS=-L/opt/OpenLDAP/lib -lldap -llber -lresolv +# 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 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 qldap + +qldap: qmail-quotawarn qmail-reply auth_pop auth_imap digest qmail-ldaplookup + +addresses.0: \ +addresses.5 + nroff -man addresses.5 > addresses.0 + +alloc.a: \ +makelib alloc.o alloc_re.o + ./makelib alloc.a alloc.o alloc_re.o + +alloc.o: \ +compile alloc.c alloc.h error.h + ./compile alloc.c + +alloc_re.o: \ +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 + ./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 + ./load auth_imap checkpassword.o check.o control.o qldap-ldaplib.o \ + qldap-debug.o auto_qmail.o dns.o timeoutconn.o timeoutread.o ip.o \ + ipalloc.o getln.a open.a env.a stralloc.a alloc.a substdio.a str.a \ + base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \ + 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 + ./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 + ./load auth_pop checkpassword.o check.o control.o qldap-ldaplib.o \ + qldap-debug.o auto_qmail.o dns.o timeoutconn.o timeoutread.o ip.o \ + ipalloc.o getln.a open.a env.a stralloc.a alloc.a substdio.a str.a \ + base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \ + 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; \ + echo CC=\'`head -1 conf-cc`\'; \ + echo LD=\'`head -1 conf-ld`\' \ + ) > auto-ccld.sh + +auto-gid: \ +load auto-gid.o substdio.a error.a str.a fs.a + ./load auto-gid substdio.a error.a str.a fs.a + +auto-gid.o: \ +compile auto-gid.c subfd.h substdio.h substdio.h readwrite.h exit.h \ +scan.h fmt.h + ./compile auto-gid.c + +auto-int: \ +load auto-int.o substdio.a error.a str.a fs.a + ./load auto-int substdio.a error.a str.a fs.a + +auto-int.o: \ +compile auto-int.c substdio.h readwrite.h exit.h scan.h fmt.h + ./compile auto-int.c + +auto-int8: \ +load auto-int8.o substdio.a error.a str.a fs.a + ./load auto-int8 substdio.a error.a str.a fs.a + +auto-int8.o: \ +compile auto-int8.c substdio.h readwrite.h exit.h scan.h fmt.h + ./compile auto-int8.c + +auto-str: \ +load auto-str.o substdio.a error.a str.a + ./load auto-str substdio.a error.a str.a + +auto-str.o: \ +compile auto-str.c substdio.h readwrite.h exit.h + ./compile auto-str.c + +auto-uid: \ +load auto-uid.o substdio.a error.a str.a fs.a + ./load auto-uid substdio.a error.a str.a fs.a + +auto-uid.o: \ +compile auto-uid.c subfd.h substdio.h substdio.h readwrite.h exit.h \ +scan.h fmt.h + ./compile auto-uid.c + +auto_break.c: \ +auto-str conf-break + ./auto-str auto_break \ + "`head -1 conf-break`" > auto_break.c + +auto_break.o: \ +compile auto_break.c + ./compile auto_break.c + +auto_patrn.c: \ +auto-int8 conf-patrn + ./auto-int8 auto_patrn `head -1 conf-patrn` > auto_patrn.c + +auto_patrn.o: \ +compile auto_patrn.c + ./compile auto_patrn.c + +auto_qmail.c: \ +auto-str conf-qmail + ./auto-str auto_qmail `head -1 conf-qmail` > auto_qmail.c + +auto_qmail.o: \ +compile auto_qmail.c + ./compile auto_qmail.c + +auto_spawn.c: \ +auto-int conf-spawn + ./auto-int auto_spawn `head -1 conf-spawn` > auto_spawn.c + +auto_spawn.o: \ +compile auto_spawn.c + ./compile auto_spawn.c + +auto_split.c: \ +auto-int conf-split + ./auto-int auto_split `head -1 conf-split` > auto_split.c + +auto_split.o: \ +compile auto_split.c + ./compile auto_split.c + +auto_uids.c: \ +auto-uid auto-gid conf-users conf-groups + ( ./auto-uid auto_uida `head -1 conf-users` \ + &&./auto-uid auto_uidd `head -2 conf-users | tail -1` \ + &&./auto-uid auto_uidl `head -3 conf-users | tail -1` \ + &&./auto-uid auto_uido `head -4 conf-users | tail -1` \ + &&./auto-uid auto_uidp `head -5 conf-users | tail -1` \ + &&./auto-uid auto_uidq `head -6 conf-users | tail -1` \ + &&./auto-uid auto_uidr `head -7 conf-users | tail -1` \ + &&./auto-uid auto_uids `head -8 conf-users | tail -1` \ + &&./auto-gid auto_gidq `head -1 conf-groups` \ + &&./auto-gid auto_gidn `head -2 conf-groups | tail -1` \ + ) > auto_uids.c.tmp && mv auto_uids.c.tmp auto_uids.c + +auto_uids.o: \ +compile auto_uids.c + ./compile auto_uids.c + +auto_usera.c: \ +auto-str conf-users + ./auto-str auto_usera `head -1 conf-users` > auto_usera.c + +auto_usera.o: \ +compile auto_usera.c + ./compile auto_usera.c + +base64.o: \ +compile base64.c base64.h + ./compile $(LDAPFLAGS) base64.c + +binm1: \ +binm1.sh conf-qmail + cat binm1.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + > binm1 + chmod 755 binm1 + +binm1+df: \ +binm1+df.sh conf-qmail + cat binm1+df.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + > binm1+df + chmod 755 binm1+df + +binm2: \ +binm2.sh conf-qmail + cat binm2.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + > binm2 + chmod 755 binm2 + +binm2+df: \ +binm2+df.sh conf-qmail + cat binm2+df.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + > binm2+df + chmod 755 binm2+df + +binm3: \ +binm3.sh conf-qmail + cat binm3.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + > binm3 + chmod 755 binm3 + +binm3+df: \ +binm3+df.sh conf-qmail + cat binm3+df.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + > binm3+df + chmod 755 binm3+df + +bouncesaying: \ +load bouncesaying.o strerr.a error.a substdio.a str.a wait.a + ./load bouncesaying strerr.a error.a substdio.a str.a \ + wait.a + +bouncesaying.0: \ +bouncesaying.1 + nroff -man bouncesaying.1 > bouncesaying.0 + +bouncesaying.o: \ +compile bouncesaying.c fork.h strerr.h error.h wait.h sig.h exit.h + ./compile bouncesaying.c + +byte_chr.o: \ +compile byte_chr.c byte.h + ./compile byte_chr.c + +byte_copy.o: \ +compile byte_copy.c byte.h + ./compile byte_copy.c + +byte_cr.o: \ +compile byte_cr.c byte.h + ./compile byte_cr.c + +byte_diff.o: \ +compile byte_diff.c byte.h + ./compile byte_diff.c + +byte_rchr.o: \ +compile byte_rchr.c byte.h + ./compile byte_rchr.c + +byte_zero.o: \ +compile byte_zero.c byte.h + ./compile byte_zero.c + +case.a: \ +makelib case_diffb.o case_diffs.o case_lowerb.o case_lowers.o \ +case_starts.o + ./makelib case.a case_diffb.o case_diffs.o case_lowerb.o \ + case_lowers.o case_starts.o + +case_diffb.o: \ +compile case_diffb.c case.h + ./compile case_diffb.c + +case_diffs.o: \ +compile case_diffs.c case.h + ./compile case_diffs.c + +case_lowerb.o: \ +compile case_lowerb.c case.h + ./compile case_lowerb.c + +case_lowers.o: \ +compile case_lowers.c case.h + ./compile case_lowers.c + +case_starts.o: \ +compile case_starts.c case.h + ./compile case_starts.c + +cdb.a: \ +makelib cdb_hash.o cdb_unpack.o cdb_seek.o + ./makelib cdb.a cdb_hash.o cdb_unpack.o cdb_seek.o + +cdb_hash.o: \ +compile cdb_hash.c cdb.h uint32.h + ./compile cdb_hash.c + +cdb_seek.o: \ +compile cdb_seek.c cdb.h uint32.h + ./compile cdb_seek.c + +cdb_unpack.o: \ +compile cdb_unpack.c cdb.h uint32.h + ./compile cdb_unpack.c + +cdbmake.a: \ +makelib cdbmake_pack.o cdbmake_hash.o cdbmake_add.o + ./makelib cdbmake.a cdbmake_pack.o cdbmake_hash.o \ + cdbmake_add.o + +cdbmake_add.o: \ +compile cdbmake_add.c cdbmake.h uint32.h + ./compile cdbmake_add.c + +cdbmake_hash.o: \ +compile cdbmake_hash.c cdbmake.h uint32.h + ./compile cdbmake_hash.c + +cdbmake_pack.o: \ +compile cdbmake_pack.c cdbmake.h uint32.h + ./compile cdbmake_pack.c + +cdbmss.o: \ +compile cdbmss.c readwrite.h seek.h alloc.h cdbmss.h cdbmake.h \ +uint32.h substdio.h + ./compile cdbmss.c + +check: \ +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 \ +compatibility.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) checkpassword.c + +chkshsgr: \ +load chkshsgr.o + ./load chkshsgr + +chkshsgr.o: \ +compile chkshsgr.c exit.h + ./compile chkshsgr.c + +chkspawn: \ +load chkspawn.o substdio.a error.a str.a fs.a auto_spawn.o + ./load chkspawn substdio.a error.a str.a fs.a auto_spawn.o + +chkspawn.o: \ +compile chkspawn.c substdio.h subfd.h substdio.h fmt.h select.h \ +exit.h auto_spawn.h + ./compile chkspawn.c + +clean: \ +TARGETS + rm -f `cat TARGETS` + +coe.o: \ +compile coe.c coe.h + ./compile coe.c + +commands.o: \ +compile commands.c commands.h substdio.h stralloc.h gen_alloc.h str.h \ +case.h + ./compile commands.c + +compile: \ +make-compile warn-auto.sh systype + ( cat warn-auto.sh; ./make-compile "`cat systype`" ) > \ + compile + chmod 755 compile + +condredirect: \ +load condredirect.o qmail.o strerr.a fd.a sig.a wait.a seek.a env.a \ +substdio.a error.a str.a fs.a auto_qmail.o + ./load condredirect qmail.o strerr.a fd.a sig.a wait.a \ + seek.a env.a substdio.a error.a str.a fs.a auto_qmail.o + +condredirect.0: \ +condredirect.1 + nroff -man condredirect.1 > condredirect.0 + +condredirect.o: \ +compile condredirect.c sig.h readwrite.h exit.h env.h error.h fork.h \ +wait.h seek.h qmail.h substdio.h strerr.h substdio.h fmt.h + ./compile condredirect.c + +config: \ +warn-auto.sh config.sh conf-qmail conf-break conf-split + cat warn-auto.sh config.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > config + chmod 755 config + +config-fast: \ +warn-auto.sh config-fast.sh conf-qmail conf-break conf-split + cat warn-auto.sh config-fast.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > config-fast + chmod 755 config-fast + +constmap.o: \ +compile constmap.c constmap.h alloc.h case.h + ./compile constmap.c + +control.o: \ +compile control.c readwrite.h open.h getln.h stralloc.h gen_alloc.h \ +substdio.h error.h control.h alloc.h scan.h + ./compile control.c + +date822fmt.o: \ +compile date822fmt.c datetime.h fmt.h date822fmt.h + ./compile date822fmt.c + +datemail: \ +warn-auto.sh datemail.sh conf-qmail conf-break conf-split + cat warn-auto.sh datemail.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > datemail + chmod 755 datemail + +datetime.a: \ +makelib datetime.o datetime_un.o + ./makelib datetime.a datetime.o datetime_un.o + +datetime.o: \ +compile datetime.c datetime.h + ./compile datetime.c + +datetime_un.o: \ +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 + ./load digest digest_md4.o digest_md5.o digest_rmd160.o \ + digest_sha1.o base64.o + +digest.o: \ +compile digest.c compatibility.h + ./compile $(LDAPFLAGS) digest.c + +digest_md4.o: \ +compile endian digest_md4.c digest_md4.h compatibility.h + ./compile $(LDAPFLAGS) `./endian` digest_md4.c + +digest_md5.o: \ +compile endian digest_md5.c digest_md5.h compatibility.h + ./compile $(LDAPFLAGS) `./endian` digest_md5.c + +digest_rmd160.o: \ +compile endian digest_rmd160.c digest_rmd160.h compatibility.h + ./compile $(LDAPFLAGS) `./endian` digest_rmd160.c + +digest_sha1.o: \ +compile endian digest_sha1.c digest_sha1.h compatibility.h + ./compile $(LDAPFLAGS) `./endian` digest_sha1.c + +direntry.h: \ +compile trydrent.c direntry.h1 direntry.h2 + ( ./compile trydrent.c >/dev/null 2>&1 \ + && cat direntry.h2 || cat direntry.h1 ) > direntry.h + rm -f trydrent.o + +dns.lib: \ +tryrsolv.c compile load socket.lib dns.o ipalloc.o ip.o stralloc.a \ +alloc.a error.a fs.a str.a + ( ( ./compile tryrsolv.c && ./load tryrsolv dns.o \ + ipalloc.o ip.o stralloc.a alloc.a error.a fs.a str.a \ + -lresolv `cat socket.lib` ) >/dev/null 2>&1 \ + && echo -lresolv || exit 0 ) > dns.lib + rm -f tryrsolv.o tryrsolv + +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 ${TLSON} dns.c + +dnscname: \ +load dnscname.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ +substdio.a error.a str.a fs.a dns.lib socket.lib + ./load dnscname dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \ + alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \ + socket.lib` + +dnscname.o: \ +compile dnscname.c substdio.h subfd.h substdio.h stralloc.h \ +gen_alloc.h dns.h dnsdoe.h readwrite.h exit.h + ./compile dnscname.c + +dnsdoe.o: \ +compile dnsdoe.c substdio.h subfd.h substdio.h exit.h dns.h dnsdoe.h + ./compile dnsdoe.c + +dnsfq: \ +load dnsfq.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ +substdio.a error.a str.a fs.a dns.lib socket.lib + ./load dnsfq dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \ + alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \ + socket.lib` + +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 ${TLSON} dnsfq.c + +dnsip: \ +load dnsip.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ +substdio.a error.a str.a fs.a dns.lib socket.lib + ./load dnsip dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \ + alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \ + socket.lib` + +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 ${TLSON} dnsip.c + +dnsmxip: \ +load dnsmxip.o dns.o dnsdoe.o ip.o ipalloc.o now.o stralloc.a alloc.a \ +substdio.a error.a str.a fs.a dns.lib socket.lib + ./load dnsmxip dns.o dnsdoe.o ip.o ipalloc.o now.o \ + stralloc.a alloc.a substdio.a error.a str.a fs.a `cat \ + dns.lib` `cat socket.lib` + +dnsmxip.o: \ +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 ${TLSON} dnsmxip.c + +dnsptr: \ +load dnsptr.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ +substdio.a error.a str.a fs.a dns.lib socket.lib + ./load dnsptr dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \ + alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \ + socket.lib` + +dnsptr.o: \ +compile dnsptr.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \ +str.h scan.h dns.h dnsdoe.h ip.h exit.h + ./compile dnsptr.c + +dot-qmail.0: \ +dot-qmail.5 + nroff -man dot-qmail.5 > dot-qmail.0 + +dot-qmail.5: \ +dot-qmail.9 conf-break conf-spawn + cat dot-qmail.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > dot-qmail.5 + +elq: \ +warn-auto.sh elq.sh conf-qmail conf-break conf-split + cat warn-auto.sh elq.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > 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 + +env.o: \ +compile env.c str.h alloc.h env.h + ./compile env.c + +envelopes.0: \ +envelopes.5 + nroff -man envelopes.5 > envelopes.0 + +envread.o: \ +compile envread.c env.h str.h + ./compile envread.c + +error.a: \ +makelib error.o error_str.o error_temp.o + ./makelib error.a error.o error_str.o error_temp.o + +error.o: \ +compile error.c error.h + ./compile error.c + +error_str.o: \ +compile error_str.c error.h + ./compile error_str.c + +error_temp.o: \ +compile error_temp.c error.h + ./compile error_temp.c + +except: \ +load except.o strerr.a error.a substdio.a str.a wait.a + ./load except strerr.a error.a substdio.a str.a wait.a + +except.0: \ +except.1 + nroff -man except.1 > except.0 + +except.o: \ +compile except.c fork.h strerr.h wait.h error.h exit.h + ./compile except.c + +fd.a: \ +makelib fd_copy.o fd_move.o + ./makelib fd.a fd_copy.o fd_move.o + +fd_copy.o: \ +compile fd_copy.c fd.h + ./compile fd_copy.c + +fd_move.o: \ +compile fd_move.c fd.h + ./compile fd_move.c + +fifo.o: \ +compile fifo.c hasmkffo.h fifo.h + ./compile fifo.c + +find-systype: \ +find-systype.sh auto-ccld.sh + cat auto-ccld.sh find-systype.sh > find-systype + chmod 755 find-systype + +fmt_str.o: \ +compile fmt_str.c fmt.h + ./compile fmt_str.c + +fmt_strn.o: \ +compile fmt_strn.c fmt.h + ./compile fmt_strn.c + +fmt_uint.o: \ +compile fmt_uint.c fmt.h + ./compile fmt_uint.c + +fmt_uint0.o: \ +compile fmt_uint0.c fmt.h + ./compile fmt_uint0.c + +fmt_ulong.o: \ +compile fmt_ulong.c fmt.h + ./compile fmt_ulong.c + +fmtqfn.o: \ +compile fmtqfn.c fmtqfn.h fmt.h auto_split.h + ./compile fmtqfn.c + +forgeries.0: \ +forgeries.7 + nroff -man forgeries.7 > forgeries.0 + +fork.h: \ +compile load tryvfork.c fork.h1 fork.h2 + ( ( ./compile tryvfork.c && ./load tryvfork ) >/dev/null \ + 2>&1 \ + && cat fork.h2 || cat fork.h1 ) > fork.h + rm -f tryvfork.o tryvfork + +forward: \ +load forward.o qmail.o strerr.a alloc.a fd.a wait.a sig.a env.a \ +substdio.a error.a str.a fs.a auto_qmail.o + ./load forward qmail.o strerr.a alloc.a fd.a wait.a sig.a \ + env.a substdio.a error.a str.a fs.a auto_qmail.o + +forward.0: \ +forward.1 + nroff -man forward.1 > forward.0 + +forward.o: \ +compile forward.c sig.h readwrite.h exit.h env.h qmail.h substdio.h \ +strerr.h substdio.h fmt.h + ./compile forward.c + +fs.a: \ +makelib fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o fmt_ulong.o \ +scan_ulong.o scan_8long.o + ./makelib fs.a fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o \ + fmt_ulong.o scan_ulong.o scan_8long.o + +getln.a: \ +makelib getln.o getln2.o + ./makelib getln.a getln.o getln2.o + +getln.o: \ +compile getln.c substdio.h byte.h stralloc.h gen_alloc.h getln.h + ./compile getln.c + +getln2.o: \ +compile getln2.c substdio.h stralloc.h gen_alloc.h byte.h getln.h + ./compile getln2.c + +getopt.a: \ +makelib subgetopt.o sgetopt.o + ./makelib getopt.a subgetopt.o sgetopt.o + +gfrom.o: \ +compile gfrom.c str.h gfrom.h + ./compile gfrom.c + +hasflock.h: \ +tryflock.c compile load + ( ( ./compile tryflock.c && ./load tryflock ) >/dev/null \ + 2>&1 \ + && echo \#define HASFLOCK 1 || exit 0 ) > hasflock.h + rm -f tryflock.o tryflock + +hasmkffo.h: \ +trymkffo.c compile load + ( ( ./compile trymkffo.c && ./load trymkffo ) >/dev/null \ + 2>&1 \ + && echo \#define HASMKFIFO 1 || exit 0 ) > hasmkffo.h + rm -f trymkffo.o trymkffo + +hasnpbg1.h: \ +trynpbg1.c compile load open.h open.a fifo.h fifo.o select.h + ( ( ./compile trynpbg1.c \ + && ./load trynpbg1 fifo.o open.a && ./trynpbg1 ) \ + >/dev/null 2>&1 \ + && echo \#define HASNAMEDPIPEBUG1 1 || exit 0 ) > \ + hasnpbg1.h + rm -f trynpbg1.o trynpbg1 + +hassalen.h: \ +trysalen.c compile + ( ./compile trysalen.c >/dev/null 2>&1 \ + && echo \#define HASSALEN 1 || exit 0 ) > hassalen.h + rm -f trysalen.o + +hassgact.h: \ +trysgact.c compile load + ( ( ./compile trysgact.c && ./load trysgact ) >/dev/null \ + 2>&1 \ + && echo \#define HASSIGACTION 1 || exit 0 ) > hassgact.h + rm -f trysgact.o trysgact + +hassgprm.h: \ +trysgprm.c compile load + ( ( ./compile trysgprm.c && ./load trysgprm ) >/dev/null \ + 2>&1 \ + && echo \#define HASSIGPROCMASK 1 || exit 0 ) > hassgprm.h + rm -f trysgprm.o trysgprm + +hasshsgr.h: \ +chkshsgr warn-shsgr tryshsgr.c compile load + ./chkshsgr || ( cat warn-shsgr; exit 1 ) + ( ( ./compile tryshsgr.c \ + && ./load tryshsgr && ./tryshsgr ) >/dev/null 2>&1 \ + && echo \#define HASSHORTSETGROUPS 1 || exit 0 ) > \ + hasshsgr.h + rm -f tryshsgr.o tryshsgr + +haswaitp.h: \ +trywaitp.c compile load + ( ( ./compile trywaitp.c && ./load trywaitp ) >/dev/null \ + 2>&1 \ + && echo \#define HASWAITPID 1 || exit 0 ) > haswaitp.h + rm -f trywaitp.o trywaitp + +headerbody.o: \ +compile headerbody.c stralloc.h gen_alloc.h substdio.h getln.h \ +hfield.h headerbody.h + ./compile headerbody.c + +hfield.o: \ +compile hfield.c hfield.h + ./compile hfield.c + +hier.o: \ +compile hier.c auto_qmail.h auto_split.h auto_uids.h fmt.h fifo.h + ./compile $(LDAPFLAGS) $(DEBUG) hier.c + +home: \ +home.sh conf-qmail + cat home.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + > home + chmod 755 home + +home+df: \ +home+df.sh conf-qmail + cat home+df.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + > home+df + chmod 755 home+df + +hostname: \ +load hostname.o substdio.a error.a str.a dns.lib socket.lib + ./load hostname substdio.a error.a str.a `cat dns.lib` \ + `cat socket.lib` + +hostname.o: \ +compile hostname.c substdio.h subfd.h substdio.h readwrite.h exit.h + ./compile hostname.c + +idedit: \ +load idedit.o strerr.a substdio.a error.a str.a fs.a wait.a open.a \ +seek.a + ./load idedit strerr.a substdio.a error.a str.a fs.a \ + wait.a open.a seek.a + +idedit.o: \ +compile idedit.c readwrite.h exit.h scan.h fmt.h strerr.h open.h \ +seek.h fork.h + ./compile idedit.c + +install: \ +load install.o fifo.o hier.o auto_qmail.o auto_split.o auto_uids.o \ +strerr.a substdio.a open.a error.a str.a fs.a + ./load install fifo.o hier.o auto_qmail.o auto_split.o \ + auto_uids.o strerr.a substdio.a open.a error.a str.a fs.a + +install-big: \ +load install-big.o fifo.o install.o auto_qmail.o auto_split.o \ +auto_uids.o strerr.a substdio.a open.a error.a str.a fs.a + ./load install-big fifo.o install.o auto_qmail.o \ + auto_split.o auto_uids.o strerr.a substdio.a open.a error.a \ + str.a fs.a + +install-big.o: \ +compile install-big.c auto_qmail.h auto_split.h auto_uids.h fmt.h \ +fifo.h + ./compile $(LDAPFLAGS) $(DEBUG) install-big.c + +install.o: \ +compile install.c substdio.h strerr.h error.h open.h readwrite.h \ +exit.h + ./compile install.c + +instcheck: \ +load instcheck.o fifo.o hier.o auto_qmail.o auto_split.o auto_uids.o \ +strerr.a substdio.a error.a str.a fs.a + ./load instcheck fifo.o hier.o auto_qmail.o auto_split.o \ + auto_uids.o strerr.a substdio.a error.a str.a fs.a + +instcheck.o: \ +compile instcheck.c strerr.h error.h readwrite.h exit.h + ./compile instcheck.c + +ip.o: \ +compile ip.c fmt.h scan.h ip.h + ./compile ip.c + +ipalloc.o: \ +compile ipalloc.c alloc.h gen_allocdefs.h ip.h ipalloc.h ip.h \ +gen_alloc.h + ./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 ${TLSON} ipme.c + +ipmeprint: \ +load ipmeprint.o ipme.o ip.o ipalloc.o stralloc.a alloc.a substdio.a \ +error.a str.a fs.a socket.lib + ./load ipmeprint ipme.o ip.o ipalloc.o stralloc.a alloc.a \ + substdio.a error.a str.a fs.a `cat socket.lib` + +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 ${TLSON} ipmeprint.c + +it: \ +qmail-local qmail-lspawn qmail-getpw qmail-remote qmail-rspawn \ +qmail-clean qmail-send qmail-start splogger qmail-queue qmail-inject \ +predate datemail mailsubj qmail-upq qmail-showctl qmail-newu \ +qmail-pw2u qmail-qread qmail-qstat qmail-tcpto qmail-tcpok \ +qmail-pop3d qmail-popup qmail-qmqpc qmail-qmqpd qmail-qmtpd \ +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 + +load: \ +make-load warn-auto.sh systype + ( cat warn-auto.sh; ./make-load "`cat systype`" ) > load + chmod 755 load + +lock.a: \ +makelib lock_ex.o lock_exnb.o lock_un.o + ./makelib lock.a lock_ex.o lock_exnb.o lock_un.o + +lock_ex.o: \ +compile lock_ex.c hasflock.h lock.h + ./compile lock_ex.c + +lock_exnb.o: \ +compile lock_exnb.c hasflock.h lock.h + ./compile lock_exnb.c + +lock_un.o: \ +compile lock_un.c hasflock.h lock.h + ./compile lock_un.c + +maildir.0: \ +maildir.5 + nroff -man maildir.5 > maildir.0 + +maildir.o: \ +compile maildir.c prioq.h datetime.h gen_alloc.h env.h stralloc.h \ +gen_alloc.h direntry.h datetime.h now.h datetime.h str.h maildir.h \ +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 + ./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 \ +str.a fs.a datetime.a + ./load maildir2mbox 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 str.a fs.a datetime.a + +maildir2mbox.0: \ +maildir2mbox.1 + nroff -man maildir2mbox.1 > maildir2mbox.0 + +maildir2mbox.o: \ +compile maildir2mbox.c readwrite.h prioq.h datetime.h gen_alloc.h \ +env.h stralloc.h gen_alloc.h subfd.h substdio.h substdio.h getln.h \ +error.h open.h lock.h gfrom.h str.h exit.h myctime.h maildir.h \ +strerr.h + ./compile maildir2mbox.c + +maildirmake: \ +load maildirmake.o strerr.a substdio.a error.a str.a + ./load maildirmake strerr.a substdio.a error.a str.a + +maildirmake.0: \ +maildirmake.1 + nroff -man maildirmake.1 > maildirmake.0 + +maildirmake.o: \ +compile maildirmake.c strerr.h exit.h + ./compile maildirmake.c + +maildirwatch: \ +load maildirwatch.o hfield.o headerbody.o maildir.o prioq.o now.o \ +getln.a env.a open.a strerr.a stralloc.a alloc.a substdio.a error.a \ +str.a + ./load maildirwatch hfield.o headerbody.o maildir.o \ + prioq.o now.o getln.a env.a open.a strerr.a stralloc.a \ + alloc.a substdio.a error.a str.a + +maildirwatch.0: \ +maildirwatch.1 + nroff -man maildirwatch.1 > maildirwatch.0 + +maildirwatch.o: \ +compile maildirwatch.c getln.h substdio.h subfd.h substdio.h prioq.h \ +datetime.h gen_alloc.h stralloc.h gen_alloc.h str.h exit.h hfield.h \ +readwrite.h open.h headerbody.h maildir.h strerr.h + ./compile maildirwatch.c + +mailsubj: \ +warn-auto.sh mailsubj.sh conf-qmail conf-break conf-split + cat warn-auto.sh mailsubj.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > mailsubj + chmod 755 mailsubj + +mailsubj.0: \ +mailsubj.1 + nroff -man mailsubj.1 > mailsubj.0 + +make-compile: \ +make-compile.sh auto-ccld.sh + cat auto-ccld.sh make-compile.sh > make-compile + chmod 755 make-compile + +make-load: \ +make-load.sh auto-ccld.sh + cat auto-ccld.sh make-load.sh > make-load + chmod 755 make-load + +make-makelib: \ +make-makelib.sh auto-ccld.sh + cat auto-ccld.sh make-makelib.sh > make-makelib + chmod 755 make-makelib + +makelib: \ +make-makelib warn-auto.sh systype + ( cat warn-auto.sh; ./make-makelib "`cat systype`" ) > \ + makelib + chmod 755 makelib + +man: \ +qmail-local.0 qmail-lspawn.0 qmail-getpw.0 qmail-remote.0 \ +qmail-rspawn.0 qmail-clean.0 qmail-send.0 qmail-start.0 splogger.0 \ +qmail-queue.0 qmail-inject.0 mailsubj.0 qmail-showctl.0 qmail-newu.0 \ +qmail-pw2u.0 qmail-qread.0 qmail-qstat.0 qmail-tcpto.0 qmail-tcpok.0 \ +qmail-pop3d.0 qmail-popup.0 qmail-qmqpc.0 qmail-qmqpd.0 qmail-qmtpd.0 \ +qmail-smtpd.0 tcp-env.0 qmail-newmrh.0 qreceipt.0 qbiff.0 forward.0 \ +preline.0 condredirect.0 bouncesaying.0 except.0 maildirmake.0 \ +maildir2mbox.0 maildirwatch.0 qmail.0 qmail-limits.0 qmail-log.0 \ +qmail-control.0 qmail-header.0 qmail-users.0 dot-qmail.0 \ +qmail-command.0 tcp-environ.0 maildir.0 mbox.0 addresses.0 \ +envelopes.0 forgeries.0 + +mbox.0: \ +mbox.5 + nroff -man mbox.5 > mbox.0 + +myctime.o: \ +compile myctime.c datetime.h fmt.h myctime.h + ./compile myctime.c + +ndelay.a: \ +makelib ndelay.o ndelay_off.o + ./makelib ndelay.a ndelay.o ndelay_off.o + +ndelay.o: \ +compile ndelay.c ndelay.h + ./compile ndelay.c + +ndelay_off.o: \ +compile ndelay_off.c ndelay.h + ./compile ndelay_off.c + +newfield.o: \ +compile newfield.c fmt.h datetime.h stralloc.h gen_alloc.h \ +date822fmt.h newfield.h stralloc.h + ./compile newfield.c + +now.o: \ +compile now.c datetime.h now.h datetime.h + ./compile now.c + +open.a: \ +makelib open_append.o open_excl.o open_read.o open_trunc.o \ +open_write.o + ./makelib open.a open_append.o open_excl.o open_read.o \ + open_trunc.o open_write.o + +open_append.o: \ +compile open_append.c open.h + ./compile open_append.c + +open_excl.o: \ +compile open_excl.c open.h + ./compile open_excl.c + +open_read.o: \ +compile open_read.c open.h + ./compile open_read.c + +open_trunc.o: \ +compile open_trunc.c open.h + ./compile open_trunc.c + +open_write.o: \ +compile open_write.c open.h + ./compile open_write.c + +pinq: \ +warn-auto.sh pinq.sh conf-qmail conf-break conf-split + cat warn-auto.sh pinq.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > pinq + chmod 755 pinq + +predate: \ +load predate.o datetime.a strerr.a sig.a fd.a wait.a substdio.a \ +error.a str.a fs.a + ./load predate datetime.a strerr.a sig.a fd.a wait.a \ + substdio.a error.a str.a fs.a + +predate.o: \ +compile predate.c datetime.h fork.h wait.h fd.h fmt.h strerr.h \ +substdio.h subfd.h substdio.h readwrite.h exit.h + ./compile predate.c + +preline: \ +load preline.o strerr.a fd.a wait.a sig.a env.a getopt.a substdio.a \ +error.a str.a + ./load preline strerr.a fd.a wait.a sig.a env.a getopt.a \ + substdio.a error.a str.a + +preline.0: \ +preline.1 + nroff -man preline.1 > preline.0 + +preline.o: \ +compile preline.c fd.h sgetopt.h subgetopt.h readwrite.h strerr.h \ +substdio.h exit.h fork.h wait.h env.h sig.h error.h + ./compile preline.c + +prioq.o: \ +compile prioq.c alloc.h gen_allocdefs.h prioq.h datetime.h \ +gen_alloc.h + ./compile prioq.c + +proc: \ +proc.sh conf-qmail + cat proc.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + > proc + chmod 755 proc + +proc+df: \ +proc+df.sh conf-qmail + cat proc+df.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + > proc+df + chmod 755 proc+df + +prot.o: \ +compile prot.c hasshsgr.h prot.h + ./compile prot.c + +qail: \ +warn-auto.sh qail.sh conf-qmail conf-break conf-split + cat warn-auto.sh qail.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > qail + chmod 755 qail + +qbiff: \ +load qbiff.o headerbody.o hfield.o getln.a env.a open.a stralloc.a \ +alloc.a substdio.a error.a str.a + ./load qbiff headerbody.o hfield.o getln.a env.a open.a \ + stralloc.a alloc.a substdio.a error.a str.a + +qbiff.0: \ +qbiff.1 + nroff -man qbiff.1 > qbiff.0 + +qbiff.o: \ +compile qbiff.c readwrite.h stralloc.h gen_alloc.h substdio.h subfd.h \ +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 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 + ./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} 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 + ./load qmail-clean 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 + +qmail-clean.0: \ +qmail-clean.8 + nroff -man qmail-clean.8 > qmail-clean.0 + +qmail-clean.o: \ +compile qmail-clean.c readwrite.h sig.h now.h datetime.h str.h \ +direntry.h getln.h stralloc.h gen_alloc.h substdio.h subfd.h \ +substdio.h byte.h scan.h fmt.h error.h exit.h fmtqfn.h auto_qmail.h + ./compile qmail-clean.c + +qmail-command.0: \ +qmail-command.8 + nroff -man qmail-command.8 > qmail-command.0 + +qmail-control.0: \ +qmail-control.5 + nroff -man qmail-control.5 > qmail-control.0 + +qmail-control.5: \ +qmail-control.9 conf-break conf-spawn + cat qmail-control.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-control.5 + +qmail-getpw: \ +load qmail-getpw.o case.a substdio.a error.a str.a fs.a auto_break.o \ +auto_usera.o + ./load qmail-getpw case.a substdio.a error.a str.a fs.a \ + auto_break.o auto_usera.o + +qmail-getpw.0: \ +qmail-getpw.8 + nroff -man qmail-getpw.8 > qmail-getpw.0 + +qmail-getpw.8: \ +qmail-getpw.9 conf-break conf-spawn + cat qmail-getpw.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-getpw.8 + +qmail-getpw.o: \ +compile qmail-getpw.c readwrite.h substdio.h subfd.h substdio.h \ +error.h exit.h byte.h str.h case.h fmt.h auto_usera.h auto_break.h \ +qlx.h + ./compile qmail-getpw.c + +qmail-header.0: \ +qmail-header.5 + nroff -man qmail-header.5 > qmail-header.0 + +qmail-inject: \ +load qmail-inject.o headerbody.o hfield.o newfield.o quote.o now.o \ +control.o date822fmt.o constmap.o qmail.o case.a fd.a wait.a open.a \ +getln.a sig.a getopt.a datetime.a token822.o env.a stralloc.a alloc.a \ +substdio.a error.a str.a fs.a auto_qmail.o + ./load qmail-inject headerbody.o hfield.o newfield.o \ + quote.o now.o control.o date822fmt.o constmap.o qmail.o \ + case.a fd.a wait.a open.a getln.a sig.a getopt.a datetime.a \ + token822.o env.a stralloc.a alloc.a substdio.a error.a \ + str.a fs.a auto_qmail.o + +qmail-inject.0: \ +qmail-inject.8 + nroff -man qmail-inject.8 > qmail-inject.0 + +qmail-inject.o: \ +compile qmail-inject.c sig.h substdio.h stralloc.h gen_alloc.h \ +subfd.h substdio.h sgetopt.h subgetopt.h getln.h alloc.h str.h fmt.h \ +hfield.h token822.h gen_alloc.h control.h env.h gen_alloc.h \ +gen_allocdefs.h error.h qmail.h substdio.h now.h datetime.h exit.h \ +quote.h headerbody.h auto_qmail.h newfield.h stralloc.h constmap.h + ./compile qmail-inject.c + +qmail-limits.0: \ +qmail-limits.7 + nroff -man qmail-limits.7 > qmail-limits.0 + +qmail-limits.7: \ +qmail-limits.9 conf-break conf-spawn + cat qmail-limits.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-limits.7 + +qmail-local: \ +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 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 + nroff -man qmail-local.8 > qmail-local.0 + +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 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 + ./load qmail-ldaplookup qldap-ldaplib.o control.o error.a \ + getln.a stralloc.a qldap-debug.o qldap-errno.o check.o fs.a \ + open.a env.a strerr.a substdio.a str.a alloc.a \ + base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \ + auto_qmail.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 compatibility.h digest_md4.h \ +digest_md5.h digest_rmd160.h digest_sha1.h open.h + ./compile $(LDAPFLAGS) $(SHADOWOPTS) qmail-ldaplookup.c + +qmail-lspawn: \ +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 + ./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 \ + 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 $(LDAPLIBS) + +qmail-lspawn.0: \ +qmail-lspawn.8 + nroff -man qmail-lspawn.8 > qmail-lspawn.0 + +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 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 + ./compile $(LDAPFLAGS) $(HDIRMAKE) $(LDAPINCLUDES) qmail-lspawn.c + +qmail-newmrh: \ +load qmail-newmrh.o cdbmss.o getln.a open.a cdbmake.a seek.a case.a \ +stralloc.a alloc.a strerr.a substdio.a error.a str.a auto_qmail.o + ./load qmail-newmrh cdbmss.o getln.a open.a cdbmake.a \ + seek.a case.a stralloc.a alloc.a strerr.a substdio.a \ + error.a str.a auto_qmail.o + +qmail-newmrh.0: \ +qmail-newmrh.8 + nroff -man qmail-newmrh.8 > qmail-newmrh.0 + +qmail-newmrh.8: \ +qmail-newmrh.9 conf-break conf-spawn + cat qmail-newmrh.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-newmrh.8 + +qmail-newmrh.o: \ +compile qmail-newmrh.c strerr.h stralloc.h gen_alloc.h substdio.h \ +getln.h exit.h readwrite.h open.h auto_qmail.h cdbmss.h cdbmake.h \ +uint32.h substdio.h + ./compile qmail-newmrh.c + +qmail-newu: \ +load qmail-newu.o cdbmss.o getln.a open.a seek.a cdbmake.a case.a \ +stralloc.a alloc.a substdio.a error.a str.a auto_qmail.o + ./load qmail-newu cdbmss.o getln.a open.a seek.a cdbmake.a \ + case.a stralloc.a alloc.a substdio.a error.a str.a \ + auto_qmail.o + +qmail-newu.0: \ +qmail-newu.8 + nroff -man qmail-newu.8 > qmail-newu.0 + +qmail-newu.8: \ +qmail-newu.9 conf-break conf-spawn + cat qmail-newu.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-newu.8 + +qmail-newu.o: \ +compile qmail-newu.c stralloc.h gen_alloc.h subfd.h substdio.h \ +getln.h substdio.h cdbmss.h cdbmake.h uint32.h substdio.h exit.h \ +readwrite.h open.h error.h case.h auto_qmail.h + ./compile qmail-newu.c + +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 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 seek.a `cat socket.lib` + +qmail-pop3d.0: \ +qmail-pop3d.8 + nroff -man qmail-pop3d.8 > qmail-pop3d.0 + +qmail-pop3d.o: \ +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 maildir++.h + ./compile $(LDAPFLAGS) $(MNW) $(MDIRMAKE) qmail-pop3d.c + +qmail-popup: \ +load qmail-popup.o commands.o timeoutread.o timeoutwrite.o now.o \ +case.a fd.a sig.a wait.a stralloc.a alloc.a substdio.a error.a str.a \ +fs.a socket.lib + ./load qmail-popup commands.o timeoutread.o timeoutwrite.o \ + now.o case.a fd.a sig.a wait.a stralloc.a alloc.a \ + substdio.a error.a str.a fs.a `cat socket.lib` + +qmail-popup.0: \ +qmail-popup.8 + nroff -man qmail-popup.8 > qmail-popup.0 + +qmail-popup.o: \ +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 $(DEBUG) qmail-popup.c + +qmail-pw2u: \ +load qmail-pw2u.o constmap.o control.o open.a getln.a case.a getopt.a \ +stralloc.a alloc.a substdio.a error.a str.a fs.a auto_usera.o \ +auto_break.o auto_qmail.o + ./load qmail-pw2u constmap.o control.o open.a getln.a \ + case.a getopt.a stralloc.a alloc.a substdio.a error.a str.a \ + fs.a auto_usera.o auto_break.o auto_qmail.o + +qmail-pw2u.0: \ +qmail-pw2u.8 + nroff -man qmail-pw2u.8 > qmail-pw2u.0 + +qmail-pw2u.8: \ +qmail-pw2u.9 conf-break conf-spawn + cat qmail-pw2u.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-pw2u.8 + +qmail-pw2u.o: \ +compile qmail-pw2u.c substdio.h readwrite.h subfd.h substdio.h \ +sgetopt.h subgetopt.h control.h constmap.h stralloc.h gen_alloc.h \ +fmt.h str.h scan.h open.h error.h getln.h auto_break.h auto_qmail.h \ +auto_usera.h + ./compile qmail-pw2u.c + +qmail-qmqpc: \ +load qmail-qmqpc.o 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 socket.lib + ./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 fs.a dns.o str.a ipalloc.o `cat dns.lib` `cat socket.lib` + +qmail-qmqpc.0: \ +qmail-qmqpc.8 + nroff -man qmail-qmqpc.8 > qmail-qmqpc.0 + +qmail-qmqpc.o: \ +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 $(LDAPFLAGS) qmail-qmqpc.c + +qmail-qmqpd: \ +load qmail-qmqpd.o received.o now.o date822fmt.o qmail.o auto_qmail.o \ +env.a substdio.a sig.a error.a wait.a fd.a str.a datetime.a fs.a + ./load qmail-qmqpd received.o now.o date822fmt.o qmail.o \ + auto_qmail.o env.a substdio.a sig.a error.a wait.a fd.a \ + str.a datetime.a fs.a + +qmail-qmqpd.0: \ +qmail-qmqpd.8 + nroff -man qmail-qmqpd.8 > qmail-qmqpd.0 + +qmail-qmqpd.o: \ +compile qmail-qmqpd.c auto_qmail.h qmail.h substdio.h received.h \ +sig.h substdio.h readwrite.h exit.h now.h datetime.h fmt.h env.h + ./compile qmail-qmqpd.c + +qmail-qmtpd: \ +load qmail-qmtpd.o rcpthosts.o control.o constmap.o received.o \ +date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a open.a \ +getln.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a \ +str.a fs.a auto_qmail.o + ./load qmail-qmtpd rcpthosts.o control.o constmap.o \ + received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \ + datetime.a open.a getln.a sig.a case.a env.a stralloc.a \ + alloc.a substdio.a error.a str.a fs.a auto_qmail.o + +qmail-qmtpd.0: \ +qmail-qmtpd.8 + nroff -man qmail-qmtpd.8 > qmail-qmtpd.0 + +qmail-qmtpd.o: \ +compile qmail-qmtpd.c stralloc.h gen_alloc.h substdio.h qmail.h \ +substdio.h now.h datetime.h str.h fmt.h env.h sig.h rcpthosts.h \ +auto_qmail.h readwrite.h control.h received.h + ./compile qmail-qmtpd.c + +qmail-qread: \ +load qmail-qread.o fmtqfn.o readsubdir.o date822fmt.o datetime.a \ +open.a getln.a stralloc.a alloc.a substdio.a error.a str.a fs.a \ +auto_qmail.o auto_split.o + ./load qmail-qread fmtqfn.o readsubdir.o date822fmt.o \ + datetime.a open.a getln.a stralloc.a alloc.a substdio.a \ + error.a str.a fs.a auto_qmail.o auto_split.o + +qmail-qread.0: \ +qmail-qread.8 + nroff -man qmail-qread.8 > qmail-qread.0 + +qmail-qread.o: \ +compile qmail-qread.c stralloc.h gen_alloc.h substdio.h subfd.h \ +substdio.h fmt.h str.h getln.h fmtqfn.h readsubdir.h direntry.h \ +auto_qmail.h open.h datetime.h date822fmt.h readwrite.h error.h \ +exit.h + ./compile qmail-qread.c + +qmail-qstat: \ +warn-auto.sh qmail-qstat.sh conf-qmail conf-break conf-split + cat warn-auto.sh qmail-qstat.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > qmail-qstat + chmod 755 qmail-qstat + +qmail-qstat.0: \ +qmail-qstat.8 + nroff -man qmail-qstat.8 > qmail-qstat.0 + +qmail-queue: \ +load qmail-queue.o triggerpull.o fmtqfn.o now.o date822fmt.o \ +datetime.a seek.a ndelay.a open.a sig.a alloc.a substdio.a error.a \ +str.a fs.a auto_qmail.o auto_split.o auto_uids.o + ./load qmail-queue triggerpull.o fmtqfn.o now.o \ + date822fmt.o datetime.a seek.a ndelay.a open.a sig.a \ + alloc.a substdio.a error.a str.a fs.a auto_qmail.o \ + auto_split.o auto_uids.o + +qmail-queue.0: \ +qmail-queue.8 + nroff -man qmail-queue.8 > qmail-queue.0 + +qmail-queue.o: \ +compile qmail-queue.c readwrite.h sig.h exit.h open.h seek.h fmt.h \ +alloc.h substdio.h datetime.h now.h datetime.h triggerpull.h extra.h \ +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 \ +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 dns.lib socket.lib + ./load qmail-remote control.o constmap.o timeoutread.o \ + 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` ${TLSLIBS} + +qmail-remote.0: \ +qmail-remote.8 + nroff -man qmail-remote.8 > qmail-remote.0 + +qmail-remote.o: \ +compile qmail-remote.c sig.h stralloc.h gen_alloc.h substdio.h \ +subfd.h substdio.h scan.h case.h error.h auto_qmail.h control.h dns.h \ +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 ${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 \ +seek.a lock.a wait.a fd.a stralloc.a alloc.a substdio.a error.a str.a \ +auto_qmail.o auto_uids.o auto_spawn.o + ./load qmail-rspawn spawn.o tcpto_clean.o now.o coe.o \ + sig.a open.a seek.a lock.a wait.a fd.a stralloc.a alloc.a \ + substdio.a error.a str.a auto_qmail.o auto_uids.o \ + auto_spawn.o + +qmail-rspawn.0: \ +qmail-rspawn.8 + nroff -man qmail-rspawn.8 > qmail-rspawn.0 + +qmail-rspawn.o: \ +compile qmail-rspawn.c fd.h wait.h substdio.h exit.h fork.h error.h \ +tcpto.h + ./compile qmail-rspawn.c + +qmail-send: \ +load qmail-send.o qsutil.o control.o constmap.o newfield.o prioq.o \ +trigger.o fmtqfn.o quote.o now.o readsubdir.o qmail.o date822fmt.o \ +datetime.a case.a ndelay.a getln.a wait.a seek.a fd.a sig.a open.a \ +lock.a stralloc.a alloc.a substdio.a error.a str.a fs.a auto_qmail.o \ +auto_split.o + ./load qmail-send qsutil.o control.o constmap.o newfield.o \ + prioq.o trigger.o fmtqfn.o quote.o now.o readsubdir.o \ + qmail.o date822fmt.o datetime.a case.a ndelay.a getln.a \ + wait.a seek.a fd.a sig.a open.a lock.a stralloc.a alloc.a \ + substdio.a error.a str.a fs.a auto_qmail.o auto_split.o + +qmail-send.0: \ +qmail-send.8 + nroff -man qmail-send.8 > qmail-send.0 + +qmail-send.8: \ +qmail-send.9 conf-break conf-spawn + cat qmail-send.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-send.8 + +qmail-send.o: \ +compile qmail-send.c readwrite.h sig.h direntry.h control.h select.h \ +open.h seek.h exit.h lock.h ndelay.h now.h datetime.h getln.h \ +substdio.h alloc.h error.h stralloc.h gen_alloc.h str.h byte.h fmt.h \ +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 $(LDAPFLAGS) qmail-send.c + +qmail-showctl: \ +load qmail-showctl.o auto_uids.o control.o open.a getln.a stralloc.a \ +alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_break.o \ +auto_patrn.o auto_spawn.o auto_split.o + ./load qmail-showctl auto_uids.o control.o open.a getln.a \ + stralloc.a alloc.a substdio.a error.a str.a fs.a \ + auto_qmail.o auto_break.o auto_patrn.o auto_spawn.o \ + auto_split.o + +qmail-showctl.0: \ +qmail-showctl.8 + nroff -man qmail-showctl.8 > qmail-showctl.0 + +qmail-showctl.o: \ +compile qmail-showctl.c substdio.h subfd.h substdio.h exit.h fmt.h \ +str.h control.h constmap.h stralloc.h gen_alloc.h direntry.h \ +auto_uids.h auto_qmail.h auto_break.h auto_patrn.h auto_spawn.h \ +auto_split.h + ./compile qmail-showctl.c + +qmail-smtpd: \ +load qmail-smtpd.o 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 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 fs.a auto_qmail.o dns.o str.a \ + `cat dns.lib` `cat socket.lib` ${TLSLIBS} + +qmail-smtpd.0: \ +qmail-smtpd.8 + nroff -man qmail-smtpd.8 > qmail-smtpd.0 + +qmail-smtpd.o: \ +compile qmail-smtpd.c sig.h readwrite.h stralloc.h gen_alloc.h \ +substdio.h alloc.h auto_qmail.h control.h received.h constmap.h \ +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 ${TLSON} ${TLSINCLUDES} qmail-smtpd.c + +qmail-start: \ +load qmail-start.o prot.o fd.a auto_uids.o + ./load qmail-start prot.o fd.a auto_uids.o + +qmail-start.0: \ +qmail-start.8 + nroff -man qmail-start.8 > qmail-start.0 + +qmail-start.8: \ +qmail-start.9 conf-break conf-spawn + cat qmail-start.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-start.8 + +qmail-start.o: \ +compile qmail-start.c fd.h prot.h exit.h fork.h auto_uids.h + ./compile qmail-start.c + +qmail-tcpok: \ +load qmail-tcpok.o open.a lock.a strerr.a substdio.a error.a str.a \ +auto_qmail.o + ./load qmail-tcpok open.a lock.a strerr.a substdio.a \ + error.a str.a auto_qmail.o + +qmail-tcpok.0: \ +qmail-tcpok.8 + nroff -man qmail-tcpok.8 > qmail-tcpok.0 + +qmail-tcpok.o: \ +compile qmail-tcpok.c strerr.h substdio.h lock.h open.h readwrite.h \ +auto_qmail.h exit.h + ./compile qmail-tcpok.c + +qmail-tcpto: \ +load qmail-tcpto.o ip.o now.o open.a lock.a substdio.a error.a str.a \ +fs.a auto_qmail.o + ./load qmail-tcpto ip.o now.o open.a lock.a substdio.a \ + error.a str.a fs.a auto_qmail.o + +qmail-tcpto.0: \ +qmail-tcpto.8 + nroff -man qmail-tcpto.8 > qmail-tcpto.0 + +qmail-tcpto.o: \ +compile qmail-tcpto.c substdio.h subfd.h substdio.h auto_qmail.h \ +fmt.h ip.h lock.h error.h exit.h datetime.h now.h datetime.h + ./compile qmail-tcpto.c + +qmail-upq: \ +warn-auto.sh qmail-upq.sh conf-qmail conf-break conf-split + cat warn-auto.sh qmail-upq.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > qmail-upq + chmod 755 qmail-upq + +qmail-users.0: \ +qmail-users.5 + nroff -man qmail-users.5 > qmail-users.0 + +qmail-users.5: \ +qmail-users.9 conf-break conf-spawn + cat qmail-users.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-users.5 + +qmail.0: \ +qmail.7 + nroff -man qmail.7 > qmail.0 + +qmail.o: \ +compile qmail.c substdio.h readwrite.h wait.h exit.h fork.h fd.h \ +qmail.h substdio.h auto_qmail.h + ./compile qmail.c + +qreceipt: \ +load qreceipt.o headerbody.o hfield.o quote.o token822.o qmail.o \ +getln.a fd.a wait.a sig.a env.a stralloc.a alloc.a substdio.a error.a \ +str.a auto_qmail.o + ./load qreceipt headerbody.o hfield.o quote.o token822.o \ + qmail.o getln.a fd.a wait.a sig.a env.a stralloc.a alloc.a \ + substdio.a error.a str.a auto_qmail.o + +qreceipt.0: \ +qreceipt.1 + nroff -man qreceipt.1 > qreceipt.0 + +qreceipt.o: \ +compile qreceipt.c sig.h env.h substdio.h stralloc.h gen_alloc.h \ +subfd.h substdio.h getln.h alloc.h str.h hfield.h token822.h \ +gen_alloc.h error.h gen_alloc.h gen_allocdefs.h headerbody.h exit.h \ +open.h quote.h qmail.h substdio.h + ./compile qreceipt.c + +qsmhook: \ +load qsmhook.o sig.a case.a fd.a wait.a getopt.a env.a stralloc.a \ +alloc.a substdio.a error.a str.a + ./load qsmhook sig.a case.a fd.a wait.a getopt.a env.a \ + stralloc.a alloc.a substdio.a error.a str.a + +qsmhook.o: \ +compile qsmhook.c fd.h stralloc.h gen_alloc.h readwrite.h sgetopt.h \ +subgetopt.h wait.h env.h byte.h str.h alloc.h exit.h fork.h case.h \ +subfd.h substdio.h error.h substdio.h sig.h + ./compile qsmhook.c + +qsutil.o: \ +compile qsutil.c stralloc.h gen_alloc.h readwrite.h substdio.h \ +qsutil.h + ./compile qsutil.c + +quote.o: \ +compile quote.c stralloc.h gen_alloc.h str.h quote.h + ./compile quote.c + +rcpthosts.o: \ +compile rcpthosts.c cdb.h uint32.h byte.h open.h error.h control.h \ +constmap.h stralloc.h gen_alloc.h rcpthosts.h + ./compile rcpthosts.c + +readsubdir.o: \ +compile readsubdir.c readsubdir.h direntry.h fmt.h scan.h str.h \ +auto_split.h + ./compile readsubdir.c + +received.o: \ +compile received.c fmt.h qmail.h substdio.h now.h datetime.h \ +datetime.h date822fmt.h received.h + ./compile received.c + +remoteinfo.o: \ +compile remoteinfo.c byte.h substdio.h ip.h fmt.h timeoutconn.h \ +timeoutread.h timeoutwrite.h remoteinfo.h + ./compile remoteinfo.c + +scan_8long.o: \ +compile scan_8long.c scan.h + ./compile scan_8long.c + +scan_ulong.o: \ +compile scan_ulong.c scan.h + ./compile scan_ulong.c + +seek.a: \ +makelib seek_cur.o seek_end.o seek_set.o seek_trunc.o + ./makelib seek.a seek_cur.o seek_end.o seek_set.o \ + seek_trunc.o + +seek_cur.o: \ +compile seek_cur.c seek.h + ./compile seek_cur.c + +seek_end.o: \ +compile seek_end.c seek.h + ./compile seek_end.c + +seek_set.o: \ +compile seek_set.c seek.h + ./compile seek_set.c + +seek_trunc.o: \ +compile seek_trunc.c seek.h + ./compile seek_trunc.c + +select.h: \ +compile trysysel.c select.h1 select.h2 + ( ./compile trysysel.c >/dev/null 2>&1 \ + && cat select.h2 || cat select.h1 ) > select.h + rm -f trysysel.o trysysel + +sendmail: \ +load sendmail.o env.a getopt.a alloc.a substdio.a error.a str.a \ +auto_qmail.o + ./load sendmail env.a getopt.a alloc.a substdio.a error.a \ + str.a auto_qmail.o + +sendmail.o: \ +compile sendmail.c sgetopt.h subgetopt.h substdio.h subfd.h \ +substdio.h alloc.h auto_qmail.h exit.h env.h str.h + ./compile sendmail.c + +setup: \ +it man qldap + ./install + +sgetopt.o: \ +compile sgetopt.c substdio.h subfd.h substdio.h sgetopt.h subgetopt.h \ +subgetopt.h + ./compile sgetopt.c + +shar: \ +FILES BLURB BLURB2 BLURB3 BLURB4 README FAQ INSTALL INSTALL.alias \ +INSTALL.ctl INSTALL.ids INSTALL.maildir INSTALL.mbox INSTALL.vsm \ +REMOVE.sendmail REMOVE.binmail TEST.deliver TEST.receive UPGRADE \ +THOUGHTS TODO THANKS CHANGES SECURITY INTERNALS SENDMAIL \ +PIC.local2alias PIC.local2ext PIC.local2local PIC.local2rem \ +PIC.local2virt PIC.nullclient PIC.relaybad PIC.relaygood \ +PIC.rem2local FILES VERSION SYSDEPS TARGETS Makefile BIN.README \ +BIN.Makefile BIN.setup idedit.c conf-break auto_break.h conf-spawn \ +auto_spawn.h chkspawn.c conf-split auto_split.h conf-patrn \ +auto_patrn.h conf-users conf-groups auto_uids.h auto_usera.h extra.h \ +addresses.5 except.1 bouncesaying.1 condredirect.1 dot-qmail.9 \ +envelopes.5 forgeries.7 forward.1 maildir2mbox.1 maildirmake.1 \ +maildirwatch.1 mailsubj.1 mbox.5 preline.1 qbiff.1 qmail-clean.8 \ +qmail-command.8 qmail-control.9 qmail-getpw.9 qmail-header.5 \ +qmail-inject.8 qmail-limits.9 qmail-local.8 qmail-log.5 \ +qmail-lspawn.8 qmail-newmrh.9 qmail-newu.9 qmail-pop3d.8 \ +qmail-popup.8 qmail-pw2u.9 qmail-qmqpc.8 qmail-qmqpd.8 qmail-qmtpd.8 \ +qmail-qread.8 qmail-qstat.8 qmail-queue.8 qmail-remote.8 \ +qmail-rspawn.8 qmail-send.9 qmail-showctl.8 qmail-smtpd.8 \ +qmail-start.9 qmail-tcpok.8 qmail-tcpto.8 qmail-users.9 qmail.7 \ +qreceipt.1 splogger.8 tcp-env.1 config.sh config-fast.sh \ +qmail-clean.c qmail-getpw.c qmail-inject.c qmail-local.c \ +qmail-lspawn.c qmail-newmrh.c qmail-newu.c qmail-pop3d.c \ +qmail-popup.c qmail-pw2u.c qmail-qmqpc.c qmail-qmqpd.c qmail-qmtpd.c \ +qmail-qread.c qmail-qstat.sh qmail-queue.c qmail-remote.c \ +qmail-rspawn.c qmail-send.c qmail-showctl.c qmail-smtpd.c \ +qmail-start.c qmail-tcpok.c qmail-tcpto.c spawn.c dnscname.c dnsfq.c \ +dnsip.c dnsmxip.c dnsptr.c hostname.c ipmeprint.c tcp-env.c \ +sendmail.c qreceipt.c qsmhook.c qbiff.c forward.c preline.c predate.c \ +except.c bouncesaying.c condredirect.c maildirmake.c maildir2mbox.c \ +maildirwatch.c splogger.c qail.sh elq.sh pinq.sh qmail-upq.sh \ +datemail.sh mailsubj.sh qlx.h rcpthosts.h rcpthosts.c commands.h \ +commands.c dnsdoe.h dnsdoe.c fmtqfn.h fmtqfn.c gfrom.h gfrom.c \ +myctime.h myctime.c newfield.h newfield.c qsutil.h qsutil.c \ +readsubdir.h readsubdir.c received.h received.c tcpto.h tcpto.c \ +tcpto_clean.c trigger.h trigger.c triggerpull.h triggerpull.c \ +trynpbg1.c trysyslog.c conf-cc conf-ld home.sh home+df.sh proc.sh \ +proc+df.sh binm1.sh binm2.sh binm3.sh binm1+df.sh binm2+df.sh \ +binm3+df.sh find-systype.sh make-compile.sh make-load.sh \ +make-makelib.sh trycpp.c warn-auto.sh auto-str.c auto-int.c \ +auto-int8.c auto-gid.c auto-uid.c hier.c install.c instcheck.c \ +install-big.c alloc.3 alloc.h alloc.c alloc_re.c case.3 case.h \ +case_diffb.c case_diffs.c case_lowerb.c case_lowers.c case_starts.c \ +cdb.3 cdb.h cdb_hash.c cdb_seek.c cdb_unpack.c cdbmake.h \ +cdbmake_add.c cdbmake_hash.c cdbmake_pack.c cdbmss.h cdbmss.c coe.3 \ +coe.h coe.c fd.h fd_copy.3 fd_copy.c fd_move.3 fd_move.c fifo_make.3 \ +fifo.h fifo.c trymkffo.c fork.h1 fork.h2 tryvfork.c now.3 now.h now.c \ +open.h open_append.c open_excl.c open_read.c open_trunc.c \ +open_write.c seek.h seek_cur.c seek_end.c seek_set.c seek_trunc.c \ +conf-qmail auto_qmail.h qmail.h qmail.c gen_alloc.h gen_allocdefs.h \ +stralloc.3 stralloc.h stralloc_eady.c stralloc_pend.c stralloc_copy.c \ +stralloc_opyb.c stralloc_opys.c stralloc_cat.c stralloc_catb.c \ +stralloc_cats.c stralloc_arts.c strerr.h strerr_sys.c strerr_die.c \ +substdio.h substdio.c substdi.c substdo.c substdio_copy.c subfd.h \ +subfderr.c subfdouts.c subfdout.c subfdins.c subfdin.c readwrite.h \ +exit.h timeoutconn.h timeoutconn.c timeoutread.h timeoutread.c \ +timeoutwrite.h timeoutwrite.c remoteinfo.h remoteinfo.c uint32.h1 \ +uint32.h2 tryulong32.c wait.3 wait.h wait_pid.c wait_nohang.c \ +trywaitp.c sig.h sig_alarm.c sig_block.c sig_catch.c sig_pause.c \ +sig_pipe.c sig_child.c sig_term.c sig_hup.c sig_misc.c sig_bug.c \ +trysgact.c trysgprm.c env.3 env.h env.c envread.c byte.h byte_chr.c \ +byte_copy.c byte_cr.c byte_diff.c byte_rchr.c byte_zero.c str.h \ +str_chr.c str_cpy.c str_diff.c str_diffn.c str_len.c str_rchr.c \ +str_start.c lock.h lock_ex.c lock_exnb.c lock_un.c tryflock.c getln.3 \ +getln.h getln.c getln2.3 getln2.c sgetopt.3 sgetopt.h sgetopt.c \ +subgetopt.3 subgetopt.h subgetopt.c error.3 error_str.3 error_temp.3 \ +error.h error.c error_str.c error_temp.c fmt.h fmt_str.c fmt_strn.c \ +fmt_uint.c fmt_uint0.c fmt_ulong.c scan.h scan_ulong.c scan_8long.c \ +slurpclose.h slurpclose.c quote.h quote.c hfield.h hfield.c \ +headerbody.h headerbody.c token822.h token822.c control.h control.c \ +datetime.3 datetime.h datetime.c datetime_un.c prioq.h prioq.c \ +date822fmt.h date822fmt.c dns.h dns.c trylsock.c tryrsolv.c ip.h ip.c \ +ipalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h ndelay.c \ +ndelay_off.c direntry.3 direntry.h1 direntry.h2 trydrent.c prot.h \ +prot.c chkshsgr.c warn-shsgr tryshsgr.c ipme.h ipme.c trysalen.c \ +maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c + shar -m `cat FILES` > shar + chmod 400 shar + +sig.a: \ +makelib sig_alarm.o sig_block.o sig_catch.o sig_pause.o sig_pipe.o \ +sig_child.o sig_hup.o sig_term.o sig_bug.o sig_misc.o + ./makelib sig.a sig_alarm.o sig_block.o sig_catch.o \ + sig_pause.o sig_pipe.o sig_child.o sig_hup.o sig_term.o \ + sig_bug.o sig_misc.o + +sig_alarm.o: \ +compile sig_alarm.c sig.h + ./compile sig_alarm.c + +sig_block.o: \ +compile sig_block.c sig.h hassgprm.h + ./compile sig_block.c + +sig_bug.o: \ +compile sig_bug.c sig.h + ./compile sig_bug.c + +sig_catch.o: \ +compile sig_catch.c sig.h hassgact.h + ./compile sig_catch.c + +sig_child.o: \ +compile sig_child.c sig.h + ./compile sig_child.c + +sig_hup.o: \ +compile sig_hup.c sig.h + ./compile sig_hup.c + +sig_misc.o: \ +compile sig_misc.c sig.h + ./compile sig_misc.c + +sig_pause.o: \ +compile sig_pause.c sig.h hassgprm.h + ./compile sig_pause.c + +sig_pipe.o: \ +compile sig_pipe.c sig.h + ./compile sig_pipe.c + +sig_term.o: \ +compile sig_term.c sig.h + ./compile sig_term.c + +slurpclose.o: \ +compile slurpclose.c stralloc.h gen_alloc.h readwrite.h slurpclose.h \ +error.h + ./compile slurpclose.c + +socket.lib: \ +trylsock.c compile load + ( ( ./compile trylsock.c && \ + ./load trylsock -lsocket -lnsl ) >/dev/null 2>&1 \ + && echo -lsocket -lnsl || exit 0 ) > socket.lib + rm -f trylsock.o trylsock + +spawn.o: \ +compile chkspawn spawn.c sig.h wait.h substdio.h byte.h str.h \ +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 + +splogger: \ +load splogger.o substdio.a error.a str.a fs.a syslog.lib socket.lib + ./load splogger substdio.a error.a str.a fs.a `cat \ + syslog.lib` `cat socket.lib` + +splogger.0: \ +splogger.8 + nroff -man splogger.8 > splogger.0 + +splogger.o: \ +compile splogger.c error.h substdio.h subfd.h substdio.h exit.h str.h \ +scan.h fmt.h + ./compile splogger.c + +str.a: \ +makelib str_len.o str_diff.o str_diffn.o str_cpy.o str_chr.o \ +str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_diff.o byte_copy.o \ +byte_cr.o byte_zero.o + ./makelib str.a str_len.o str_diff.o str_diffn.o str_cpy.o \ + str_chr.o str_rchr.o str_start.o byte_chr.o byte_rchr.o \ + byte_diff.o byte_copy.o byte_cr.o byte_zero.o + +str_chr.o: \ +compile str_chr.c str.h + ./compile str_chr.c + +str_cpy.o: \ +compile str_cpy.c str.h + ./compile str_cpy.c + +str_diff.o: \ +compile str_diff.c str.h + ./compile str_diff.c + +str_diffn.o: \ +compile str_diffn.c str.h + ./compile str_diffn.c + +str_len.o: \ +compile str_len.c str.h + ./compile str_len.c + +str_rchr.o: \ +compile str_rchr.c str.h + ./compile str_rchr.c + +str_start.o: \ +compile str_start.c str.h + ./compile str_start.c + +stralloc.a: \ +makelib stralloc_eady.o stralloc_pend.o stralloc_copy.o \ +stralloc_opys.o stralloc_opyb.o stralloc_cat.o stralloc_cats.o \ +stralloc_catb.o stralloc_arts.o + ./makelib stralloc.a stralloc_eady.o stralloc_pend.o \ + stralloc_copy.o stralloc_opys.o stralloc_opyb.o \ + stralloc_cat.o stralloc_cats.o stralloc_catb.o \ + stralloc_arts.o + +stralloc_arts.o: \ +compile stralloc_arts.c byte.h str.h stralloc.h gen_alloc.h + ./compile stralloc_arts.c + +stralloc_cat.o: \ +compile stralloc_cat.c byte.h stralloc.h gen_alloc.h + ./compile stralloc_cat.c + +stralloc_catb.o: \ +compile stralloc_catb.c stralloc.h gen_alloc.h byte.h + ./compile stralloc_catb.c + +stralloc_cats.o: \ +compile stralloc_cats.c byte.h str.h stralloc.h gen_alloc.h + ./compile stralloc_cats.c + +stralloc_copy.o: \ +compile stralloc_copy.c byte.h stralloc.h gen_alloc.h + ./compile stralloc_copy.c + +stralloc_eady.o: \ +compile stralloc_eady.c alloc.h stralloc.h gen_alloc.h \ +gen_allocdefs.h + ./compile stralloc_eady.c + +stralloc_opyb.o: \ +compile stralloc_opyb.c stralloc.h gen_alloc.h byte.h + ./compile stralloc_opyb.c + +stralloc_opys.o: \ +compile stralloc_opys.c byte.h str.h stralloc.h gen_alloc.h + ./compile stralloc_opys.c + +stralloc_pend.o: \ +compile stralloc_pend.c alloc.h stralloc.h gen_alloc.h \ +gen_allocdefs.h + ./compile stralloc_pend.c + +strerr.a: \ +makelib strerr_sys.o strerr_die.o + ./makelib strerr.a strerr_sys.o strerr_die.o + +strerr_die.o: \ +compile strerr_die.c substdio.h subfd.h substdio.h exit.h strerr.h + ./compile strerr_die.c + +strerr_sys.o: \ +compile strerr_sys.c error.h strerr.h + ./compile strerr_sys.c + +subfderr.o: \ +compile subfderr.c readwrite.h substdio.h subfd.h substdio.h + ./compile subfderr.c + +subfdin.o: \ +compile subfdin.c readwrite.h substdio.h subfd.h substdio.h + ./compile subfdin.c + +subfdins.o: \ +compile subfdins.c readwrite.h substdio.h subfd.h substdio.h + ./compile subfdins.c + +subfdout.o: \ +compile subfdout.c readwrite.h substdio.h subfd.h substdio.h + ./compile subfdout.c + +subfdouts.o: \ +compile subfdouts.c readwrite.h substdio.h subfd.h substdio.h + ./compile subfdouts.c + +subgetopt.o: \ +compile subgetopt.c subgetopt.h + ./compile subgetopt.c + +substdi.o: \ +compile substdi.c substdio.h byte.h error.h + ./compile substdi.c + +substdio.a: \ +makelib substdio.o substdi.o substdo.o subfderr.o subfdout.o \ +subfdouts.o subfdin.o subfdins.o substdio_copy.o + ./makelib substdio.a substdio.o substdi.o substdo.o \ + subfderr.o subfdout.o subfdouts.o subfdin.o subfdins.o \ + substdio_copy.o + +substdio.o: \ +compile substdio.c substdio.h + ./compile substdio.c + +substdio_copy.o: \ +compile substdio_copy.c substdio.h + ./compile substdio_copy.c + +substdo.o: \ +compile substdo.c substdio.h str.h byte.h error.h + ./compile substdo.c + +syslog.lib: \ +trysyslog.c compile load + ( ( ./compile trysyslog.c && \ + ./load trysyslog -lgen ) >/dev/null 2>&1 \ + && echo -lgen || exit 0 ) > syslog.lib + rm -f trysyslog.o trysyslog + +systype: \ +find-systype trycpp.c + ./find-systype > systype + +tcp-env: \ +load tcp-env.o dns.o remoteinfo.o timeoutread.o timeoutwrite.o \ +timeoutconn.o ip.o ipalloc.o case.a ndelay.a sig.a env.a getopt.a \ +stralloc.a alloc.a substdio.a error.a str.a fs.a dns.lib socket.lib + ./load tcp-env dns.o remoteinfo.o timeoutread.o \ + timeoutwrite.o timeoutconn.o ip.o ipalloc.o case.a ndelay.a \ + sig.a env.a getopt.a stralloc.a alloc.a substdio.a error.a \ + str.a fs.a `cat dns.lib` `cat socket.lib` + +tcp-env.0: \ +tcp-env.1 + nroff -man tcp-env.1 > tcp-env.0 + +tcp-env.o: \ +compile tcp-env.c sig.h stralloc.h gen_alloc.h str.h env.h fmt.h \ +scan.h subgetopt.h ip.h dns.h byte.h remoteinfo.h exit.h case.h + ./compile tcp-env.c + +tcp-environ.0: \ +tcp-environ.5 + nroff -man tcp-environ.5 > tcp-environ.0 + +tcpto.o: \ +compile tcpto.c tcpto.h open.h lock.h seek.h now.h datetime.h ip.h \ +byte.h datetime.h readwrite.h + ./compile tcpto.c + +tcpto_clean.o: \ +compile tcpto_clean.c tcpto.h open.h substdio.h readwrite.h + ./compile tcpto_clean.c + +timeoutconn.o: \ +compile timeoutconn.c ndelay.h select.h error.h readwrite.h ip.h \ +byte.h timeoutconn.h + ./compile timeoutconn.c + +timeoutread.o: \ +compile timeoutread.c timeoutread.h select.h error.h readwrite.h + ./compile timeoutread.c + +timeoutwrite.o: \ +compile timeoutwrite.c timeoutwrite.h select.h error.h readwrite.h + ./compile timeoutwrite.c + +token822.o: \ +compile token822.c stralloc.h gen_alloc.h alloc.h str.h token822.h \ +gen_alloc.h gen_allocdefs.h + ./compile token822.c + +trigger.o: \ +compile trigger.c select.h open.h trigger.h hasnpbg1.h + ./compile trigger.c + +triggerpull.o: \ +compile triggerpull.c ndelay.h open.h triggerpull.h + ./compile triggerpull.c + +uint32.h: \ +tryulong32.c compile load uint32.h1 uint32.h2 + ( ( ./compile tryulong32.c && ./load tryulong32 && \ + ./tryulong32 ) >/dev/null 2>&1 \ + && cat uint32.h2 || cat uint32.h1 ) > uint32.h + rm -f tryulong32.o tryulong32 + +wait.a: \ +makelib wait_pid.o wait_nohang.o + ./makelib wait.a wait_pid.o wait_nohang.o + +wait_nohang.o: \ +compile wait_nohang.c haswaitp.h + ./compile wait_nohang.c + +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 -u -N qmail-1.03-orig/QLDAPINSTALL test/QLDAPINSTALL --- qmail-1.03-orig/QLDAPINSTALL Thu Jan 1 01:00:00 1970 +++ test/QLDAPINSTALL Thu Mar 1 23:58:55 2001 @@ -0,0 +1,702 @@ +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/03/01 20:20:07 $) + +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 + BUGS & PROBLEMS How to help us helping you + +TODO: + + see QLDAPTODO + +NEWS: + + see QLDAPNEWS + +IMPORTANT NEWS: + + new check algorithm (see QLDAPNEWS) + + new mailMessageStore/homedirectory handling (see QLDAPNEWS) + +================================================================================ + +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) + 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 man ld or man gcc. + - 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. + +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 + +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 DEBUGLEVEL environment + variable (e.g. with env, env DEBUGLEVEL=3 qmail-start ...) + There are these DEBUGLEVELs: + DEBUGLEVEL=1 -> Errors + DEBUGLEVEL=2 -> Warnings + DEBUGLEVEL=4 -> Info + DEBUGLEVEL=8 -> Info^2 + DEBUGLEVEL=16 -> Debug + DEBUGLEVEL=32 -> Debug^2 + DEBUGLEVEL=64 -> LDAP Debug + DEBUGLEVEL=128 -> LDAP Debug^2 + DEBUGLEVEL=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 DEBUGLEVEL is compare with a bit mask, so that + DEBUGLEVEL=3 will report warnings and errors but DEBUGLEVEL=2 will + only report warnings. + +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 uses + 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 you IMAP server can use a 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. + 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 + Required + Example: ldap.nrg4u.com ldap2.nrg4u.com + +~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/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: rbl.maps.vix.com + Note: Multiline. To activate RBL checks you have to set RBL 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 without control file: + +DEBUGLEVEL + + Level of log verbosity in qmail-lspawn, auth_* + Default: none (0) + LEVELS: + DEBUGLEVEL=1 -> Errors + DEBUGLEVEL=2 -> Warnings + DEBUGLEVEL=4 -> Info + DEBUGLEVEL=8 -> Info^2 + DEBUGLEVEL=16 -> Debug + DEBUGLEVEL=32 -> Debug^2 + DEBUGLEVEL=64 -> LDAP Debug + DEBUGLEVEL=128 -> LDAP Debug^2 + DEBUGLEVEL=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 DEBUGLEVEL is compare with a bit mask, so that + DEBUGLEVEL=3 will report warnings and errors but DEBUGLEVEL=2 will + only report warnings. + +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 + +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 + +================================================================================ + +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) + Default: no accountStatus is equal to active. + + +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 + + +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 + +================================================================================ + +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. + +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 DEBUGLEVEL 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 -u -N qmail-1.03-orig/QLDAPNEWS test/QLDAPNEWS --- qmail-1.03-orig/QLDAPNEWS Thu Jan 1 01:00:00 1970 +++ test/QLDAPNEWS Thu Mar 1 23:58:55 2001 @@ -0,0 +1,359 @@ +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/03/01 20:20:08 $ ($Revision: 1.34 $) + + +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 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 -u -N qmail-1.03-orig/QLDAPPICTURE test/QLDAPPICTURE --- qmail-1.03-orig/QLDAPPICTURE Thu Jan 1 01:00:00 1970 +++ test/QLDAPPICTURE Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/QLDAPTODO test/QLDAPTODO --- qmail-1.03-orig/QLDAPTODO Thu Jan 1 01:00:00 1970 +++ test/QLDAPTODO Thu Mar 1 23:58:55 2001 @@ -0,0 +1,41 @@ +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/03/01 20:20:08 $ ($Revision: 1.14 $) + +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 ???) +- benchmarking the code +- enhancement to debug code +- test what happens if only uid and mail is defiend in ldap or similar uncommon + cases +- clean up and strip of the digest_*.c files so that it get more platform + independent. Target is to remove the "ugly" compatibility.h +- make the complete lookup code modular so that it should be possible to add + diffrent backends or use a "caching" server to accelerate lookups. + 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) + diff -u -N qmail-1.03-orig/TARGETS test/TARGETS --- qmail-1.03-orig/TARGETS Mon Jun 15 12:53:16 1998 +++ test/TARGETS Thu Mar 1 23:58:55 2001 @@ -385,3 +385,31 @@ 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 diff -u -N qmail-1.03-orig/TARGETS.orig test/TARGETS.orig --- qmail-1.03-orig/TARGETS.orig Thu Jan 1 01:00:00 1970 +++ test/TARGETS.orig Thu Mar 1 23:58:55 2001 @@ -0,0 +1,387 @@ +auto-ccld.sh +make-load +find-systype +systype +load +make-compile +compile +fork.h +qmail-local.o +qmail.o +quote.o +now.o +gfrom.o +myctime.o +slurpclose.o +make-makelib +makelib +case_diffb.o +case_diffs.o +case_lowerb.o +case_lowers.o +case_starts.o +case.a +getln.o +getln2.o +getln.a +subgetopt.o +sgetopt.o +getopt.a +sig_alarm.o +hassgprm.h +sig_block.o +hassgact.h +sig_catch.o +sig_pause.o +sig_pipe.o +sig_child.o +sig_hup.o +sig_term.o +sig_bug.o +sig_misc.o +sig.a +open_append.o +open_excl.o +open_read.o +open_trunc.o +open_write.o +open.a +seek_cur.o +seek_end.o +seek_set.o +seek_trunc.o +seek.a +hasflock.h +lock_ex.o +lock_exnb.o +lock_un.o +lock.a +fd_copy.o +fd_move.o +fd.a +haswaitp.h +wait_pid.o +wait_nohang.o +wait.a +env.o +envread.o +env.a +stralloc_eady.o +stralloc_pend.o +stralloc_copy.o +stralloc_opys.o +stralloc_opyb.o +stralloc_cat.o +stralloc_cats.o +stralloc_catb.o +stralloc_arts.o +stralloc.a +alloc.o +alloc_re.o +alloc.a +strerr_sys.o +strerr_die.o +strerr.a +substdio.o +substdi.o +substdo.o +subfderr.o +subfdout.o +subfdouts.o +subfdin.o +subfdins.o +substdio_copy.o +substdio.a +error.o +error_str.o +error_temp.o +error.a +str_len.o +str_diff.o +str_diffn.o +str_cpy.o +str_chr.o +str_rchr.o +str_start.o +byte_chr.o +byte_rchr.o +byte_diff.o +byte_copy.o +byte_cr.o +byte_zero.o +str.a +fmt_str.o +fmt_strn.o +fmt_uint.o +fmt_uint0.o +fmt_ulong.o +scan_ulong.o +scan_8long.o +fs.a +datetime.o +datetime_un.o +datetime.a +auto-str.o +auto-str +auto_qmail.c +auto_qmail.o +auto-int8.o +auto-int8 +auto_patrn.c +auto_patrn.o +socket.lib +qmail-local +uint32.h +qmail-lspawn.o +select.h +chkspawn.o +auto-int.o +auto-int +auto_spawn.c +auto_spawn.o +chkspawn +spawn.o +chkshsgr.o +chkshsgr +hasshsgr.h +prot.o +coe.o +cdb_hash.o +cdb_unpack.o +cdb_seek.o +cdb.a +auto-uid.o +auto-uid +auto-gid.o +auto-gid +auto_uids.c +auto_uids.o +qmail-lspawn +qmail-getpw.o +auto_break.c +auto_break.o +auto_usera.c +auto_usera.o +qmail-getpw +qmail-remote.o +control.o +constmap.o +timeoutread.o +timeoutwrite.o +timeoutconn.o +tcpto.o +dns.o +ip.o +ipalloc.o +hassalen.h +ipme.o +ndelay.o +ndelay_off.o +ndelay.a +dns.lib +qmail-remote +qmail-rspawn.o +tcpto_clean.o +qmail-rspawn +direntry.h +qmail-clean.o +fmtqfn.o +auto_split.c +auto_split.o +qmail-clean +qmail-send.o +qsutil.o +newfield.o +prioq.o +hasmkffo.h +fifo.o +hasnpbg1.h +trigger.o +readsubdir.o +date822fmt.o +qmail-send +qmail-start.o +qmail-start +splogger.o +syslog.lib +splogger +qmail-queue.o +triggerpull.o +qmail-queue +qmail-inject.o +headerbody.o +hfield.o +token822.o +qmail-inject +predate.o +predate +datemail +mailsubj +qmail-upq +qmail-showctl.o +qmail-showctl +qmail-newu.o +cdbmss.o +cdbmake_pack.o +cdbmake_hash.o +cdbmake_add.o +cdbmake.a +qmail-newu +qmail-pw2u.o +qmail-pw2u +qmail-qread.o +qmail-qread +qmail-qstat +qmail-tcpto.o +qmail-tcpto +qmail-tcpok.o +qmail-tcpok +qmail-pop3d.o +commands.o +maildir.o +qmail-pop3d +qmail-popup.o +qmail-popup +qmail-qmqpc.o +qmail-qmqpc +qmail-qmqpd.o +received.o +qmail-qmqpd +qmail-qmtpd.o +rcpthosts.o +qmail-qmtpd +qmail-smtpd.o +qmail-smtpd +sendmail.o +sendmail +tcp-env.o +remoteinfo.o +tcp-env +qmail-newmrh.o +qmail-newmrh +config +config-fast +dnscname.o +dnsdoe.o +dnscname +dnsptr.o +dnsptr +dnsip.o +dnsip +dnsmxip.o +dnsmxip +dnsfq.o +dnsfq +hostname.o +hostname +ipmeprint.o +ipmeprint +qreceipt.o +qreceipt +qsmhook.o +qsmhook +qbiff.o +qbiff +forward.o +forward +preline.o +preline +condredirect.o +condredirect +bouncesaying.o +bouncesaying +except.o +except +maildirmake.o +maildirmake +maildir2mbox.o +maildir2mbox +maildirwatch.o +maildirwatch +qail +elq +pinq +idedit.o +idedit +install-big.o +install.o +install-big +hier.o +install +instcheck.o +instcheck +home +home+df +proc +proc+df +binm1 +binm1+df +binm2 +binm2+df +binm3 +binm3+df +it +qmail-local.0 +qmail-lspawn.0 +qmail-getpw.8 +qmail-getpw.0 +qmail-remote.0 +qmail-rspawn.0 +qmail-clean.0 +qmail-send.8 +qmail-send.0 +qmail-start.8 +qmail-start.0 +splogger.0 +qmail-queue.0 +qmail-inject.0 +mailsubj.0 +qmail-showctl.0 +qmail-newu.8 +qmail-newu.0 +qmail-pw2u.8 +qmail-pw2u.0 +qmail-qread.0 +qmail-qstat.0 +qmail-tcpto.0 +qmail-tcpok.0 +qmail-pop3d.0 +qmail-popup.0 +qmail-qmqpc.0 +qmail-qmqpd.0 +qmail-qmtpd.0 +qmail-smtpd.0 +tcp-env.0 +qmail-newmrh.8 +qmail-newmrh.0 +qreceipt.0 +qbiff.0 +forward.0 +preline.0 +condredirect.0 +bouncesaying.0 +except.0 +maildirmake.0 +maildir2mbox.0 +maildirwatch.0 +qmail.0 +qmail-limits.7 +qmail-limits.0 +qmail-log.0 +qmail-control.5 +qmail-control.0 +qmail-header.0 +qmail-users.5 +qmail-users.0 +dot-qmail.5 +dot-qmail.0 +qmail-command.0 +tcp-environ.0 +maildir.0 +mbox.0 +addresses.0 +envelopes.0 +forgeries.0 +man +setup +check diff -u -N qmail-1.03-orig/TLS.readme test/TLS.readme --- qmail-1.03-orig/TLS.readme Thu Jan 1 01:00:00 1970 +++ test/TLS.readme Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/auth_imap.c test/auth_imap.c --- qmail-1.03-orig/auth_imap.c Thu Jan 1 01:00:00 1970 +++ test/auth_imap.c Thu Mar 1 23:58:55 2001 @@ -0,0 +1,448 @@ +/* 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" +#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 */ + debug(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; + + debug(2, "warning: auth_fail: user %s failed\n", login); + if ( qldap_errno == AUTH_NOSUCH ) { + debug(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 ) { + debug(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 ) { + debug(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(); + } + debug(32, "auth_success: setgid succeeded (%i)\n", gid); + /* ... then the user id */ + if (prot_uid(uid) == -1) { + qldap_errno = AUTH_ERROR; + auth_error(); + } + debug(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; + + debug(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 ) { + debug(2, "warning: auth_success: dirmaker failed (%s)\n", + error_str(errno)); + } else { + debug(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) { + debug(2, "warning: auth_success: chdir failed after dirmaker (%s)\n", + error_str(errno)); + qldap_errno = MAILDIR_CORRUPT; + auth_error(); + } + debug(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(); + } + } + + debug(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 */ + + debug(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(); +} + +static int allwrite(op,fd,buf,len) +/* copied from substdo.c */ +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + register int w; + + while (len) { + w = op(fd,buf,len); + if (w == -1) { + if (errno == error_intr) continue; + return -1; /* note that some data may have been written */ + } + if (w == 0) ; /* luser's fault */ + buf += w; + len -= w; + } + return 0; +} + +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"); + + if ( !( tag && *tag ) ) { + /* UH OH, no imap tag, how could that be ? */ + qldap_errno = AUTH_PANIC; + auth_error(); + } + + get_ok(fd, "*"); + allwrite(write, fd, tag, str_len(tag) ); + allwrite(write, fd, " login ", 7); + allwrite(write, fd, login, str_len(login) ); + allwrite(write, fd, " ", 1); + allwrite(write, fd, passwd, str_len(passwd) ); + allwrite(write, fd, "\n\r",1); + +} + +#endif /* QLDAP_CLUSTER */ + diff -u -N qmail-1.03-orig/auth_mod.h test/auth_mod.h --- qmail-1.03-orig/auth_mod.h Thu Jan 1 01:00:00 1970 +++ test/auth_mod.h Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/auth_pop.c test/auth_pop.c --- qmail-1.03-orig/auth_pop.c Thu Jan 1 01:00:00 1970 +++ test/auth_pop.c Thu Mar 1 23:59:20 2001 @@ -0,0 +1,362 @@ +/* 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" +#ifdef AUTOHOMEDIRMAKE +#include "qldap-mdm.h" +#endif +#ifdef SMTP_AFTER_POP +#include +#include + +int child; +int wstat; +char *opensmtp = "/usr/local/bin/pop3-record"; +#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 ) { + debug(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 ) { + debug(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(); + } + +#ifdef SMTP_AFTER_POP + if (!env_put2("AUTHUSER",login)) { + qldap_errno = ERRNO; + auth_error(); + } + + switch(child = fork()) { + case -1: _exit(111); break; + case 0: execl(opensmtp, opensmtp, 0); _exit(111); break; + } + waitpid(child, &wstat, 0); + if (!WIFEXITED(wstat)) _exit(111); +#endif + + /* first set the group id */ + if (prot_gid(gid) == -1) { + qldap_errno = AUTH_ERROR; + auth_error(); + } + debug(32, "auth_success: setgid succeeded (%i)\n", gid); + /* ... then the user id */ + if (prot_uid(uid) == -1) { + qldap_errno = AUTH_ERROR; + auth_error(); + } + debug(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; + + debug(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 ) { + debug(2, "warning: auth_success: dirmaker failed (%s)\n", + error_str(errno)); + } else { + debug(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) { + debug(2, + "warning: auth_success: chdir failed after dirmaker (%s)\n", + error_str(errno)); + qldap_errno = MAILDIR_CORRUPT; + auth_error(); + } + debug(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(); + } + } + + debug(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 + */ + debug(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(); +} + +static int allwrite(op,fd,buf,len) +/* copied from substdo.c */ +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + register int w; + + while (len) { + w = op(fd,buf,len); + if (w == -1) { + if (errno == error_intr) continue; + return -1; /* note that some data may have been written */ + } + if (w == 0) ; /* luser's fault */ + buf += w; + len -= w; + } + return 0; +} + +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 */ +{ + get_ok(fd); + allwrite(write, fd, "user ", 5); + allwrite(write, fd, login, str_len(login) ); + allwrite(write, fd, "\n\r", 1); + get_ok(fd); + allwrite(write, fd, "pass ", 5); + allwrite(write, fd, passwd, str_len(passwd) ); + allwrite(write, fd, "\n\r",1); + +} + +#endif /* QLDAP_CLUSTER */ + diff -u -N qmail-1.03-orig/auth_pop.c.orig test/auth_pop.c.orig --- qmail-1.03-orig/auth_pop.c.orig Thu Jan 1 01:00:00 1970 +++ test/auth_pop.c.orig Thu Mar 1 23:58:55 2001 @@ -0,0 +1,340 @@ +/* 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" +#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 ) { + debug(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 ) { + debug(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(); + } + debug(32, "auth_success: setgid succeeded (%i)\n", gid); + /* ... then the user id */ + if (prot_uid(uid) == -1) { + qldap_errno = AUTH_ERROR; + auth_error(); + } + debug(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; + + debug(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 ) { + debug(2, "warning: auth_success: dirmaker failed (%s)\n", + error_str(errno)); + } else { + debug(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) { + debug(2, + "warning: auth_success: chdir failed after dirmaker (%s)\n", + error_str(errno)); + qldap_errno = MAILDIR_CORRUPT; + auth_error(); + } + debug(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(); + } + } + + debug(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 + */ + debug(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(); +} + +static int allwrite(op,fd,buf,len) +/* copied from substdo.c */ +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + register int w; + + while (len) { + w = op(fd,buf,len); + if (w == -1) { + if (errno == error_intr) continue; + return -1; /* note that some data may have been written */ + } + if (w == 0) ; /* luser's fault */ + buf += w; + len -= w; + } + return 0; +} + +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 */ +{ + get_ok(fd); + allwrite(write, fd, "user ", 5); + allwrite(write, fd, login, str_len(login) ); + allwrite(write, fd, "\n\r", 1); + get_ok(fd); + allwrite(write, fd, "pass ", 5); + allwrite(write, fd, passwd, str_len(passwd) ); + allwrite(write, fd, "\n\r",1); + +} + +#endif /* QLDAP_CLUSTER */ + diff -u -N qmail-1.03-orig/base64.c test/base64.c --- qmail-1.03-orig/base64.c Thu Jan 1 01:00:00 1970 +++ test/base64.c Thu Mar 1 23:58:55 2001 @@ -0,0 +1,319 @@ +/* base64.c for QLDAP checkpassword.c */ + +/* */ +/* 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 + #include +*/ +#include +/* #include */ +#ifndef NULL +#define NULL (void*) 0 +#endif + +#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) + u_char const *src; + size_t srclength; + char *target; + size_t targsize; +{ + size_t datalength = 0; + u_char input[3]; + u_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. + */ + +int +b64_pton(src, target, targsize) + char const *src; + u_char *target; + size_t targsize; +{ + int tarindex, state, ch; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + 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 -u -N qmail-1.03-orig/base64.h test/base64.h --- qmail-1.03-orig/base64.h Thu Jan 1 01:00:00 1970 +++ test/base64.h Thu Mar 1 23:58:55 2001 @@ -0,0 +1,9 @@ +/* base64.h for QLDAP checkpassword.c */ + +/* */ +/* BASE64 */ +/* */ + +int b64_ntop(u_char const *, size_t, char *, size_t); +int b64_pton(char const *, u_char *, size_t); + diff -u -N qmail-1.03-orig/check.c test/check.c --- qmail-1.03-orig/check.c Thu Jan 1 01:00:00 1970 +++ test/check.c Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/check.h test/check.h --- qmail-1.03-orig/check.h Thu Jan 1 01:00:00 1970 +++ test/check.h Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/checkpassword.c test/checkpassword.c --- qmail-1.03-orig/checkpassword.c Thu Jan 1 01:00:00 1970 +++ test/checkpassword.c Thu Mar 1 23:58:55 2001 @@ -0,0 +1,619 @@ +/* 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 "compatibility.h" +#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" + +/* 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 +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; + + init_debug(STDERR, 255); /* XXX limited to 64 so it is not possible to get + * XXX passwords via debug on normal systems */ + + auth_init(argc, argv, &login, &authdata); + debug(256, "auth_init: login=%s, authdata=%s\n", login.s, authdata.s); + + if ( init_ldap(&locald, &cluster, &rebind, &homemaker, 0, 0, 0) == -1 ) { + debug(1, "alert: init_ldap failed.\n"); + _exit(1); + } + debug(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) ) { + debug(16, "authentication with ldap was not successful\n"); + if ( locald == 1 && + (qldap_errno == LDAP_NOSUCH || qldap_errno == LDAP_SEARCH) ) { + debug(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 */ + debug(4, "warning: check_ldap: could not make a filter\n"); + /* qldap_errno set by make_filter */ + return -1; + } + search.filter = filter.s; + + ret = ldap_lookup(&search, attrs, &info, extra); + free_stralloc(&filter); /* free the old filter */ + if ( ret != 0 ) { + debug(4, "warning: check_ldap: ldap_lookup not successful!\n"); + /* qldap_errno set by ldap_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) ) { + /* hostname is different, so I reconnect */ + debug(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) ) { + debug(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) ) { + debug(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 ) { + debug(32, + "check_ldap: ldap_lookup sucessfully authenticated with rebind\n"); + return 0; + /* if we got till here under rebind mode, the user is authenticated */ + } else if ( rebind ) { + debug(32, + "check_ldap: ldap_lookup authentication failed with rebind\n"); + qldap_errno = AUTH_FAILED; + return -1; /* user authentification failed */ + } + + if ( ! extra[0].vals ) { + debug(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]); + debug(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 */ + debug(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; + } + debug(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 */ + debug(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; + ns_mta_hash_alg(hashed, salt, (char *) clear); + 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 */ + debug(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 */ + debug(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(); + } + + 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 -u -N qmail-1.03-orig/chkspawn.c test/chkspawn.c --- qmail-1.03-orig/chkspawn.c Mon Jun 15 12:53:16 1998 +++ test/chkspawn.c Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/chkspawn.c.orig test/chkspawn.c.orig --- qmail-1.03-orig/chkspawn.c.orig Thu Jan 1 01:00:00 1970 +++ test/chkspawn.c.orig Thu Mar 1 23:58:55 2001 @@ -0,0 +1,48 @@ +#include "substdio.h" +#include "subfd.h" +#include "fmt.h" +#include "select.h" +#include "exit.h" +#include "auto_spawn.h" + +char num[FMT_ULONG]; +fd_set fds; + +void main() +{ + unsigned long hiddenlimit; + unsigned long maxnumd; + + hiddenlimit = sizeof(fds) * 8; + maxnumd = (hiddenlimit - 5) / 2; + + if (auto_spawn < 1) { + substdio_puts(subfderr,"Oops. You have set conf-spawn lower than 1.\n"); + substdio_flush(subfderr); + _exit(1); + } + + if (auto_spawn > 255) { + substdio_puts(subfderr,"Oops. You have set conf-spawn higher than 255.\n"); + substdio_flush(subfderr); + _exit(1); + } + + if (auto_spawn > maxnumd) { + substdio_puts(subfderr,"Oops. Your system's FD_SET() has a hidden limit of "); + substdio_put(subfderr,num,fmt_ulong(num,hiddenlimit)); + substdio_puts(subfderr," descriptors.\n\ +This means that the qmail daemons could crash if you set the run-time\n\ +concurrency higher than "); + substdio_put(subfderr,num,fmt_ulong(num,maxnumd)); + substdio_puts(subfderr,". So I'm going to insist that the concurrency\n\ +limit in conf-spawn be at most "); + substdio_put(subfderr,num,fmt_ulong(num,maxnumd)); + substdio_puts(subfderr,". Right now it's "); + substdio_put(subfderr,num,fmt_ulong(num,(unsigned long) auto_spawn)); + substdio_puts(subfderr,".\n"); + substdio_flush(subfderr); + _exit(1); + } + _exit(0); +} diff -u -N qmail-1.03-orig/compatibility.h test/compatibility.h --- qmail-1.03-orig/compatibility.h Thu Jan 1 01:00:00 1970 +++ test/compatibility.h Thu Mar 1 23:58:55 2001 @@ -0,0 +1,28 @@ +#ifndef __COMPATIBILITY_H__ +#define __COMPATIBILITY_H__ + +/* compatibility.h a compatibility include for the qmail-ldap checkpasword * + * implementation. These nasty little differences of U*NXes are driving me nuts */ + + +#ifndef __P +# ifdef __STDC__ +# define __P(p) p +# else +# define __P(p) () +# endif +#endif + + +#ifdef sun /* some special treatments for SunOSes :-( */ + +#include + +/* typedef uint32_t u_int32_t; + typedef uint64_t u_int64_t; */ +typedef u_longlong_t u_int64_t; +typedef unsigned int u_int32_t; + +#endif + +#endif diff -u -N qmail-1.03-orig/conf-spawn test/conf-spawn --- qmail-1.03-orig/conf-spawn Mon Jun 15 12:53:16 1998 +++ test/conf-spawn Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/conf-spawn.orig test/conf-spawn.orig --- qmail-1.03-orig/conf-spawn.orig Thu Jan 1 01:00:00 1970 +++ test/conf-spawn.orig Thu Mar 1 23:58:55 2001 @@ -0,0 +1,5 @@ +120 + +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 +limit is too high. diff -u -N qmail-1.03-orig/digest.c test/digest.c --- qmail-1.03-orig/digest.c Thu Jan 1 01:00:00 1970 +++ test/digest.c Thu Mar 1 23:58:55 2001 @@ -0,0 +1,37 @@ +/* Who knows? */ + +#include +#include +#include +#include +#include +#include +#include "compatibility.h" +#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 -u -N qmail-1.03-orig/digest_md4.c test/digest_md4.c --- qmail-1.03-orig/digest_md4.c Thu Jan 1 01:00:00 1970 +++ test/digest_md4.c Thu Mar 1 23:58:55 2001 @@ -0,0 +1,390 @@ +/* digest_md4.c for QLDAP checkpassword.c */ +/* 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 +#include +#include +#include +#include +#include +#include +#include "compatibility.h" +#include "digest_md4.h" +#include "base64.h" + +/* 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 __P ((u_int32_t [4], const unsigned char [64])); + +#ifdef __LITTLE_ENDIAN__ +/* #warning __LITTLE_ENDIAN__ */ +#define Encode memcpy +#define Decode memcpy +#else /* __BIG_ENDIAN__ */ +/* #warning __BIG_ENDIAN__ */ +static void Encode __P ((void *, const void *, size_t)); +static void Decode __P ((void *, const void *, size_t)); +#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) + (u_int32_t)0x5a827999; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } +#define HH(a, b, c, d, x, s) { \ + (a) += H ((b), (c), (d)) + (x) + (u_int32_t)0x6ed9eba1; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } + +#ifdef __BIG_ENDIAN__ +/* Encodes input (u_int32_t) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (out, in, len) +void *out; +const void *in; +size_t len; +{ + const u_int32_t *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 (u_int32_t). Assumes len is + a multiple of 4. + */ +static void Decode (out, in, len) +void *out; +const void *in; +size_t len; +{ + u_int32_t *output = out; + const unsigned char *input = in; + size_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((u_int32_t)input[j]) | (((u_int32_t)input[j+1]) << 8) | + (((u_int32_t)input[j+2]) << 16) | (((u_int32_t)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; + + /* 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 >> 3) & 0x3F); + + /* Update number of bits */ + context->count += ((u_int64_t)inputLen << 3); + + partLen = 64 - index; + /* Transform as many times as possible. */ + if (inputLen >= partLen) { + memcpy + ((POINTER)&context->buffer[index], (POINTER)input, partLen); + 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 */ + memcpy + ((POINTER)&context->buffer[index], (POINTER)&input[i], + inputLen-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; + u_int32_t hi, lo; + + /* Save number of bits */ + hi = context->count >> 32; + lo = (u_int32_t)context->count & 0xffffffff; + Encode (bits, &lo, 4); + Encode (bits + 4, &hi, 4); + + /* Pad out to 56 mod 64. + */ + index = (unsigned int)((context->count >> 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, context->state, 16); + + /* Zeroize sensitive information. + */ + memset ((POINTER)context, 0, sizeof (*context)); + } +} + +/* MD4 basic transformation. Transforms state based on block. + */ +static void MD4Transform (state, block) +u_int32_t state[4]; +const unsigned char block[64]; +{ + u_int32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* 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. + */ + memset ((POINTER)x, 0, 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; +{ + int i; + char *p = buf; + unsigned char digest[16]; + static const char hex[]="0123456789abcdef"; + + if (!p) + p = malloc(33); + 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 * +MD4File (filename, buf) + char *filename; + char *buf; +{ + unsigned char buffer[BUFSIZ]; + MD4_CTX ctx; + int f,i,j; + + MD4Init(&ctx); + f = open(filename,O_RDONLY); + if (f < 0) return 0; + while ((i = read(f,buffer,sizeof buffer)) > 0) { + MD4Update(&ctx,buffer,i); + } + j = errno; + close(f); + errno = j; + if (i < 0) return 0; + return MD4End(&ctx, buf); +} + +char * +MD4Data (data, len, buf) + const unsigned char *data; + size_t len; + char *buf; +{ + MD4_CTX ctx; + + MD4Init(&ctx); + MD4Update(&ctx,data,len); + return MD4End(&ctx, buf); +} + +/* Base 64 */ + +char * +MD4DataBase64 (data, len, buf, buflen) + const u_char *data; + size_t len; + char *buf; + 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 -u -N qmail-1.03-orig/digest_md4.h test/digest_md4.h --- qmail-1.03-orig/digest_md4.h Thu Jan 1 01:00:00 1970 +++ test/digest_md4.h Thu Mar 1 23:58:55 2001 @@ -0,0 +1,46 @@ +/* digest_md4.h for QLDAP checkpassword.c */ + +/* */ +/* 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_ + +/* MD4 context. */ +typedef struct MD4Context { + u_int32_t state[4]; /* state (ABCD) */ + u_int64_t count; /* number of bits, modulo 2^64 */ + unsigned char buffer[64]; /* input buffer */ +} MD4_CTX; + +void MD4Init __P((MD4_CTX *)); +void MD4Update __P((MD4_CTX *, const unsigned char *, size_t)); +void MD4Final __P((unsigned char [16], MD4_CTX *)); +char *MD4End __P((MD4_CTX *, char *)); +char *MD4File __P((char *, char *)); +char *MD4Data __P((const unsigned char *, size_t, char *)); + +char *MD4DataBase64 __P((const unsigned char *, size_t, char *, size_t)); + +#endif /* _MD4_H_ */ diff -u -N qmail-1.03-orig/digest_md5.c test/digest_md5.c --- qmail-1.03-orig/digest_md5.c Thu Jan 1 01:00:00 1970 +++ test/digest_md5.c Thu Mar 1 23:58:55 2001 @@ -0,0 +1,472 @@ +/* digest_md5.c for QLDAP checkpassword.c */ +/* 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 +#include +#include +#include +#include +#include +#include +#include "compatibility.h" +#include "digest_md5.h" +#include "base64.h" + +/* 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 __P ((u_int32_t [4], const unsigned char [64])); + +#ifdef __LITTLE_ENDIAN__ +/* #warning __LITTLE_ENDIAN__ */ +#define Encode memcpy +#define Decode memcpy +#else /* __BIG_ENDIAN__ */ +/* #warning __BIG_ENDIAN__ */ +static void Encode __P((void *, const void *, size_t)); +static void Decode __P((void *, const void *, size_t)); +#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) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +#ifdef __BIG_ENDIAN__ +/* Encodes input (u_int32_t) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (out, in, len) +void *out; +const void *in; +size_t len; +{ + unsigned char *output = out; + size_t i, j; + const u_int32_t *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 (u_int32_t). Assumes len is + a multiple of 4. + */ +static void Decode (out, in, len) +void *out; +const void *in; +size_t len; +{ + u_int32_t *output = out; + const unsigned char *input = in; + size_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((u_int32_t)input[j]) | (((u_int32_t)input[j+1]) << 8) | + (((u_int32_t)input[j+2]) << 16) | (((u_int32_t)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; + /* 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 >> 3) & 0x3F); + + /* Update number of bits */ + context->count += ((u_int64_t)inputLen << 3); + + partLen = 64 - index; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) { + memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen); + 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 */ + memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-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; + u_int32_t hi, lo; + + /* Save number of bits */ + hi = context->count >> 32; + lo = (u_int32_t)context->count & 0xffffffff; + Encode (bits, &lo, 4); + Encode (bits + 4, &hi, 4); + + /* Pad out to 56 mod 64. */ + index = (unsigned int)((context->count >> 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, context->state, 16); + + /* Zeroize sensitive information. */ + memset ((POINTER)context, 0, sizeof (*context)); + } +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (state, block) +u_int32_t state[4]; +const unsigned char block[64]; +{ + u_int32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* 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. */ + memset ((POINTER)x, 0, 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) + p = malloc(33); + 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 * +MD5File (filename, buf) + char *filename; + char *buf; +{ + unsigned char buffer[BUFSIZ]; + MD5_CTX ctx; + int f,i,j; + + MD5Init(&ctx); + f = open(filename,O_RDONLY); + if (f < 0) return 0; + while ((i = read(f,buffer,sizeof buffer)) > 0) { + MD5Update(&ctx,buffer,i); + } + j = errno; + close(f); + errno = j; + if (i < 0) return 0; + return MD5End(&ctx, buf); +} + +char * +MD5Data (data, len, buf) + const unsigned char *data; + size_t len; + char *buf; +{ + MD5_CTX ctx; + + MD5Init(&ctx); + MD5Update(&ctx,data,len); + return MD5End(&ctx, buf); +} + +/* Base 64 */ + +char * +MD5DataBase64 (data, len, buf, buflen) + const u_char *data; + size_t len; + char *buf; + 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 */ + +static char * ns_mta_hextab = "0123456789abcdef"; + +void +ns_mta_hexify(char *buffer, char *str, int len) +{ + char *pch = str; + char ch; + int i; + + for(i = 0;i < len; i ++) { + ch = pch[i]; + buffer[2*i] = ns_mta_hextab[(ch>>4)&15]; + buffer[2*i+1] = ns_mta_hextab[ch&15]; + } + + return; +} + +char * +ns_mta_hash_alg(char *buffer, char *salt, char *passwd) +{ + MD5_CTX context; + char saltstr[2048]; + unsigned char digest[16]; + + sprintf(saltstr,"%s%c%s%c%s",salt,89,passwd,247,salt); + + MD5Init(&context); + MD5Update(&context,(unsigned char *)saltstr,strlen(saltstr)); + MD5Final(digest,&context); + ns_mta_hexify(buffer,(char*)digest,16); + buffer[32] = '\0'; + return(buffer); +} + +int +ns_mta_md5_cmp_pw(char * clear, char *mangled) +{ + char mta_hash[33]; + char mta_salt[33]; + char buffer[65]; + int gaga; + + strncpy(mta_hash,mangled,32); + strncpy(mta_salt,&mangled[32],32); + + mta_hash[32] = mta_salt[32] = 0; + gaga = strcmp(mta_hash,ns_mta_hash_alg(buffer,mta_salt,clear)); + + return(gaga); +} + diff -u -N qmail-1.03-orig/digest_md5.h test/digest_md5.h --- qmail-1.03-orig/digest_md5.h Thu Jan 1 01:00:00 1970 +++ test/digest_md5.h Thu Mar 1 23:58:55 2001 @@ -0,0 +1,52 @@ +/* digest_md5.h for QLDAP checkpassword.c */ + +/* */ +/* 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_ + +/* MD5 context. */ +typedef struct MD5Context { + u_int32_t state[4]; /* state (ABCD) */ + u_int64_t count; /* number of bits, modulo 2^64 */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void MD5Init __P((MD5_CTX *)); +void MD5Update __P((MD5_CTX *, const unsigned char *, size_t)); +void MD5Final __P((unsigned char [16], MD5_CTX *)); +char *MD5End __P((MD5_CTX *, char *)); +char *MD5File __P((char *, char *)); +char *MD5Data __P((const unsigned char *, size_t, char *)); + +char *MD5DataBase64 __P((const unsigned char *, size_t, char *, size_t)); + +void ns_mta_hexify(char *, char *, int); +char *ns_mta_hash_alg(char *, char *, char *); +int ns_mta_md5_cmp_pw(char *, char *); + +#endif /* _MD5_H_ */ diff -u -N qmail-1.03-orig/digest_rmd160.c test/digest_rmd160.c --- qmail-1.03-orig/digest_rmd160.c Thu Jan 1 01:00:00 1970 +++ test/digest_rmd160.c Thu Mar 1 23:58:55 2001 @@ -0,0 +1,512 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include "compatibility.h" +#include "digest_rmd160.h" +#include "base64.h" + +/* macro definitions */ + +/* collect four bytes into one word: */ +#define BYTES_TO_DWORD(strptr) \ + (((u_int32_t) *((strptr)+3) << 24) | \ + ((u_int32_t) *((strptr)+2) << 16) | \ + ((u_int32_t) *((strptr)+1) << 8) | \ + ((u_int32_t) *(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) + u_int32_t state[5]; + const u_int32_t block[16]; +{ + u_int32_t aa = state[0], bb = state[1], cc = state[2], + dd = state[3], ee = state[4]; + u_int32_t 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 u_char *data; + u_int32_t nbytes; +{ + u_int32_t X[16]; + u_int32_t ofs = 0; + u_int32_t i; +#ifdef __BIG_ENDIAN__ + u_int32_t 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; + + (void)memset(X, 0, sizeof(X)); + + if ( context->buflen + nbytes < 64 ) + { + (void)memcpy(context->bbuffer + context->buflen, data, nbytes); + context->buflen += nbytes; + } + else + { + /* process first block */ + ofs = 64 - context->buflen; + (void)memcpy(context->bbuffer + context->buflen, data, ofs); +#ifdef __LITTLE_ENDIAN__ +/* #warning __LITTLE_ENDIAN__ */ + (void)memcpy(X, context->bbuffer, sizeof(X)); +#else /* __BIG_ENDIAN__ */ +/* #warning __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__ + (void)memcpy(X, data + (64 * i) + ofs, sizeof(X)); +#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; + memcpy(context->bbuffer, data + (64 * i) + ofs, context->buflen); + } +} + +void RMD160Final(digest, context) + u_char digest[20]; + RMD160_CTX *context; +{ + u_int32_t i; + u_int32_t X[16]; +#ifdef __BIG_ENDIAN__ + u_int32_t j; +#endif /* __BIG_ENDIAN__ */ + + /* append the bit m_n == 1 */ + context->bbuffer[context->buflen] = '\200'; + + (void)memset(context->bbuffer + context->buflen + 1, 0, + 63 - context->buflen); +#ifdef __LITTLE_ENDIAN__ + (void)memcpy(X, context->bbuffer, sizeof(X)); +#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); + (void)memset(X, 0, 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; +{ + int i; + char *p = buf; + u_char digest[20]; + static const char hex[]="0123456789abcdef"; + + if (p == NULL && (p = malloc(41)) == 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 * +RMD160File (filename, buf) + char *filename; + char *buf; +{ + u_char buffer[BUFSIZ]; + RMD160_CTX ctx; + int fd, num, oerrno; + + RMD160Init(&ctx); + + if ((fd = open(filename,O_RDONLY)) < 0) + return(0); + + while ((num = read(fd, buffer, sizeof(buffer))) > 0) + RMD160Update(&ctx, buffer, num); + + oerrno = errno; + close(fd); + errno = oerrno; + return(num < 0 ? 0 : RMD160End(&ctx, buf)); +} + +char * +RMD160Data (data, len, buf) + const u_char *data; + size_t len; + char *buf; +{ + RMD160_CTX ctx; + + RMD160Init(&ctx); + RMD160Update(&ctx, data, len); + return(RMD160End(&ctx, buf)); +} + +/* Base 64 */ + +char * +RMD160DataBase64 (data, len, buf, buflen) + const u_char *data; + size_t len; + char *buf; + 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 -u -N qmail-1.03-orig/digest_rmd160.h test/digest_rmd160.h --- qmail-1.03-orig/digest_rmd160.h Thu Jan 1 01:00:00 1970 +++ test/digest_rmd160.h Thu Mar 1 23:58:55 2001 @@ -0,0 +1,52 @@ +/* digest_rmd160.h for QLDAP checkpassword.c */ + +/* */ +/* 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 + +/********************************************************************/ + +/* structure definitions */ + +typedef struct { + u_int32_t state[5]; /* state (ABCDE) */ + u_int32_t length[2]; /* number of bits */ + unsigned char bbuffer[64]; /* overflow buffer */ + u_int32_t buflen; /* number of chars in bbuffer */ +} RMD160_CTX; + +/********************************************************************/ + +/* function prototypes */ + +void RMD160Init __P((RMD160_CTX *context)); +void RMD160Transform __P((u_int32_t state[5], const u_int32_t block[16])); +void RMD160Update __P((RMD160_CTX *context, const unsigned char *data, unsigned int nbytes)); +void RMD160Final __P((unsigned char digest[20], RMD160_CTX *context)); +char *RMD160End __P((RMD160_CTX *, char *)); +char *RMD160File __P((char *, char *)); +char *RMD160Data __P((const unsigned char *, size_t, char *)); + +char *RMD160DataBase64 __P((const unsigned char *, size_t, char *, size_t)); + +#endif /* _RMD160_H */ diff -u -N qmail-1.03-orig/digest_sha1.c test/digest_sha1.c --- qmail-1.03-orig/digest_sha1.c Thu Jan 1 01:00:00 1970 +++ test/digest_sha1.c Thu Mar 1 23:58:55 2001 @@ -0,0 +1,285 @@ +/* digest_sha1.c for QLDAP checkpassword.c */ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include "compatibility.h" +#include "digest_sha1.h" +#include "base64.h" + +#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__ +/* #warning __LITTLE_ENDIAN__ */ +# define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#else /* __BIG_ENDIAN__ */ +/* #warning __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) + u_int32_t state[5]; + const u_char buffer[64]; +{ + u_int32_t a, b, c, d, e; + typedef union { + u_char c[64]; + u_int l[16]; + } CHAR64LONG16; + CHAR64LONG16 *block; + +#ifdef SHA1HANDSOFF + static u_char workspace[64]; + block = (CHAR64LONG16 *)workspace; + (void)memcpy(block, buffer, 64); +#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 u_char *data; + u_int len; +{ + u_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) { + (void)memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) + SHA1Transform(context->state, &data[i]); + j = 0; + } else { + i = 0; + } + (void)memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* + * Add padding and return the message digest. + */ +void SHA1Final(digest, context) + u_char digest[20]; + SHA1_CTX* context; +{ + u_int i; + u_char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (u_char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (u_char *)"\200", 1); + while ((context->count[0] & 504) != 448) + SHA1Update(context, (u_char *)"\0", 1); + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + + if (digest) { + for (i = 0; i < 20; i++) + digest[i] = (u_char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } +} + + +/* 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; +{ + int i; + char *p = buf; + u_char digest[20]; + static const char hex[]="0123456789abcdef"; + + if (p == NULL && (p = malloc(41)) == 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 * +SHA1File (filename, buf) + char *filename; + char *buf; +{ + u_char buffer[BUFSIZ]; + SHA1_CTX ctx; + int fd, num, oerrno; + + SHA1Init(&ctx); + + if ((fd = open(filename,O_RDONLY)) < 0) + return(0); + + while ((num = read(fd, buffer, sizeof(buffer))) > 0) + SHA1Update(&ctx, buffer, num); + + oerrno = errno; + close(fd); + errno = oerrno; + return(num < 0 ? 0 : SHA1End(&ctx, buf)); +} + +char * +SHA1Data (data, len, buf) + const u_char *data; + size_t len; + char *buf; +{ + SHA1_CTX ctx; + + SHA1Init(&ctx); + SHA1Update(&ctx, data, len); + return(SHA1End(&ctx, buf)); +} + +/* Base 64 */ + +char * +SHA1DataBase64 (data, len, buf, buflen) + const u_char *data; + size_t len; + char *buf; + 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 -u -N qmail-1.03-orig/digest_sha1.h test/digest_sha1.h --- qmail-1.03-orig/digest_sha1.h Thu Jan 1 01:00:00 1970 +++ test/digest_sha1.h Thu Mar 1 23:58:55 2001 @@ -0,0 +1,32 @@ +/* digest_sha1.h for QLDAP checkpassword.c */ + +/* */ +/* SHA1 */ +/* */ + +/* + * SHA-1 in C + * By Steve Reid + * 100% Public Domain + */ + +#ifndef _SHA1_H +#define _SHA1_H + +typedef struct { + u_int32_t state[5]; + u_int32_t count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +void SHA1Transform __P((u_int32_t state[5], const unsigned char buffer[64])); +void SHA1Init __P((SHA1_CTX *context)); +void SHA1Update __P((SHA1_CTX *context, const unsigned char *data, unsigned int len)); +void SHA1Final __P((unsigned char digest[20], SHA1_CTX *context)); +char *SHA1End __P((SHA1_CTX *, char *)); +char *SHA1File __P((char *, char *)); +char *SHA1Data __P((const unsigned char *, size_t, char *)); + +char *SHA1DataBase64 __P((const unsigned char *, size_t, char *, size_t)); + +#endif /* _SHA1_H */ diff -u -N qmail-1.03-orig/dirmaker test/dirmaker --- qmail-1.03-orig/dirmaker Thu Jan 1 01:00:00 1970 +++ test/dirmaker Thu Mar 1 23:58:55 2001 @@ -0,0 +1,3 @@ +#!/bin/sh +/bin/mkdir -m 700 -p $1 +#EOF diff -u -N qmail-1.03-orig/dns.c test/dns.c --- qmail-1.03-orig/dns.c Mon Jun 15 12:53:16 1998 +++ test/dns.c Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/dns.c.orig test/dns.c.orig --- qmail-1.03-orig/dns.c.orig Thu Jan 1 01:00:00 1970 +++ test/dns.c.orig Thu Mar 1 23:58:55 2001 @@ -0,0 +1,400 @@ +#include +#include +#include +#include +#include +#include +#include +extern int res_query(); +extern int res_search(); +extern int errno; +extern int h_errno; +#include "ip.h" +#include "ipalloc.h" +#include "fmt.h" +#include "alloc.h" +#include "str.h" +#include "stralloc.h" +#include "dns.h" +#include "case.h" + +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 int responselen; +static unsigned char *responseend; +static unsigned char *responsepos; + +static int numanswers; +static char name[MAXDNAME]; +static struct ip_address ip; +unsigned short pref; + +static stralloc glue = {0}; + +static int (*lookup)() = res_query; + +static int resolve(domain,type) +stralloc *domain; +int type; +{ + int n; + int i; + + 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 (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); + while (n-- > 0) + { + i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); + if (i < 0) return DNS_SOFT; + responsepos += i; + i = responseend - responsepos; + if (i < QFIXEDSZ) return DNS_SOFT; + responsepos += QFIXEDSZ; + } + numanswers = ntohs(response.hdr.ancount); + return 0; +} + +static int findname(wanttype) +int wanttype; +{ + unsigned short rrtype; + unsigned short rrdlen; + int i; + + if (numanswers <= 0) return 2; + --numanswers; + if (responsepos == responseend) return DNS_SOFT; + + i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); + if (i < 0) return DNS_SOFT; + responsepos += i; + + i = responseend - responsepos; + if (i < 4 + 3 * 2) return DNS_SOFT; + + rrtype = getshort(responsepos); + rrdlen = getshort(responsepos + 8); + responsepos += 10; + + if (rrtype == wanttype) + { + if (dn_expand(response.buf,responseend,responsepos,name,MAXDNAME) < 0) + return DNS_SOFT; + responsepos += rrdlen; + return 1; + } + + responsepos += rrdlen; + return 0; +} + +static int findip(wanttype) +int wanttype; +{ + unsigned short rrtype; + unsigned short rrdlen; + int i; + + if (numanswers <= 0) return 2; + --numanswers; + if (responsepos == responseend) return DNS_SOFT; + + i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); + if (i < 0) return DNS_SOFT; + responsepos += i; + + i = responseend - responsepos; + if (i < 4 + 3 * 2) return DNS_SOFT; + + rrtype = getshort(responsepos); + rrdlen = getshort(responsepos + 8); + responsepos += 10; + + if (rrtype == wanttype) + { + if (rrdlen < 4) + return DNS_SOFT; + ip.d[0] = responsepos[0]; + ip.d[1] = responsepos[1]; + ip.d[2] = responsepos[2]; + ip.d[3] = responsepos[3]; + responsepos += rrdlen; + return 1; + } + + responsepos += rrdlen; + return 0; +} + +static int findmx(wanttype) +int wanttype; +{ + unsigned short rrtype; + unsigned short rrdlen; + int i; + + if (numanswers <= 0) return 2; + --numanswers; + if (responsepos == responseend) return DNS_SOFT; + + i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); + if (i < 0) return DNS_SOFT; + responsepos += i; + + i = responseend - responsepos; + if (i < 4 + 3 * 2) return DNS_SOFT; + + rrtype = getshort(responsepos); + rrdlen = getshort(responsepos + 8); + responsepos += 10; + + if (rrtype == wanttype) + { + if (rrdlen < 3) + return DNS_SOFT; + pref = (responsepos[0] << 8) + responsepos[1]; + if (dn_expand(response.buf,responseend,responsepos + 2,name,MAXDNAME) < 0) + return DNS_SOFT; + responsepos += rrdlen; + return 1; + } + + responsepos += rrdlen; + return 0; +} + +void dns_init(flagsearch) +int flagsearch; +{ + res_init(); + if (flagsearch) lookup = res_search; +} + +int dns_cname(sa) +stralloc *sa; +{ + int r; + int loop; + for (loop = 0;loop < 10;++loop) + { + if (!sa->len) return loop; + if (sa->s[sa->len - 1] == ']') return loop; + if (sa->s[sa->len - 1] == '.') { --sa->len; continue; } + switch(resolve(sa,T_ANY)) + { + case DNS_MEM: return DNS_MEM; + case DNS_SOFT: return DNS_SOFT; + case DNS_HARD: return loop; + default: + while ((r = findname(T_CNAME)) != 2) + { + if (r == DNS_SOFT) return DNS_SOFT; + if (r == 1) + { + if (!stralloc_copys(sa,name)) return DNS_MEM; + break; + } + } + if (r == 2) return loop; + } + } + return DNS_HARD; /* alias loop */ +} + +#define FMT_IAA 40 + +static int iaafmt(s,ip) +char *s; +struct ip_address *ip; +{ + unsigned int i; + unsigned int len; + len = 0; + i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i; + i = fmt_str(s,"."); len += i; if (s) s += i; + i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i; + i = fmt_str(s,"."); len += i; if (s) s += i; + i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i; + i = fmt_str(s,"."); len += i; if (s) s += i; + i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i; + i = fmt_str(s,".in-addr.arpa."); len += i; if (s) s += i; + return len; +} + +int dns_ptr(sa,ip) +stralloc *sa; +struct ip_address *ip; +{ + int r; + + if (!stralloc_ready(sa,iaafmt((char *) 0,ip))) return DNS_MEM; + sa->len = iaafmt(sa->s,ip); + switch(resolve(sa,T_PTR)) + { + case DNS_MEM: return DNS_MEM; + case DNS_SOFT: return DNS_SOFT; + case DNS_HARD: return DNS_HARD; + } + while ((r = findname(T_PTR)) != 2) + { + if (r == DNS_SOFT) return DNS_SOFT; + if (r == 1) + { + if (!stralloc_copys(sa,name)) return DNS_MEM; + return 0; + } + } + return DNS_HARD; +} + +static int dns_ipplus(ia,sa,pref) +ipalloc *ia; +stralloc *sa; +int pref; +{ + int r; + struct ip_mx ix; + + if (!stralloc_copy(&glue,sa)) return DNS_MEM; + if (!stralloc_0(&glue)) return DNS_MEM; + if (glue.s[0]) { + ix.pref = 0; + if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) + { + if (!ipalloc_append(ia,&ix)) return DNS_MEM; + return 0; + } + } + + switch(resolve(sa,T_A)) + { + case DNS_MEM: return DNS_MEM; + case DNS_SOFT: return DNS_SOFT; + case DNS_HARD: return DNS_HARD; + } + while ((r = findip(T_A)) != 2) + { + ix.ip = ip; + ix.pref = pref; + if (r == DNS_SOFT) return DNS_SOFT; + if (r == 1) + if (!ipalloc_append(ia,&ix)) return DNS_MEM; + } + return 0; +} + +int dns_ip(ia,sa) +ipalloc *ia; +stralloc *sa; +{ + if (!ipalloc_readyplus(ia,0)) return DNS_MEM; + ia->len = 0; + return dns_ipplus(ia,sa,0); +} + +int dns_mxip(ia,sa,random) +ipalloc *ia; +stralloc *sa; +unsigned long random; +{ + int r; + struct mx { stralloc sa; unsigned short p; } *mx; + struct ip_mx ix; + int nummx; + int i; + int j; + int flagsoft; + + if (!ipalloc_readyplus(ia,0)) return DNS_MEM; + ia->len = 0; + + if (!stralloc_copy(&glue,sa)) return DNS_MEM; + if (!stralloc_0(&glue)) return DNS_MEM; + if (glue.s[0]) { + ix.pref = 0; + if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) + { + if (!ipalloc_append(ia,&ix)) return DNS_MEM; + return 0; + } + } + + switch(resolve(sa,T_MX)) + { + case DNS_MEM: return DNS_MEM; + case DNS_SOFT: return DNS_SOFT; + case DNS_HARD: return dns_ip(ia,sa); + } + + mx = (struct mx *) alloc(numanswers * sizeof(struct mx)); + if (!mx) return DNS_MEM; + nummx = 0; + + while ((r = findmx(T_MX)) != 2) + { + if (r == DNS_SOFT) { alloc_free(mx); return DNS_SOFT; } + if (r == 1) + { + mx[nummx].p = pref; + mx[nummx].sa.s = 0; + if (!stralloc_copys(&mx[nummx].sa,name)) + { + while (nummx > 0) alloc_free(mx[--nummx].sa.s); + alloc_free(mx); return DNS_MEM; + } + ++nummx; + } + } + + if (!nummx) return dns_ip(ia,sa); /* e.g., CNAME -> A */ + + flagsoft = 0; + while (nummx > 0) + { + unsigned long numsame; + + i = 0; + numsame = 1; + for (j = 1;j < nummx;++j) + if (mx[j].p < mx[i].p) + { + i = j; + numsame = 1; + } + else if (mx[j].p == mx[i].p) + { + ++numsame; + random = random * 69069 + 1; + if ((random / 2) < (2147483647 / numsame)) + i = j; + } + + switch(dns_ipplus(ia,&mx[i].sa,mx[i].p)) + { + case DNS_MEM: case DNS_SOFT: + flagsoft = 1; break; + } + + alloc_free(mx[i].sa.s); + mx[i] = mx[--nummx]; + } + + alloc_free(mx); + return flagsoft; +} diff -u -N qmail-1.03-orig/endian.c test/endian.c --- qmail-1.03-orig/endian.c Thu Jan 1 01:00:00 1970 +++ test/endian.c Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/hier.c test/hier.c --- qmail-1.03-orig/hier.c Mon Jun 15 12:53:16 1998 +++ test/hier.c Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/hier.c.orig test/hier.c.orig --- qmail-1.03-orig/hier.c.orig Thu Jan 1 01:00:00 1970 +++ test/hier.c.orig Thu Mar 1 23:58:55 2001 @@ -0,0 +1,252 @@ +#include "auto_qmail.h" +#include "auto_split.h" +#include "auto_uids.h" +#include "fmt.h" +#include "fifo.h" + +char buf[100 + FMT_ULONG]; + +void dsplit(base,uid,mode) +char *base; /* must be under 100 bytes */ +int uid; +int mode; +{ + char *x; + unsigned long i; + + d(auto_qmail,base,uid,auto_gidq,mode); + + for (i = 0;i < auto_split;++i) { + x = buf; + x += fmt_str(x,base); + x += fmt_str(x,"/"); + x += fmt_ulong(x,i); + *x = 0; + + d(auto_qmail,buf,uid,auto_gidq,mode); + } +} + +void hier() +{ + h(auto_qmail,auto_uido,auto_gidq,0755); + + d(auto_qmail,"control",auto_uido,auto_gidq,0755); + d(auto_qmail,"users",auto_uido,auto_gidq,0755); + d(auto_qmail,"bin",auto_uido,auto_gidq,0755); + d(auto_qmail,"boot",auto_uido,auto_gidq,0755); + d(auto_qmail,"doc",auto_uido,auto_gidq,0755); + d(auto_qmail,"man",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/cat1",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/cat5",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/cat7",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/cat8",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/man1",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/man5",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/man7",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/man8",auto_uido,auto_gidq,0755); + + d(auto_qmail,"alias",auto_uida,auto_gidq,02755); + + d(auto_qmail,"queue",auto_uidq,auto_gidq,0750); + d(auto_qmail,"queue/pid",auto_uidq,auto_gidq,0700); + d(auto_qmail,"queue/intd",auto_uidq,auto_gidq,0700); + d(auto_qmail,"queue/todo",auto_uidq,auto_gidq,0750); + d(auto_qmail,"queue/bounce",auto_uids,auto_gidq,0700); + + dsplit("queue/mess",auto_uidq,0750); + dsplit("queue/info",auto_uids,0700); + dsplit("queue/local",auto_uids,0700); + dsplit("queue/remote",auto_uids,0700); + + d(auto_qmail,"queue/lock",auto_uidq,auto_gidq,0750); + z(auto_qmail,"queue/lock/tcpto",1024,auto_uidr,auto_gidq,0644); + z(auto_qmail,"queue/lock/sendmutex",0,auto_uids,auto_gidq,0600); + p(auto_qmail,"queue/lock/trigger",auto_uids,auto_gidq,0622); + + c(auto_qmail,"boot","home",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","home+df",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","proc",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","proc+df",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","binm1",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","binm1+df",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","binm2",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","binm2+df",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","binm3",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755); + + c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL.alias",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL.ctl",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL.ids",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL.maildir",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL.mbox",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL.vsm",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","TEST.deliver",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","TEST.receive",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","REMOVE.sendmail",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","REMOVE.binmail",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","PIC.local2alias",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","PIC.local2ext",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","PIC.local2local",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","PIC.local2rem",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","PIC.local2virt",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","PIC.nullclient",auto_uido,auto_gidq,0644); + 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,"bin","qmail-queue",auto_uidq,auto_gidq,04711); + c(auto_qmail,"bin","qmail-lspawn",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","qmail-start",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","qmail-getpw",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-local",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-remote",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-rspawn",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-send",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","splogger",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-newu",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","qmail-newmrh",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","qmail-pw2u",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-inject",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","predate",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","datemail",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","mailsubj",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-showctl",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-qread",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-qstat",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-tcpto",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-tcpok",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-pop3d",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-popup",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-qmqpc",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-qmqpd",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-qmtpd",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-smtpd",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","sendmail",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","tcp-env",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qreceipt",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qsmhook",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qbiff",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","forward",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","preline",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","condredirect",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","bouncesaying",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","except",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","maildirmake",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","maildir2mbox",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","maildirwatch",auto_uido,auto_gidq,0755); + 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,"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); + c(auto_qmail,"man/cat5","envelopes.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","maildir.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","maildir.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","mbox.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","mbox.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","dot-qmail.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","dot-qmail.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","qmail-control.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","qmail-control.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","qmail-header.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","qmail-header.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","qmail-log.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","qmail-log.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","qmail-users.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","qmail-users.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","tcp-environ.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","tcp-environ.0",auto_uido,auto_gidq,0644); + + c(auto_qmail,"man/man7","forgeries.7",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat7","forgeries.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man7","qmail-limits.7",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat7","qmail-limits.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man7","qmail.7",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat7","qmail.0",auto_uido,auto_gidq,0644); + + c(auto_qmail,"man/man1","forward.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","forward.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","condredirect.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","condredirect.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","bouncesaying.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","bouncesaying.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","except.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","except.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","maildirmake.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","maildirmake.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","maildir2mbox.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","maildir2mbox.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","maildirwatch.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","maildirwatch.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","mailsubj.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","mailsubj.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","qreceipt.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","qreceipt.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","qbiff.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","qbiff.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","preline.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","preline.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","tcp-env.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","tcp-env.0",auto_uido,auto_gidq,0644); + + c(auto_qmail,"man/man8","qmail-local.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-local.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-lspawn.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-lspawn.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-getpw.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-getpw.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-remote.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-remote.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-rspawn.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-rspawn.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-clean.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-clean.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-send.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-send.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-start.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-start.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","splogger.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","splogger.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-queue.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-queue.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-inject.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-inject.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-showctl.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-showctl.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-newmrh.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-newmrh.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-newu.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-newu.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-pw2u.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-pw2u.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-qread.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-qread.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-qstat.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-qstat.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-tcpok.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-tcpok.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-tcpto.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-tcpto.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-pop3d.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-pop3d.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-popup.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-popup.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-qmqpc.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-qmqpc.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-qmqpd.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-qmqpd.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-qmtpd.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-qmtpd.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-smtpd.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-smtpd.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-command.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-command.0",auto_uido,auto_gidq,0644); +} diff -u -N qmail-1.03-orig/install-big.c test/install-big.c --- qmail-1.03-orig/install-big.c Mon Jun 15 12:53:16 1998 +++ test/install-big.c Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/install-big.c.orig test/install-big.c.orig --- qmail-1.03-orig/install-big.c.orig Thu Jan 1 01:00:00 1970 +++ test/install-big.c.orig Thu Mar 1 23:58:55 2001 @@ -0,0 +1,285 @@ +#include "auto_qmail.h" +#include "auto_split.h" +#include "auto_uids.h" +#include "fmt.h" +#include "fifo.h" + +char buf[100 + FMT_ULONG]; + +void dsplit(base,uid,mode) +char *base; /* must be under 100 bytes */ +int uid; +int mode; +{ + char *x; + unsigned long i; + + d(auto_qmail,base,uid,auto_gidq,mode); + + for (i = 0;i < auto_split;++i) { + x = buf; + x += fmt_str(x,base); + x += fmt_str(x,"/"); + x += fmt_ulong(x,i); + *x = 0; + + d(auto_qmail,buf,uid,auto_gidq,mode); + } +} + +void hier() +{ + h(auto_qmail,auto_uido,auto_gidq,0755); + + d(auto_qmail,"control",auto_uido,auto_gidq,0755); + d(auto_qmail,"users",auto_uido,auto_gidq,0755); + d(auto_qmail,"bin",auto_uido,auto_gidq,0755); + d(auto_qmail,"boot",auto_uido,auto_gidq,0755); + d(auto_qmail,"doc",auto_uido,auto_gidq,0755); + d(auto_qmail,"man",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/cat1",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/cat5",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/cat7",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/cat8",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/man1",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/man5",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/man7",auto_uido,auto_gidq,0755); + d(auto_qmail,"man/man8",auto_uido,auto_gidq,0755); + + d(auto_qmail,"alias",auto_uida,auto_gidq,02755); + + d(auto_qmail,"queue",auto_uidq,auto_gidq,0750); + d(auto_qmail,"queue/pid",auto_uidq,auto_gidq,0700); + d(auto_qmail,"queue/intd",auto_uidq,auto_gidq,0700); + d(auto_qmail,"queue/todo",auto_uidq,auto_gidq,0750); + d(auto_qmail,"queue/bounce",auto_uids,auto_gidq,0700); + + dsplit("queue/mess",auto_uidq,0750); + dsplit("queue/info",auto_uids,0700); + dsplit("queue/local",auto_uids,0700); + dsplit("queue/remote",auto_uids,0700); + + d(auto_qmail,"queue/lock",auto_uidq,auto_gidq,0750); + z(auto_qmail,"queue/lock/tcpto",1024,auto_uidr,auto_gidq,0644); + z(auto_qmail,"queue/lock/sendmutex",0,auto_uids,auto_gidq,0600); + p(auto_qmail,"queue/lock/trigger",auto_uids,auto_gidq,0622); + + c(auto_qmail,"boot","home",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","home+df",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","proc",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","proc+df",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","binm1",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","binm1+df",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","binm2",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","binm2+df",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","binm3",auto_uido,auto_gidq,0755); + c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755); + + c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL.alias",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL.ctl",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL.ids",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL.maildir",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL.mbox",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","INSTALL.vsm",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","TEST.deliver",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","TEST.receive",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","REMOVE.sendmail",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","REMOVE.binmail",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","PIC.local2alias",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","PIC.local2ext",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","PIC.local2local",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","PIC.local2rem",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","PIC.local2virt",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","PIC.nullclient",auto_uido,auto_gidq,0644); + 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,"bin","qmail-queue",auto_uidq,auto_gidq,04711); + c(auto_qmail,"bin","qmail-lspawn",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","qmail-start",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","qmail-getpw",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-local",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-remote",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-rspawn",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-send",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","splogger",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-newu",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","qmail-newmrh",auto_uido,auto_gidq,0700); + c(auto_qmail,"bin","qmail-pw2u",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-inject",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","predate",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","datemail",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","mailsubj",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-showctl",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-qread",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-qstat",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-tcpto",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-tcpok",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-pop3d",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-popup",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-qmqpc",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-qmqpd",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-qmtpd",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qmail-smtpd",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","sendmail",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","tcp-env",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qreceipt",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qsmhook",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","qbiff",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","forward",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","preline",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","condredirect",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","bouncesaying",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","except",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","maildirmake",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","maildir2mbox",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","maildirwatch",auto_uido,auto_gidq,0755); + 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,"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); + c(auto_qmail,"man/cat5","envelopes.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","maildir.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","maildir.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","mbox.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","mbox.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","dot-qmail.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","dot-qmail.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","qmail-control.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","qmail-control.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","qmail-header.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","qmail-header.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","qmail-log.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","qmail-log.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","qmail-users.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","qmail-users.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man5","tcp-environ.5",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat5","tcp-environ.0",auto_uido,auto_gidq,0644); + + c(auto_qmail,"man/man7","forgeries.7",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat7","forgeries.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man7","qmail-limits.7",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat7","qmail-limits.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man7","qmail.7",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat7","qmail.0",auto_uido,auto_gidq,0644); + + c(auto_qmail,"man/man1","forward.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","forward.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","condredirect.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","condredirect.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","bouncesaying.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","bouncesaying.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","except.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","except.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","maildirmake.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","maildirmake.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","maildir2mbox.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","maildir2mbox.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","maildirwatch.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","maildirwatch.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","mailsubj.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","mailsubj.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","qreceipt.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","qreceipt.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","qbiff.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","qbiff.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","preline.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","preline.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","tcp-env.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","tcp-env.0",auto_uido,auto_gidq,0644); + + c(auto_qmail,"man/man8","qmail-local.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-local.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-lspawn.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-lspawn.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-getpw.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-getpw.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-remote.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-remote.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-rspawn.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-rspawn.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-clean.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-clean.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-send.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-send.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-start.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-start.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","splogger.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","splogger.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-queue.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-queue.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-inject.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-inject.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-showctl.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-showctl.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-newmrh.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-newmrh.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-newu.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-newu.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-pw2u.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-pw2u.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-qread.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-qread.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-qstat.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-qstat.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-tcpok.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-tcpok.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-tcpto.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-tcpto.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-pop3d.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-pop3d.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-popup.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-popup.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-qmqpc.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-qmqpc.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-qmqpd.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-qmqpd.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-qmtpd.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-qmtpd.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-smtpd.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-smtpd.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man8","qmail-command.8",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat8","qmail-command.0",auto_uido,auto_gidq,0644); + + c(auto_qmail,"bin","dot-forward",auto_uido,auto_gidq,0755); + + c(auto_qmail,"man/man1","dot-forward.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","dot-forward.0",auto_uido,auto_gidq,0644); + + d(auto_qmail,"doc/fastforward",auto_uido,auto_gidq,0755); + + c(auto_qmail,"bin","fastforward",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","printforward",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","setforward",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","newaliases",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","printmaillist",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","setmaillist",auto_uido,auto_gidq,0755); + c(auto_qmail,"bin","newinclude",auto_uido,auto_gidq,0755); + + c(auto_qmail,"doc/fastforward","ALIASES",auto_uido,auto_gidq,0644); + + c(auto_qmail,"man/man1","fastforward.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","printforward.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","setforward.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","newaliases.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","printmaillist.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","setmaillist.1",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/man1","newinclude.1",auto_uido,auto_gidq,0644); + + c(auto_qmail,"man/cat1","fastforward.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","printforward.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","setforward.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","newaliases.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","printmaillist.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","setmaillist.0",auto_uido,auto_gidq,0644); + c(auto_qmail,"man/cat1","newinclude.0",auto_uido,auto_gidq,0644); +} diff -u -N qmail-1.03-orig/ipalloc.h test/ipalloc.h --- qmail-1.03-orig/ipalloc.h Mon Jun 15 12:53:16 1998 +++ test/ipalloc.h Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/ipalloc.h.orig test/ipalloc.h.orig --- qmail-1.03-orig/ipalloc.h.orig Thu Jan 1 01:00:00 1970 +++ test/ipalloc.h.orig Thu Mar 1 23:58:55 2001 @@ -0,0 +1,14 @@ +#ifndef IPALLOC_H +#define IPALLOC_H + +#include "ip.h" + +struct ip_mx { struct ip_address ip; int pref; } ; + +#include "gen_alloc.h" + +GEN_ALLOC_typedef(ipalloc,struct ip_mx,ix,len,a) +extern int ipalloc_readyplus(); +extern int ipalloc_append(); + +#endif diff -u -N qmail-1.03-orig/ipme.c test/ipme.c --- qmail-1.03-orig/ipme.c Mon Jun 15 12:53:16 1998 +++ test/ipme.c Thu Mar 1 23:58:55 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 -u -N qmail-1.03-orig/ipme.c.orig test/ipme.c.orig --- qmail-1.03-orig/ipme.c.orig Thu Jan 1 01:00:00 1970 +++ test/ipme.c.orig Thu Mar 1 23:58:55 2001 @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include +#include +#ifndef SIOCGIFCONF /* whatever works */ +#include +#endif +#include "hassalen.h" +#include "byte.h" +#include "ip.h" +#include "ipalloc.h" +#include "stralloc.h" +#include "ipme.h" + +static int ipmeok = 0; +ipalloc ipme = {0}; + +int ipme_is(ip) +struct ip_address *ip; +{ + int i; + if (ipme_init() != 1) return -1; + for (i = 0;i < ipme.len;++i) + if (byte_equal(&ipme.ix[i].ip,4,ip)) + return 1; + return 0; +} + +static stralloc buf = {0}; + +int ipme_init() +{ + struct ifconf ifc; + char *x; + struct ifreq *ifr; + struct sockaddr_in *sin; + int len; + int s; + struct ip_mx ix; + + if (ipmeok) return 1; + if (!ipalloc_readyplus(&ipme,0)) return 0; + ipme.len = 0; + ix.pref = 0; + + if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) return -1; + + len = 256; + for (;;) { + if (!stralloc_ready(&buf,len)) { close(s); return 0; } + buf.len = 0; + ifc.ifc_buf = buf.s; + ifc.ifc_len = len; + if (ioctl(s,SIOCGIFCONF,&ifc) >= 0) /* > is for System V */ + if (ifc.ifc_len + sizeof(*ifr) + 64 < len) { /* what a stupid interface */ + buf.len = ifc.ifc_len; + break; + } + if (len > 200000) { close(s); return -1; } + len += 100 + (len >> 2); + } + x = buf.s; + while (x < buf.s + buf.len) { + ifr = (struct ifreq *) x; +#ifdef HASSALEN + len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len; + if (len < sizeof(*ifr)) + len = sizeof(*ifr); + if (ifr->ifr_addr.sa_family == AF_INET) { + sin = (struct sockaddr_in *) &ifr->ifr_addr; + byte_copy(&ix.ip,4,&sin->sin_addr); + if (ioctl(s,SIOCGIFFLAGS,x) == 0) + if (ifr->ifr_flags & IFF_UP) + if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; } + } +#else + len = sizeof(*ifr); + if (ioctl(s,SIOCGIFFLAGS,x) == 0) + if (ifr->ifr_flags & IFF_UP) + if (ioctl(s,SIOCGIFADDR,x) == 0) + if (ifr->ifr_addr.sa_family == AF_INET) { + sin = (struct sockaddr_in *) &ifr->ifr_addr; + byte_copy(&ix.ip,4,&sin->sin_addr); + if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; } + } +#endif + x += len; + } + close(s); + ipmeok = 1; + return 1; +} diff -u -N qmail-1.03-orig/maildir++.c test/maildir++.c --- qmail-1.03-orig/maildir++.c Thu Jan 1 01:00:00 1970 +++ test/maildir++.c Thu Mar 1 23:58:55 2001 @@ -0,0 +1,627 @@ +#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 +#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 */ + close(fd); + 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 */ + close(fd); + return; /* ignore errors, perhaps the file was removed */ +} + +int quota_calc(char *dir, int *fd, quota_t *q) +{ + char bigbuf[5120]; /* as big as maildirsize max size */ + int i = 0; + + if ( ! stralloc_copys(&path, dir) ) 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 ) { + return quota_parsesize(q, fd, bigbuf, i); + } else { + return quota_calcsize(q, fd, bigbuf, i); + } +} + +int quota_recalc(char *dir, int *fd, quota_t *q, unsigned long size, + unsigned long count, int *perc) +{ + char bigbuf[5120]; /* as big as maildirsize max size */ + int i = 0; + int j; + int lines = 0; + time_t tm; + struct stat st; + + if ( ! stralloc_copys(&path, dir) ) 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 ) return -1; + } + /* need to recalculate the quota */ + close(*fd); *fd = -1; + unlink(path.s); + } + if ( quota_calcsize(q, fd, bigbuf, i) == -1 ) return -1; + return quota_check(q, size, count, perc); + +} + +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 == ' ' ) ; /* hope 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; + struct dirent *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; +// if ( close(*fd) == -1 ) goto fail; /* NFS dorks */ + + 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 */ +{ + struct dirent *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) */ +{ + struct dirent *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 -u -N qmail-1.03-orig/maildir++.h test/maildir++.h --- qmail-1.03-orig/maildir++.h Thu Jan 1 01:00:00 1970 +++ test/maildir++.h Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/popfetch.pl test/popfetch.pl --- qmail-1.03-orig/popfetch.pl Thu Jan 1 01:00:00 1970 +++ test/popfetch.pl Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/profile.patch test/profile.patch --- qmail-1.03-orig/profile.patch Thu Jan 1 01:00:00 1970 +++ test/profile.patch Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/qldap-debug.c test/qldap-debug.c --- qmail-1.03-orig/qldap-debug.c Thu Jan 1 01:00:00 1970 +++ test/qldap-debug.c Thu Mar 1 23:58:55 2001 @@ -0,0 +1,173 @@ +/* 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 "env.h" +#include "scan.h" +#include "readwrite.h" + +#include + +#ifdef DEBUG + +#define DEBUGLEN 1024 +char debugbuffer[DEBUGLEN]; +char num[FMT_ULONG]; +int debfd; +unsigned int dlevel = 0 ; +substdio ssdeb; + +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 ); +} +#endif + +void debug(int level, char *fmt, ...) +/* works like printf 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 */ +{ +#ifdef DEBUG + va_list args; + unsigned long ul; + long l; + char *s; + char *start; + char *cur; + void *p; + unsigned char c; + stralloc *sa; + + if ( ! ( dlevel & (unsigned int) level ) ) return; + va_start(args,fmt); + + start = fmt; + cur = fmt; + while (*cur) { + if (*cur == '%') { + if ( substdio_put(&ssdeb, start, cur-start) == -1 ) return; + 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(&ssdeb, "-", 1) == -1 ) return; + } + ul = (unsigned long) l; + if ( substdio_put(&ssdeb, num, fmt_ulong(num, ul) ) ) + return; + break; + case 'u': + ul = va_arg(args, unsigned long); + if ( substdio_put(&ssdeb, num, fmt_ulong(num, ul) ) ) + return; + break; + case 's': + s = va_arg(args, char *); + if ( !s ) { + if ( substdio_put(&ssdeb, nullString, + str_len(nullString) ) ) + return; + break; + } + if ( substdio_put(&ssdeb, s, str_len(s) ) ) return; + break; + case 'S': + sa = va_arg(args, stralloc *); + if ( !sa ) { + if ( substdio_put(&ssdeb, nullString, + str_len(nullString) ) ) + return; + break; + } + if ( substdio_put(&ssdeb, sa->s, sa->len ) ) return; + break; + case '%': + if ( substdio_put(&ssdeb, "%", 1) == -1 ) return; + break; + case 'p': + p = va_arg(args, void *); + ul = (unsigned long) p; + if ( substdio_put(&ssdeb, "0x", 2) ) return; + if ( substdio_put(&ssdeb, num, fmt_hexulong(num, ul) ) ) + return; + break; + case 'x': + ul = va_arg(args, unsigned long); + if ( substdio_put(&ssdeb, "0x", 2) ) return; + if ( substdio_put(&ssdeb, num, fmt_hexulong(num, ul) ) ) + return; + break; + case 'c': + c = (unsigned char) va_arg(args, unsigned int); + substdio_BPUTC(&ssdeb, c); + break; + } + start = ++cur; + } else { + ++cur; + } + } + if ( substdio_put(&ssdeb, start, cur-start) == -1 ) return; + if ( substdio_flush(&ssdeb) == -1 ) return; + va_end(args); + +#endif /* DEBUG */ +} + +void init_debug(int fd, unsigned long levelmask) +/* + * Known DEBUGLEVELs: + * 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) + */ +{ +#ifdef DEBUG + char *a = env_get("DEBUGLEVEL"); + + dlevel = 0; + if ( a && *a ) { + scan_ulong(a, &dlevel); + } + dlevel &= levelmask; + + substdio_fdbuf(&ssdeb, write, fd, debugbuffer, sizeof(debugbuffer) ); + +#endif /* DEBUG */ +} + diff -u -N qmail-1.03-orig/qldap-debug.h test/qldap-debug.h --- qmail-1.03-orig/qldap-debug.h Thu Jan 1 01:00:00 1970 +++ test/qldap-debug.h Thu Mar 1 23:58:55 2001 @@ -0,0 +1,26 @@ +/* qldap-debug.h, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#ifndef __QLDAP_DEBUG_H__ +#define __QLDAP_DEBUG_H__ + +#define STDERR 2 +#define STDOUT 1 + +void debug(int level, char *fmt, ...); +/* 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 init_debug(int fd, unsigned long levelmask); +/* reads the DEBUGLEVEL env var and sets the corresponding debuglevel */ + +#endif + diff -u -N qmail-1.03-orig/qldap-errno.c test/qldap-errno.c --- qmail-1.03-orig/qldap-errno.c Thu Jan 1 01:00:00 1970 +++ test/qldap-errno.c Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/qldap-errno.h test/qldap-errno.h --- qmail-1.03-orig/qldap-errno.h Thu Jan 1 01:00:00 1970 +++ test/qldap-errno.h Thu Mar 1 23:58:55 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 -u -N qmail-1.03-orig/qldap-ldaplib.c test/qldap-ldaplib.c --- qmail-1.03-orig/qldap-ldaplib.c Thu Jan 1 01:00:00 1970 +++ test/qldap-ldaplib.c Thu Mar 1 23:58:55 2001 @@ -0,0 +1,629 @@ +/* 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 */ + +#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 */ + +/* 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; + debug(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; + debug(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 */ + debug(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; + debug(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; + debug(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; + debug(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; + debug(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; + debug(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; + debug(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; + debug(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; + debug(64, "init_ldap: control/ldaplocaldelivery: %i\n", *localdelivery); + } + if (cluster != 0 ) { + t = cf; + t += fmt_strn(cf, "control/ldapcluster", 64); *t=0; + if (control_readint(cluster, ctrl_file) == -1) return -1; + debug(64, "init_ldap: control/ldapcluster: %i\n", *cluster); + } + if ( bind != 0 ) { + t = cf; + t += fmt_strn(cf, "control/ldaprebind", 64); *t=0; + if (control_readint(bind, ctrl_file) == -1) return -1; + debug(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; + debug(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; +} + +int ldap_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. */ +{ + LDAP *ld; + LDAPMessage *res, *msg; + char *dn; + int rc; + int version; + int num_entries; + struct timeval ldaptimeout = {0}; + +#ifndef USE_CLDAP + debug(128, "ldap_lookup: "); + /* allocate the connection */ + if ( (ld = ldap_init(qldap_server.s,PORT_LDAP)) == 0 ) { + qldap_errno = LDAP_INIT; + return -1; + } + debug(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; + } + debug(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 ) { + debug(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; + } + } + debug(128, ", bind successful\n"); + + /* 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 ) { + debug(64, "ldap_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 */ + debug(128, "ldap_lookup: "); + /* allocate the connection */ + if ( (ld = cldap_open(qldap_server.s,PORT_LDAP)) == 0 ) { + qldap_errno = LDAP_INIT; + return -1; + } + debug(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 ) + { + debug(64, "ldap_lookup: csearch for %s failed (%s)\n", + search->filter, ldap_err2string(rc) ); + qldap_errno = LDAP_SEARCH; + return -1; + } +#endif + + debug(128, "ldap_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) { + debug(64, "ldap_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); + debug(64, "ldap_lookup: rebind with %s failed (%s)", + dn, ldap_err2string(rc) ); + search->bind_ok = 0; + qldap_errno = LDAP_REBIND; + return -1; + } + search->bind_ok = 1; + debug(128, "ldap_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); +#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 */ + debug(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; + } + debug(64, "%s (from server)\n", vals[0]); + str_copy( info->uid, vals[0] ); + } else { + if (!( qldap_uid.s && qldap_uid.s[0] ) ) { + debug(64, "undefined\n"); + qldap_errno = LDAP_NEEDED; + return -1; + } + if ( (info->uid = alloc( qldap_uid.len ) ) == 0 ) { + qldap_errno = LDAP_ERRNO; + return -1; + } + debug(64, "%s (default)\n", qldap_uid.s); + str_copy( info->uid, qldap_uid.s ); + } + ldap_value_free(vals); + + debug(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; + } + debug(64, "%s (from server)\n", vals[0]); + str_copy( info->gid, vals[0] ); + } else { + if (!( qldap_gid.s && qldap_gid.s[0] ) ) { + debug(64, "undefined\n"); + qldap_errno = LDAP_NEEDED; + return -1; + } + if ( (info->gid = alloc( qldap_gid.len ) ) == 0 ) { + qldap_errno = LDAP_ERRNO; + return -1; + } + debug(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 */ + debug(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; + } + debug(64, "%s (from server)\n", vals[0]); + str_copy( info->user, vals[0] ); + } else { + debug(64, "undefined but NEEDED !!!!!!!\n"); + qldap_errno = LDAP_NEEDED; + return -1; + } + ldap_value_free(vals); + + /* check if the ldap entry is active */ + debug(64, "ldap_get_userinfo: %s: ", LDAP_ISACTIVE); + if ( (vals = ldap_get_values(ld,msg,LDAP_ISACTIVE)) != 0 ) { + debug(64, "%s (from server)\n", vals[0]); + if ( !str_diff(ISACTIVE_BOUNCE, vals[0]) ) + info->status = STATUS_BOUNCE; + else if ( !str_diff(ISACTIVE_NOPOP, vals[0]) ) + info->status = STATUS_NOPOP; + else info->status = STATUS_OK; + } else { + debug(64, "undefined\n"); + info->status = STATUS_UNDEF; + } + ldap_value_free(vals); + + debug(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; + } + debug(64, "%s (from server)\n", vals[0]); + str_copy( info->host, vals[0] ); + } else { + debug(64, "undefined\n"); + info->host = 0; + } + ldap_value_free(vals); + + debug(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)); + debug(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++ ) { + debug(64, "ldap_get_extrainfo: %s: ", info[i].what); + info[i].vals = ldap_get_values(ld,msg,info[i].what); + debug(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] != '/' ) { + debug(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; + } + debug(64, "%s=%s (from server)\n", LDAP_HOMEDIR, hdval[0]); + str_copy( *homedir, hdval[0] ); + } else { + debug(64, "%s=undefined\n", LDAP_HOMEDIR); + *homedir = 0; + } + if ( mmsval ) { + debug(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 ) { + debug(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 ) { + debug(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 { + debug(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 -u -N qmail-1.03-orig/qldap-ldaplib.h test/qldap-ldaplib.h --- qmail-1.03-orig/qldap-ldaplib.h Thu Jan 1 01:00:00 1970 +++ test/qldap-ldaplib.h Thu Mar 1 23:58:55 2001 @@ -0,0 +1,49 @@ +/* qldap-ldaplib.h, jeker@n-r-g.com, best viewed with tabsize = 4 */ +#ifndef __QLDAPLIB_H__ +#define __QLDAPLIB_H__ +#include "stralloc.h" + +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 ldap_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 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 -u -N qmail-1.03-orig/qldap-mdm.c test/qldap-mdm.c --- qmail-1.03-orig/qldap-mdm.c Thu Jan 1 01:00:00 1970 +++ test/qldap-mdm.c Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/qldap-mdm.h test/qldap-mdm.h --- qmail-1.03-orig/qldap-mdm.h Thu Jan 1 01:00:00 1970 +++ test/qldap-mdm.h Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/qldap-profile.c test/qldap-profile.c --- qmail-1.03-orig/qldap-profile.c Thu Jan 1 01:00:00 1970 +++ test/qldap-profile.c Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/qldap-profile.h test/qldap-profile.h --- qmail-1.03-orig/qldap-profile.h Thu Jan 1 01:00:00 1970 +++ test/qldap-profile.h Thu Mar 1 23:58:55 2001 @@ -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 -u -N qmail-1.03-orig/qmail-ldap.h test/qmail-ldap.h --- qmail-1.03-orig/qmail-ldap.h Thu Jan 1 01:00:00 1970 +++ test/qmail-ldap.h Thu Mar 1 23:58:55 2001 @@ -0,0 +1,105 @@ +#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 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_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 -u -N qmail-1.03-orig/qmail-ldaplookup.c test/qmail-ldaplookup.c --- qmail-1.03-orig/qmail-ldaplookup.c Thu Jan 1 01:00:00 1970 +++ test/qmail-ldaplookup.c Thu Mar 1 23:58:55 2001 @@ -0,0 +1,607 @@ +/* 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 "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 "compatibility.h" +#include "digest_md4.h" +#include "digest_md5.h" +#include "digest_rmd160.h" +#include "digest_sha1.h" +#include "open.h" + +#include + +/* 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 { uid, mail} mode_d; + +extern stralloc qldap_me; +extern stralloc qldap_objectclass; + +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 1024 +char buffer[LEN]; + +void output(char *fmt, ...); +static int cmp_passwd(unsigned char *clear, char *encrypted); +static void local_lookup(char *username, char *passwd); + +void usage() +{ + output( "qmail-ldaplookup: usage qmail-ldaplookup {-u uid | -m mail}\n"); + _exit(1); +} + +int main(int argc, char **argv) +{ + mode_d mode; + 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 */ + + + init_debug(STDERR, -1); + substdio_fdbuf(&ssout, write, STDOUT, buffer, sizeof(buffer) ); + + if (!argv[1] || !argv[2]) { + usage(); + } + + if ( ! stralloc_copys(&value, argv[2]) ) { + strerr_die2x(1, "ERROR: ", error_str(errno)); + } + if (!str_diff(argv[1], "-u") ) { + mode = uid; + } else if (!str_diff(argv[1], "-m") ) { + mode = mail; + } else usage(); + + if ( init_ldap( &locald, &cluster, &rebind, &homemaker, &defdot, &defquota, + "awarning) == -1 ) { + strerr_die2x(1, "ERROR: init_ldap failed: ", qldap_err_str(qldap_errno)); + } + + output( "init_ldap:\tpasswords are %scompared via rebind\n", + rebind?"":"not "); + output( "\t\tlocaldelivery:\t %s\n\t\tclustering:\t %s\n", + locald?"on":"off", cluster?"on":"off"); + output( "\t\tldapobjectclass: %S\n", &qldap_objectclass); + output( "\t\thomedirmaker:\t %s\n", homemaker.len?homemaker.s:"undefined"); + output( "\t\tdefaultDotMode:\t %s\n", defdot.s); + output( "\t\tdefaultQuota:\t %s\n", defquota.len?defquota.s:"undedined"); + output( "\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[2].what = LDAP_QUOTA; + extra[3].what = LDAP_FORWARDS; + extra[4].what = LDAP_PROGRAM; + extra[6].what = LDAP_MODE; + extra[7].what = LDAP_REPLYTEXT; + extra[5].what = LDAP_DOTMODE; + extra[0].what = LDAP_MAIL; + extra[1].what = LDAP_MAILALTERNATE; + if ( mode == mail ) { + extra[8].what = 0; /* under mail lookups no passwords are compared */ + attrs[15] = 0; + search.bindpw = 0; /* rebind off */ + } else if (!argv[3] || 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) ); + } + if ( !stralloc_copys(&filter,"(") ) { + strerr_die2x(1, "ERROR: can not create a filter: ", + error_str(errno)); + } + if ( mode == mail) { + /* build the search string for the email address */ + 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,"|(" ) || + !stralloc_cats(&filter, LDAP_MAIL ) || + !stralloc_cats(&filter, "=" ) || + !stralloc_cat(&filter,&value) || + !stralloc_cats(&filter,")(" ) || + !stralloc_cats(&filter,LDAP_MAILALTERNATE ) || + !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)); + } + } else { + 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)); + } + } + search.filter = filter.s; + output( "ldap_lookup:\tsearching with %s\n", filter.s); + ret = ldap_lookup(&search, attrs, &info, extra); + if ( ret != 0 ) { + output("ERROR: ldap_lookup not successful: ", + qldap_err_str(qldap_errno)); + if ( mode == uid && locald ) { + output("Will try a local password lookup\n"); + local_lookup(argv[2], argv[3]); + } else { + output("%s\n", mode!=uid?"only uid lookups can be local": + "localdelivery of so no local lookup"); + exit(111); + } + } + output( "ldap_lookup:\tsucceeded, found:\n"); + output( "\t\t%s: %s\n", LDAP_UID, info.user); + if (!chck_users(info.user) ) { + output( "\tWARNING %s contains illegal chars!\n", LDAP_UID); + } + output( "\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( "\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( "\tWARNING %s is out of range (%i...%i)\n", + LDAP_QMAILGID, GID_MIN, GID_MAX); + } + output( "\t\t%s: %s\n", LDAP_ISACTIVE, + info.status==STATUS_BOUNCE?ISACTIVE_BOUNCE: + info.status==STATUS_NOPOP?ISACTIVE_NOPOP: + info.status==STATUS_OK?ISACTIVE_ACTIVE:"undefined"); + + output( "\t\t%s: %s\n", LDAP_MAILSTORE, info.mms); + if (info.mms) if ( !chck_paths(info.mms) ) { + output( "\tWARNING %s contains illegal chars!\n", LDAP_MAILSTORE); + } + output( "\t\t%s: %s\n", LDAP_HOMEDIR, info.homedir); + if (info.homedir) if ( !chck_paths(info.homedir) ) { + output( "\tWARNING %s contains illegal chars!\n", LDAP_HOMEDIR); + } + + output( "\t\t%s: %s\n", LDAP_MAILHOST, info.host); + if ( cluster && info.host && str_diff(qldap_me.s, info.host) ) { + /* hostname is different, so I would reconnect */ + output( "\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( "\t\t%s: %s\n", extra[i].what, extra[i].vals[0]); + for ( j = 1; extra[i].vals[j] != 0; j++ ) { + output( "\t\t\t\t %s\n", extra[i].vals[j]); + if ( i == 4 && !chck_progs(extra[i].vals[j]) ) { + output( "\tWARNING %s contains illegal chars!\n", + LDAP_PROGRAM); + } + } + ldap_value_free(extra[i].vals); + } else { + output( "\t\t%s: no entry in the database\n", extra[i].what); + } + } + + if ( mode == uid && argv[3] && !rebind ) { + ret = cmp_passwd((unsigned char *) argv[3], extra[8].vals[0] ); + output( "ldap_lookup:\tpassword compare was %s\n", + ret==0?"successful":"not successful"); + } + return 0; +} + +char num[FMT_ULONG]; +static const char nullString[] = "(null pointer)"; + +void output(char *fmt, ...) +/* works like printf 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)) + * % is the % sign */ +{ + va_list args; + unsigned long ul; + long l; + char *s; + char *start; + char *cur; + unsigned char c; + stralloc *sa; + va_start(args,fmt); + + start = fmt; + cur = fmt; + while (*cur) { + if (*cur == '%') { + if ( substdio_put(&ssout, start, cur-start) == -1 ) return; + 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(&ssout, "-", 1) == -1 ) return; + } + ul = (unsigned long) l; + if ( substdio_put(&ssout, num, fmt_ulong(num, ul) ) ) + return; + break; + case 'u': + ul = va_arg(args, unsigned long); + if ( substdio_put(&ssout, num, fmt_ulong(num, ul) ) ) + return; + break; + case 's': + s = va_arg(args, char *); + if ( !s ) { + if ( substdio_put(&ssout, nullString, + str_len(nullString) ) ) + return; + break; + } + if ( substdio_put(&ssout, s, str_len(s) ) ) return; + break; + case 'S': + sa = va_arg(args, stralloc *); + if ( !sa ) { + if ( substdio_put(&ssout, nullString, + str_len(nullString) ) ) + return; + break; + } + if ( substdio_put(&ssout, sa->s, sa->len ) ) return; + break; + case '%': + if ( substdio_put(&ssout, "%", 1) == -1 ) return; + break; + case 'c': + c = (unsigned char) va_arg(args, unsigned int); + substdio_BPUTC(&ssout, c); + break; + } + start = ++cur; + } else { + ++cur; + } + } + if ( substdio_put(&ssout, start, cur-start) == -1 ) return; + if ( substdio_flush(&ssout) == -1 ) return; + va_end(args); + +} + +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("local_lookup:\tuser %s not found in passwd db\n", username); + _exit(0); + } + output( "local_lookup:\tsucceeded\n\t\tuser %s found in passwd database\n", + username); + output( "\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( "\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( "\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( "\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( "\t\tmaildir: %s (from ~/.qmail)\n", md.s); + + if ( !passwd ) { + output( "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( "\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( "\t\tcrypted passwd: %s\n", spw->upw_passwd); + ret = cmp_passwd((unsigned char *) passwd, spw->upw_passwd); +#else /* no AIX */ + output( "\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( "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; + ns_mta_hash_alg(hashed, salt, (char *) clear); + 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 */ + debug(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 */ + debug(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 -u -N qmail-1.03-orig/qmail-local.c test/qmail-local.c --- qmail-1.03-orig/qmail-local.c Mon Jun 15 12:53:16 1998 +++ test/qmail-local.c Thu Mar 1 23:58:55 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,17 @@ int flagforwardonly; char *x; + /* set up the variables for qmail-ldap */ + int slen; + int qmode; + int mboxdelivery; + int localdelivery; + int ldapprogdelivery; + char *s; + + mboxdelivery = 1; localdelivery = 0; ldapprogdelivery = 0; + + umask(077); sig_pipeignore(); @@ -487,8 +685,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 +807,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 ( s = env_get(ENV_REPLYTEXT) ) { + if ( flagdoit ) { + mailprogram("qmail-reply"); + } else { + sayit("reply to ",sender,str_len(sender)); + sayit("replytext ",s,str_len(s)); + } + } 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 +1019,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 -u -N qmail-1.03-orig/qmail-local.c.orig test/qmail-local.c.orig --- qmail-1.03-orig/qmail-local.c.orig Thu Jan 1 01:00:00 1970 +++ test/qmail-local.c.orig Thu Mar 1 23:58:55 2001 @@ -0,0 +1,698 @@ +#include +#include +#include "readwrite.h" +#include "sig.h" +#include "env.h" +#include "byte.h" +#include "exit.h" +#include "fork.h" +#include "open.h" +#include "wait.h" +#include "lock.h" +#include "seek.h" +#include "substdio.h" +#include "getln.h" +#include "strerr.h" +#include "subfd.h" +#include "sgetopt.h" +#include "alloc.h" +#include "error.h" +#include "stralloc.h" +#include "fmt.h" +#include "str.h" +#include "now.h" +#include "case.h" +#include "quote.h" +#include "qmail.h" +#include "slurpclose.h" +#include "myctime.h" +#include "gfrom.h" +#include "auto_patrn.h" + +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)"); } +void temp_rewind() { strerr_die1x(111,"Unable to rewind message. (#4.3.0)"); } +void temp_childcrashed() { strerr_die1x(111,"Aack, child crashed. (#4.3.0)"); } +void temp_fork() { strerr_die3x(111,"Unable to fork: ",error_str(errno),". (#4.3.0)"); } +void temp_read() { strerr_die3x(111,"Unable to read message: ",error_str(errno),". (#4.3.0)"); } +void temp_slowlock() +{ strerr_die1x(111,"File has been locked for 30 seconds straight. (#4.3.0)"); } +void temp_qmail(fn) char *fn; +{ strerr_die5x(111,"Unable to open ",fn,": ",error_str(errno),". (#4.3.0)"); } + +int flagdoit; +int flag99; + +char *user; +char *homedir; +char *local; +char *dash; +char *ext; +char *host; +char *sender; +char *aliasempty; + +stralloc safeext = {0}; +stralloc ufline = {0}; +stralloc rpline = {0}; +stralloc envrecip = {0}; +stralloc dtline = {0}; +stralloc qme = {0}; +stralloc ueo = {0}; +stralloc cmds = {0}; +stralloc messline = {0}; +stralloc foo = {0}; + +char buf[1024]; +char outbuf[1024]; + +/* child process */ + +char fntmptph[80 + FMT_ULONG * 2]; +char fnnewtph[80 + FMT_ULONG * 2]; +void tryunlinktmp() { unlink(fntmptph); } +void sigalrm() { tryunlinktmp(); _exit(3); } + +void maildir_child(dir) +char *dir; +{ + unsigned long pid; + unsigned long time; + char host[64]; + char *s; + int loop; + struct stat st; + int fd; + substdio ss; + substdio ssout; + + sig_alarmcatch(sigalrm); + if (chdir(dir) == -1) { if (error_temp(errno)) _exit(1); _exit(2); } + pid = getpid(); + host[0] = 0; + gethostname(host,sizeof(host)); + for (loop = 0;;++loop) + { + time = now(); + s = fntmptph; + 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; + if (stat(fntmptph,&st) == -1) if (errno == error_noent) break; + /* really should never get to this point */ + if (loop == 2) _exit(1); + sleep(2); + } + str_copy(fnnewtph,fntmptph); + byte_copy(fnnewtph,3,"new"); + + alarm(86400); + fd = open_excl(fntmptph); + if (fd == -1) _exit(1); + + substdio_fdbuf(&ss,read,0,buf,sizeof(buf)); + substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); + if (substdio_put(&ssout,rpline.s,rpline.len) == -1) goto fail; + if (substdio_put(&ssout,dtline.s,dtline.len) == -1) goto fail; + + switch(substdio_copy(&ssout,&ss)) + { + case -2: tryunlinktmp(); _exit(4); + case -3: 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) goto fail; + /* if it was error_exist, almost certainly successful; i hate NFS */ + tryunlinktmp(); _exit(0); + + fail: tryunlinktmp(); _exit(1); +} + +/* end child process */ + +void maildir(fn) +char *fn; +{ + int child; + int wstat; + + if (seek_begin(0) == -1) temp_rewind(); + + switch(child = fork()) + { + case -1: + temp_fork(); + case 0: + maildir_child(fn); + _exit(111); + } + + wait_pid(&wstat,child); + if (wait_crashed(wstat)) + temp_childcrashed(); + switch(wait_exitcode(wstat)) + { + case 0: break; + 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)"); + default: strerr_die1x(111,"Temporary error on maildir delivery. (#4.3.0)"); + } +} + +void mailfile(fn) +char *fn; +{ + int fd; + substdio ss; + substdio ssout; + int match; + seek_pos pos; + int flaglocked; + + if (seek_begin(0) == -1) temp_rewind(); + + fd = open_append(fn); + if (fd == -1) + strerr_die5x(111,"Unable to open ",fn,": ",error_str(errno),". (#4.2.1)"); + + sig_alarmcatch(temp_slowlock); + alarm(30); + flaglocked = (lock_ex(fd) != -1); + alarm(0); + sig_alarmdefault(); + + seek_end(fd); + pos = seek_cur(fd); + + substdio_fdbuf(&ss,read,0,buf,sizeof(buf)); + substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); + 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; + for (;;) + { + if (getln(&ss,&messline,&match,'\n') != 0) + { + strerr_warn3("Unable to read message: ",error_str(errno),". (#4.3.0)",0); + if (flaglocked) seek_trunc(fd,pos); close(fd); + _exit(111); + } + if (!match && !messline.len) break; + if (gfrom(messline.s,messline.len)) + if (substdio_bput(&ssout,">",1)) goto writeerrs; + if (substdio_bput(&ssout,messline.s,messline.len)) goto writeerrs; + if (!match) + { + if (substdio_bputs(&ssout,"\n")) goto writeerrs; + break; + } + } + if (substdio_bputs(&ssout,"\n")) goto writeerrs; + if (substdio_flush(&ssout)) goto writeerrs; + if (fsync(fd) == -1) goto writeerrs; + close(fd); + return; + + writeerrs: + strerr_warn5("Unable to write ",fn,": ",error_str(errno),". (#4.3.0)",0); + if (flaglocked) seek_trunc(fd,pos); + close(fd); + _exit(111); +} + +void mailprogram(prog) +char *prog; +{ + int child; + char *(args[4]); + int wstat; + + if (seek_begin(0) == -1) temp_rewind(); + + switch(child = fork()) + { + case -1: + temp_fork(); + case 0: + args[0] = "/bin/sh"; args[1] = "-c"; args[2] = prog; args[3] = 0; + sig_pipedefault(); + execv(*args,args); + strerr_die3x(111,"Unable to run /bin/sh: ",error_str(errno),". (#4.3.0)"); + } + + 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; + case 99: flag99 = 1; break; + default: _exit(111); + } +} + +unsigned long mailforward_qp = 0; + +void mailforward(recips) +char **recips; +{ + struct qmail qqt; + char *qqx; + substdio ss; + int match; + + if (seek_begin(0) == -1) temp_rewind(); + substdio_fdbuf(&ss,read,0,buf,sizeof(buf)); + + if (qmail_open(&qqt) == -1) temp_fork(); + mailforward_qp = qmail_qp(&qqt); + qmail_put(&qqt,dtline.s,dtline.len); + do + { + if (getln(&ss,&messline,&match,'\n') != 0) { qmail_fail(&qqt); break; } + qmail_put(&qqt,messline.s,messline.len); + } + while (match); + qmail_from(&qqt,ueo.s); + while (*recips) qmail_to(&qqt,*recips++); + qqx = qmail_close(&qqt); + if (!*qqx) return; + strerr_die3x(*qqx == 'D' ? 100 : 111,"Unable to forward message: ",qqx + 1,"."); +} + +void bouncexf() +{ + int match; + substdio ss; + + if (seek_begin(0) == -1) temp_rewind(); + substdio_fdbuf(&ss,read,0,buf,sizeof(buf)); + for (;;) + { + if (getln(&ss,&messline,&match,'\n') != 0) temp_read(); + if (!match) break; + if (messline.len <= 1) + break; + if (messline.len == dtline.len) + if (!str_diffn(messline.s,dtline.s,dtline.len)) + strerr_die1x(100,"This message is looping: it already has my Delivered-To line. (#5.4.6)"); + } +} + +void checkhome() +{ + struct stat st; + + if (stat(".",&st) == -1) + strerr_die3x(111,"Unable to stat home directory: ",error_str(errno),". (#4.3.0)"); + if (st.st_mode & auto_patrn) + strerr_die1x(111,"Uh-oh: home directory is writable. (#4.7.0)"); + if (st.st_mode & 01000) + if (flagdoit) + strerr_die1x(111,"Home directory is sticky: user is editing his .qmail file. (#4.2.1)"); + else + strerr_warn1("Warning: home directory is sticky.",0); +} + +int qmeox(dashowner) +char *dashowner; +{ + struct stat st; + + if (!stralloc_copys(&qme,".qmail")) temp_nomem(); + if (!stralloc_cats(&qme,dash)) temp_nomem(); + if (!stralloc_cat(&qme,&safeext)) temp_nomem(); + if (!stralloc_cats(&qme,dashowner)) temp_nomem(); + if (!stralloc_0(&qme)) temp_nomem(); + if (stat(qme.s,&st) == -1) + { + if (error_temp(errno)) temp_qmail(qme.s); + return -1; + } + return 0; +} + +int qmeexists(fd,cutable) +int *fd; +int *cutable; +{ + struct stat st; + + if (!stralloc_0(&qme)) temp_nomem(); + + *fd = open_read(qme.s); + if (*fd == -1) { + if (error_temp(errno)) temp_qmail(qme.s); + if (errno == error_perm) temp_qmail(qme.s); + if (errno == error_acces) temp_qmail(qme.s); + return 0; + } + + if (fstat(*fd,&st) == -1) temp_qmail(qme.s); + if ((st.st_mode & S_IFMT) == S_IFREG) { + if (st.st_mode & auto_patrn) + strerr_die1x(111,"Uh-oh: .qmail file is writable. (#4.7.0)"); + *cutable = !!(st.st_mode & 0100); + return 1; + } + close(*fd); + return 0; +} + +/* "" "": "" */ +/* "-/" "": "-/" "-/default" */ +/* "-/" "a": "-/a" "-/default" */ +/* "-/" "a-": "-/a-" "-/a-default" "-/default" */ +/* "-/" "a-b": "-/a-b" "-/a-default" "-/default" */ +/* "-/" "a-b-": "-/a-b-" "-/a-b-default" "-/a-default" "-/default" */ +/* "-/" "a-b-c": "-/a-b-c" "-/a-b-default" "-/a-default" "-/default" */ + +void qmesearch(fd,cutable) +int *fd; +int *cutable; +{ + int i; + + if (!stralloc_copys(&qme,".qmail")) temp_nomem(); + if (!stralloc_cats(&qme,dash)) temp_nomem(); + if (!stralloc_cat(&qme,&safeext)) temp_nomem(); + if (qmeexists(fd,cutable)) { + if (safeext.len >= 7) { + i = safeext.len - 7; + if (!byte_diff("default",7,safeext.s + i)) + if (i <= str_len(ext)) /* paranoia */ + if (!env_put2("DEFAULT",ext + i)) temp_nomem(); + } + return; + } + + for (i = safeext.len;i >= 0;--i) + if (!i || (safeext.s[i - 1] == '-')) { + if (!stralloc_copys(&qme,".qmail")) temp_nomem(); + if (!stralloc_cats(&qme,dash)) temp_nomem(); + if (!stralloc_catb(&qme,safeext.s,i)) temp_nomem(); + if (!stralloc_cats(&qme,"default")) temp_nomem(); + if (qmeexists(fd,cutable)) { + if (i <= str_len(ext)) /* paranoia */ + if (!env_put2("DEFAULT",ext + i)) temp_nomem(); + return; + } + } + + *fd = -1; +} + +unsigned long count_file = 0; +unsigned long count_forward = 0; +unsigned long count_program = 0; +char count_buf[FMT_ULONG]; + +void count_print() +{ + substdio_puts(subfdoutsmall,"did "); + substdio_put(subfdoutsmall,count_buf,fmt_ulong(count_buf,count_file)); + substdio_puts(subfdoutsmall,"+"); + substdio_put(subfdoutsmall,count_buf,fmt_ulong(count_buf,count_forward)); + substdio_puts(subfdoutsmall,"+"); + substdio_put(subfdoutsmall,count_buf,fmt_ulong(count_buf,count_program)); + substdio_puts(subfdoutsmall,"\n"); + if (mailforward_qp) + { + substdio_puts(subfdoutsmall,"qp "); + substdio_put(subfdoutsmall,count_buf,fmt_ulong(count_buf,mailforward_qp)); + substdio_puts(subfdoutsmall,"\n"); + } + substdio_flush(subfdoutsmall); +} + +void sayit(type,cmd,len) +char *type; +char *cmd; +int len; +{ + substdio_puts(subfdoutsmall,type); + substdio_put(subfdoutsmall,cmd,len); + substdio_putsflush(subfdoutsmall,"\n"); +} + +void main(argc,argv) +int argc; +char **argv; +{ + int opt; + int i; + int j; + int k; + int fd; + int numforward; + char **recips; + datetime_sec starttime; + int flagforwardonly; + char *x; + + umask(077); + sig_pipeignore(); + + if (!env_init()) temp_nomem(); + + flagdoit = 1; + while ((opt = getopt(argc,argv,"nN")) != opteof) + switch(opt) + { + case 'n': flagdoit = 0; break; + case 'N': flagdoit = 1; break; + default: + usage(); + } + argc -= optind; + argv += optind; + + if (!(user = *argv++)) usage(); + if (!(homedir = *argv++)) usage(); + if (!(local = *argv++)) usage(); + if (!(dash = *argv++)) usage(); + if (!(ext = *argv++)) usage(); + if (!(host = *argv++)) usage(); + if (!(sender = *argv++)) usage(); + if (!(aliasempty = *argv++)) usage(); + if (*argv) usage(); + + if (homedir[0] != '/') usage(); + if (chdir(homedir) == -1) + strerr_die5x(111,"Unable to switch to ",homedir,": ",error_str(errno),". (#4.3.0)"); + checkhome(); + + if (!env_put2("HOST",host)) temp_nomem(); + if (!env_put2("HOME",homedir)) temp_nomem(); + if (!env_put2("USER",user)) temp_nomem(); + if (!env_put2("LOCAL",local)) temp_nomem(); + + if (!stralloc_copys(&envrecip,local)) temp_nomem(); + if (!stralloc_cats(&envrecip,"@")) temp_nomem(); + if (!stralloc_cats(&envrecip,host)) temp_nomem(); + + if (!stralloc_copy(&foo,&envrecip)) temp_nomem(); + if (!stralloc_0(&foo)) temp_nomem(); + if (!env_put2("RECIPIENT",foo.s)) temp_nomem(); + + if (!stralloc_copys(&dtline,"Delivered-To: ")) temp_nomem(); + if (!stralloc_cat(&dtline,&envrecip)) temp_nomem(); + for (i = 0;i < dtline.len;++i) if (dtline.s[i] == '\n') dtline.s[i] = '_'; + if (!stralloc_cats(&dtline,"\n")) temp_nomem(); + + if (!stralloc_copy(&foo,&dtline)) temp_nomem(); + if (!stralloc_0(&foo)) temp_nomem(); + if (!env_put2("DTLINE",foo.s)) temp_nomem(); + + if (flagdoit) + bouncexf(); + + if (!env_put2("SENDER",sender)) temp_nomem(); + + if (!quote2(&foo,sender)) temp_nomem(); + if (!stralloc_copys(&rpline,"Return-Path: <")) temp_nomem(); + if (!stralloc_cat(&rpline,&foo)) temp_nomem(); + for (i = 0;i < rpline.len;++i) if (rpline.s[i] == '\n') rpline.s[i] = '_'; + if (!stralloc_cats(&rpline,">\n")) temp_nomem(); + + if (!stralloc_copy(&foo,&rpline)) temp_nomem(); + if (!stralloc_0(&foo)) temp_nomem(); + if (!env_put2("RPLINE",foo.s)) temp_nomem(); + + if (!stralloc_copys(&ufline,"From ")) temp_nomem(); + if (*sender) + { + int len; int i; char ch; + + len = str_len(sender); + if (!stralloc_readyplus(&ufline,len)) temp_nomem(); + for (i = 0;i < len;++i) + { + ch = sender[i]; + if ((ch == ' ') || (ch == '\t') || (ch == '\n')) ch = '-'; + ufline.s[ufline.len + i] = ch; + } + ufline.len += len; + } + else + 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 (!stralloc_copy(&foo,&ufline)) temp_nomem(); + if (!stralloc_0(&foo)) temp_nomem(); + if (!env_put2("UFLINE",foo.s)) temp_nomem(); + + x = ext; + if (!env_put2("EXT",x)) temp_nomem(); + x += str_chr(x,'-'); if (*x) ++x; + if (!env_put2("EXT2",x)) temp_nomem(); + x += str_chr(x,'-'); if (*x) ++x; + if (!env_put2("EXT3",x)) temp_nomem(); + x += str_chr(x,'-'); if (*x) ++x; + if (!env_put2("EXT4",x)) temp_nomem(); + + if (!stralloc_copys(&safeext,ext)) temp_nomem(); + case_lowerb(safeext.s,safeext.len); + for (i = 0;i < safeext.len;++i) + if (safeext.s[i] == '.') + safeext.s[i] = ':'; + + i = str_len(host); + i = byte_rchr(host,i,'.'); + if (!stralloc_copyb(&foo,host,i)) temp_nomem(); + if (!stralloc_0(&foo)) temp_nomem(); + if (!env_put2("HOST2",foo.s)) temp_nomem(); + i = byte_rchr(host,i,'.'); + if (!stralloc_copyb(&foo,host,i)) temp_nomem(); + if (!stralloc_0(&foo)) temp_nomem(); + if (!env_put2("HOST3",foo.s)) temp_nomem(); + i = byte_rchr(host,i,'.'); + if (!stralloc_copyb(&foo,host,i)) temp_nomem(); + if (!stralloc_0(&foo)) temp_nomem(); + 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(); + } + } + if (!stralloc_0(&ueo)) temp_nomem(); + if (!env_put2("NEWSENDER",ueo.s)) temp_nomem(); + + if (!stralloc_ready(&cmds,0)) temp_nomem(); + cmds.len = 0; + if (fd != -1) + if (slurpclose(fd,&cmds,256) == -1) temp_nomem(); + + if (!cmds.len) + { + if (!stralloc_copys(&cmds,aliasempty)) temp_nomem(); + flagforwardonly = 0; + } + if (!cmds.len || (cmds.s[cmds.len - 1] != '\n')) + if (!stralloc_cats(&cmds,"\n")) temp_nomem(); + + numforward = 0; + i = 0; + for (j = 0;j < cmds.len;++j) + if (cmds.s[j] == '\n') + { + switch(cmds.s[i]) { case '#': case '.': case '/': case '|': break; + default: ++numforward; } + i = j + 1; + } + + recips = (char **) alloc((numforward + 1) * sizeof(char *)); + if (!recips) temp_nomem(); + numforward = 0; + + flag99 = 0; + + i = 0; + for (j = 0;j < cmds.len;++j) + if (cmds.s[j] == '\n') + { + cmds.s[j] = 0; + k = j; + while ((k > i) && (cmds.s[k - 1] == ' ') || (cmds.s[k - 1] == '\t')) + cmds.s[--k] = 0; + switch(cmds.s[i]) + { + case 0: /* k == i */ + if (i) break; + strerr_die1x(111,"Uh-oh: first line of .qmail file is blank. (#4.2.1)"); + case '#': + break; + case '.': + case '/': + ++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] == '/') + if (flagdoit) maildir(cmds.s + i); + else sayit("maildir ",cmds.s + i,k - i); + else + if (flagdoit) mailfile(cmds.s + i); + else sayit("mbox ",cmds.s + i,k - i); + break; + case '|': + ++count_program; + if (flagforwardonly) strerr_die1x(111,"Uh-oh: .qmail has prog delivery but has x bit set. (#4.7.0)"); + if (flagdoit) mailprogram(cmds.s + i + 1); + else sayit("program ",cmds.s + i + 1,k - i - 1); + break; + case '+': + if (str_equal(cmds.s + i + 1,"list")) + flagforwardonly = 1; + break; + case '&': + ++i; + default: + ++count_forward; + if (flagdoit) recips[numforward++] = cmds.s + i; + else sayit("forward ",cmds.s + i,k - i); + break; + } + i = j + 1; + if (flag99) break; + } + + if (numforward) if (flagdoit) + { + recips[numforward] = 0; + mailforward(recips); + } + + count_print(); + _exit(0); +} diff -u -N qmail-1.03-orig/qmail-lspawn.c test/qmail-lspawn.c --- qmail-1.03-orig/qmail-lspawn.c Mon Jun 15 12:53:16 1998 +++ test/qmail-lspawn.c Thu Mar 1 23:59:20 2001 @@ -14,14 +14,104 @@ #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 "byte.h" +#include "open.h" +#include "readwrite.h" +#include "str.h" +#include +#include +#ifdef QLDAP_CLUSTER +#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 +static int allwrite(op,fd,buf,len) +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + register int w; + + while (len) { + w = op(fd,buf,len); + if (w == -1) { + if (errno == error_intr) continue; + return -1; /* note that some data may have been written */ + } + if (w == 0) ; /* luser's fault */ + buf += w; + len -= w; + } + return 0; +} + +/* 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 +122,599 @@ 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 reply; + int at; + int i; +#ifdef DASH_EXT + int dash; +#endif + int force_forward; + char *r; + stralloc filter = {0}; + unsigned long tid; + + /* check the mailaddress for illegal characters * + * escape '*', ,'\', '(' and ')' with a preceding '\' */ + if (!escape_forldap(mail) ) _exit(QLX_NOMEM); + + /* 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 */ + if (!stralloc_cats(&filter,"|(")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_MAIL)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"=")) _exit(QLX_NOMEM); + if (!stralloc_cat(&filter,mail)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,")(")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_MAILALTERNATE)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"=")) _exit(QLX_NOMEM); + if (!stralloc_cat(&filter,mail)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"))")) _exit(QLX_NOMEM); + if ( qldap_objectclass.len ) { + if (!stralloc_cats(&filter,")")) _exit(QLX_NOMEM); + } + if (!stralloc_0(&filter)) _exit(QLX_NOMEM); + + debug(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 = ldap_lookup(&search, attrs, &info, extra); + + if ( ret != 0 && qldap_errno == LDAP_NOSUCH ) { + /* extensions: catchall and dash-trick */ + at = 0; + r = mail->s; + i = mail->len; + for (at = i - 1; r[at] != '@' && at >= 0 ; at--) ; + /* handels also mailwith 2 @ */ + +#ifdef DASH_EXT + dash=0; + for (dash = at-1; r[dash] != '-' && dash > 0; dash--); + + /* dash trick */ + if ((dash > 0) && (dash < at)) { + if (!stralloc_copys(&filter, "")) _exit(QLX_NOMEM); + if (!stralloc_copys(&filter,"(|(" ) ) _exit(QLX_NOMEM); + /* optional objectclass */ + if (qldap_objectclass.len) { + 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 */ + if (!stralloc_cats(&filter,LDAP_MAIL)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"=")) _exit(QLX_NOMEM); + if (!stralloc_catb(&filter,r,dash)) _exit(QLX_NOMEM); + if (!stralloc_catb(&filter,r+at, i-at)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,")(")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_MAILALTERNATE)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"=")) _exit(QLX_NOMEM); + if (!stralloc_catb(&filter,r,dash)) _exit(QLX_NOMEM); + if (!stralloc_catb(&filter,r+at, i-at)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"))")) _exit(QLX_NOMEM); + if (!stralloc_0(&filter)) _exit(QLX_NOMEM); + + debug(16, "retry with filter '%s'\n", filter.s); + /* do the search */ + ret = ldap_lookup(&search, attrs, &info, extra); + } + + if (ret != 0 && qldap_errno == LDAP_NOSUCH) { +#endif + /* catchall */ + /* build the search string for the email address */ + if (!stralloc_copys(&filter, "")) _exit(QLX_NOMEM); + if (!stralloc_copys(&filter,"(|(" ) ) _exit(QLX_NOMEM); + /* optional objectclass */ + if (qldap_objectclass.len) { + 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 */ + if (!stralloc_cats(&filter,LDAP_MAIL)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"=")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_CATCH_ALL)) _exit(QLX_NOMEM); + if (!stralloc_catb(&filter,r+at, i-at)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,")(")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_MAILALTERNATE)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"=")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_CATCH_ALL)) _exit(QLX_NOMEM); + if (!stralloc_catb(&filter,r+at, i-at)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"))")) _exit(QLX_NOMEM); + if (!stralloc_0(&filter)) _exit(QLX_NOMEM); + + debug(16, "retry with filter '%s'\n", filter.s); + /* do the search for the catchall address */ + ret = ldap_lookup(&search, attrs, &info, extra); +#ifdef DASH_EXT + } +#endif + } + alloc_free(filter.s); filter.s = 0; + + 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? */ + debug(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 ) { + debug(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) ) { + /* 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); + +#ifdef DASH_EXT + /* Here we fill the nughde structure with the dash-field the extension field */ + if ((dash > 0) && (dash < (at-1))) { + if (!stralloc_cats(&nughde,"-")) _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + if (!stralloc_catb(&nughde,r+dash+1,at-dash-1)) _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + + } else { +#endif + + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + +#ifdef DASH_EXT + } +#endif + + /* get the quota for the user of that maildir mbox */ + if ( extra[0].vals != 0 ) { + debug(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 ) { + debug(32, "%s: %s\n", ENV_QUOTA, qldap_defaultquota.s); + if ( !env_put2(ENV_QUOTA, qldap_defaultquota.s )) _exit(QLX_NOMEM); + } else { + debug(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); + debug(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); + debug(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); + + /* get the deliverymode of the mailbox: * + * reply, echo, forwardonly, normal, nombox, localdelivery */ + reply = 0; + 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 ( !str_diff(MODE_REPLY, extra[3].vals[i]) ) reply = 1; + 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); + debug(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); + + if ( reply ) { + if ( extra[4].vals != 0 ) { + debug(32, "%s: %s\n", ENV_REPLYTEXT, extra[4].vals[0] ); + if ( !env_put2(ENV_REPLYTEXT, extra[4].vals[0]) ) _exit(QLX_NOMEM); + } + ldap_value_free(extra[4].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); + } + debug(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 */ + 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 +728,7 @@ if (errno != error_noent) _exit(QLX_CDB); - if (fd != -1) - { + if (fd != -1) { uint32 dlen; unsigned int i; @@ -111,20 +741,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 +759,7 @@ } --i; flagwild = 1; - } - while (i); + } while (i); close(fd); } @@ -142,10 +768,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 +784,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,54 +796,128 @@ { 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; + + /* XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX + * DEBUG should be handled better, so that it will not be included + * in maildelivery-failures mails */ + init_debug(fdout, -1); /* here are no critical data handled + * so debuglevel is free */ + 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); + debug(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: + debug(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 */ + debug(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]; + + debug(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: + debug(2, "warning: ldap lookup failed with %i\n", rv); + _exit(190 + rv); + break; + } /* end switch */ + /* debug(16, "nughde: %S\n", &nughde); */ x = nughde.s; xlen = nughde.len; 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; + debug(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 +931,94 @@ } return f; } + + +#ifdef QLDAP_CLUSTER +stralloc dtline = {0}; + +void bouncexf(int fdmess) +{ + char buf[1024]; + int match; + 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; + + 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); + } + + debug(8, "Forwarding to %S at host %s from %s ", to, host, from); + close(pi[0]); + allwrite(write, pi[1], "F", 1); + allwrite(write, pi[1], from, str_len(from)); + allwrite(write, pi[1], "",1); + allwrite(write, pi[1], "T",1); + allwrite(write, pi[1], to->s, to->len); + allwrite(write, pi[1], "", 1); + allwrite(write, pi[1], "", 1); + allwrite(write, pi[1], "H",1); + allwrite(write, pi[1], qldap_me.s, qldap_me.len); + allwrite(write, pi[1], "", 1); + close(pi[1]); + wait_pid(&wstat,child); + if (wait_crashed(wstat)) { + _exit(238); + } + + switch(i=wait_exitcode(wstat)) { + case 0: + debug(8, "was successful\n"); + _exit(0); + case 31: case 61: + debug(8, "failed (hard error %i)/n", i); + _exit(240); + default: + debug(8, "failed (soft error %i)/n", i); + _exit(239); + } +} +#endif + diff -u -N qmail-1.03-orig/qmail-lspawn.c.orig test/qmail-lspawn.c.orig --- qmail-1.03-orig/qmail-lspawn.c.orig Thu Jan 1 01:00:00 1970 +++ test/qmail-lspawn.c.orig Thu Mar 1 23:58:55 2001 @@ -0,0 +1,970 @@ +#include "fd.h" +#include "wait.h" +#include "prot.h" +#include "substdio.h" +#include "stralloc.h" +#include "scan.h" +#include "exit.h" +#include "fork.h" +#include "error.h" +#include "cdb.h" +#include "case.h" +#include "slurpclose.h" +#include "auto_qmail.h" +#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 "byte.h" +#include "open.h" +#include "readwrite.h" +#include "str.h" +#include +#include +#ifdef QLDAP_CLUSTER +#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 +static int allwrite(op,fd,buf,len) +register int (*op)(); +register int fd; +register char *buf; +register int len; +{ + register int w; + + while (len) { + w = op(fd,buf,len); + if (w == -1) { + if (errno == error_intr) continue; + return -1; /* note that some data may have been written */ + } + if (w == 0) ; /* luser's fault */ + buf += w; + len -= w; + } + return 0; +} + +/* 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); + } + + /* read the control files */ + get_qldap_controls(); + sig_hangupcatch(get_qldap_controls); + sig_hangupunblock(); +} + +int truncreport = 3000; + +void report(ss,wstat,s,len) +substdio *ss; +int wstat; +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"); + REPORT_RETURN; + } + switch(wait_exitcode(wstat)) { + case QLX_CDB: + 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"); + REPORT_RETURN; + + case QLX_SYS: + substdio_puts(ss,"ZTemporary failure in qmail-lspawn.\n"); + REPORT_RETURN; + + case QLX_NOALIAS: + 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"); + REPORT_RETURN; + + case QLX_USAGE: + substdio_puts(ss,"ZInternal qmail-lspawn bug.\n"); + REPORT_RETURN; + + case QLX_NFS: + substdio_puts(ss,"ZNFS failure in qmail-local.\n"); + REPORT_RETURN; + + case QLX_EXECHARD: + substdio_puts(ss,"DUnable to run qmail-local.\n"); + REPORT_RETURN; + + case QLX_EXECSOFT: + substdio_puts(ss,"ZUnable to run qmail-local.\n"); + REPORT_RETURN; + + case QLX_EXECPW: + 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; + + case 0: + 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; + } + + for (i = 0;i < len;++i) + if (!s[i]) + break; + + substdio_put(ss,s,i); +} + + +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 reply; + int at; + int i; + int force_forward; + char *r; + stralloc filter = {0}; + unsigned long tid; + + /* check the mailaddress for illegal characters * + * escape '*', ,'\', '(' and ')' with a preceding '\' */ + if (!escape_forldap(mail) ) _exit(QLX_NOMEM); + + /* 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 */ + if (!stralloc_cats(&filter,"|(")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_MAIL)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"=")) _exit(QLX_NOMEM); + if (!stralloc_cat(&filter,mail)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,")(")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_MAILALTERNATE)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"=")) _exit(QLX_NOMEM); + if (!stralloc_cat(&filter,mail)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"))")) _exit(QLX_NOMEM); + if ( qldap_objectclass.len ) { + if (!stralloc_cats(&filter,")")) _exit(QLX_NOMEM); + } + if (!stralloc_0(&filter)) _exit(QLX_NOMEM); + + debug(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 = ldap_lookup(&search, attrs, &info, extra); + + if ( ret != 0 && qldap_errno == LDAP_NOSUCH ) { + /* this handles the "catch all" extension */ + at = 0; + r = mail->s; + i = mail->len; + for (at = i - 1; r[at] != '@' && at >= 0 ; at--) ; + /* handels also mailwith 2 @ */ + /* build the search string for the email address */ + if (!stralloc_copys(&filter, "")) _exit(QLX_NOMEM); + if (!stralloc_copys(&filter,"(|(" ) ) _exit(QLX_NOMEM); + /* optional objectclass */ + if (qldap_objectclass.len) { + 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 */ + if (!stralloc_cats(&filter,LDAP_MAIL)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"=")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_CATCH_ALL)) _exit(QLX_NOMEM); + if (!stralloc_catb(&filter,r+at, i-at)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,")(")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_MAILALTERNATE)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"=")) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,LDAP_CATCH_ALL)) _exit(QLX_NOMEM); + if (!stralloc_catb(&filter,r+at, i-at)) _exit(QLX_NOMEM); + if (!stralloc_cats(&filter,"))")) _exit(QLX_NOMEM); + if (!stralloc_0(&filter)) _exit(QLX_NOMEM); + + debug(16, "retry with filter '%s'\n", filter.s); + /* do the search for the catchall address */ + ret = ldap_lookup(&search, attrs, &info, extra); + } + alloc_free(filter.s); filter.s = 0; + + 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? */ + debug(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 ) { + debug(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) ) { + /* 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 (!stralloc_0(&nughde)) _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 ) { + debug(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 ) { + debug(32, "%s: %s\n", ENV_QUOTA, qldap_defaultquota.s); + if ( !env_put2(ENV_QUOTA, qldap_defaultquota.s )) _exit(QLX_NOMEM); + } else { + debug(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); + debug(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); + debug(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); + + /* get the deliverymode of the mailbox: * + * reply, echo, forwardonly, normal, nombox, localdelivery */ + reply = 0; + 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 ( !str_diff(MODE_REPLY, extra[3].vals[i]) ) reply = 1; + 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); + debug(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); + + if ( reply ) { + if ( extra[4].vals != 0 ) { + debug(32, "%s: %s\n", ENV_REPLYTEXT, extra[4].vals[0] ); + if ( !env_put2(ENV_REPLYTEXT, extra[4].vals[0]) ) _exit(QLX_NOMEM); + } + ldap_value_free(extra[4].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); + } + debug(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 */ + 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], + gpwpid, + gpwstat, + r, + fd, + flagwild; + + if (!stralloc_copys(&lower,"!")) _exit(QLX_NOMEM); + if (!stralloc_cats(&lower,local)) _exit(QLX_NOMEM); + if (!stralloc_0(&lower)) _exit(QLX_NOMEM); + case_lowerb(lower.s,lower.len); + + if (!stralloc_copys(&nughde,"")) _exit(QLX_NOMEM); + + fd = open_read("users/cdb"); + if (fd == -1) + if (errno != error_noent) + _exit(QLX_CDB); + + if (fd != -1) { + uint32 dlen; + unsigned int i; + + r = cdb_seek(fd,"",0,&dlen); + if (r != 1) _exit(QLX_CDB); + if (!stralloc_ready(&wildchars,(unsigned int) dlen)) _exit(QLX_NOMEM); + wildchars.len = dlen; + if (cdb_bread(fd,wildchars.s,wildchars.len) == -1) _exit(QLX_CDB); + + i = lower.len; + flagwild = 0; + + do { + /* i > 0 */ + 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 (!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_0(&nughde)) _exit(QLX_NOMEM); + close(fd); + return; + } + } + --i; + flagwild = 1; + } while (i); + + close(fd); + } + + if (pipe(pi) == -1) _exit(QLX_SYS); + args[0] = "bin/qmail-getpw"; + args[1] = local; + args[2] = 0; + 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); + close(pi[0]); + if (fd_move(1,pi[1]) == -1) _exit(QLX_SYS); + execv(*args,args); + _exit(QLX_EXECPW); + } + close(pi[1]); + + if (slurpclose(pi[0],&nughde,128) == -1) _exit(QLX_SYS); + + if (wait_pid(&gpwstat,gpwpid) != -1) { + if (wait_crashed(gpwstat)) _exit(QLX_SYS); + if (wait_exitcode(gpwstat) != 0) _exit(wait_exitcode(gpwstat)); + } +} + +int spawn(fdmess,fdout,s,r,at) +int fdmess; int fdout; +char *s; char *r; int at; +{ + int f; + + if (!(f = fork())) { + char *(args[11]); + unsigned long u; + int n, + uid, + gid; + char *x; + unsigned int xlen; + + stralloc ra = {0}; + int rv; + + /* XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX + * DEBUG should be handled better, so that it will not be included + * in maildelivery-failures mails */ + init_debug(fdout, -1); /* here are no critical data handled + * so debuglevel is free */ + + 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); + debug(16, "mailaddr: %S\n", &ra); + /* end -- save the @ */ + + r[at] = 0; + if (!r[0]) _exit(0); /* <> */ + + if (chdir(auto_qmail) == -1) _exit(QLX_USAGE); + + /* do the address lookup */ + rv = qldap_get(&ra, s, fdmess); + switch( rv ) { + case 0: + debug(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 */ + debug(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]; + + debug(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: + debug(2, "warning: ldap lookup failed with %i\n", rv); + _exit(190 + rv); + break; + } /* end switch */ + + /* debug(16, "nughde: %S\n", &nughde); */ + x = nughde.s; + xlen = nughde.len; + + 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(198); x += n; xlen -= n; + + scan_ulong(x,&u); + gid = u; + + 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(198); x += n; xlen -= n; + + args[4] = r; + + args[5] = x; + + 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(198); x += n; xlen -= n; + + args[7] = r + at + 1; + args[8] = s; + args[9] = aliasempty; + args[10] = 0; + + debug(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); + if (prot_gid(gid) == -1) _exit(QLX_USAGE); + if (prot_uid(uid) == -1) _exit(QLX_USAGE); + if (!getuid()) _exit(QLX_ROOT); + + execv(*args,args); + if (error_temp(errno)) _exit(QLX_EXECSOFT); + _exit(QLX_EXECHARD); + } + return f; +} + + +#ifdef QLDAP_CLUSTER +stralloc dtline = {0}; + +void bouncexf(int fdmess) +{ + char buf[1024]; + int match; + 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; + + 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); + } + + debug(8, "Forwarding to %S at host %s from %s ", to, host, from); + close(pi[0]); + allwrite(write, pi[1], "F", 1); + allwrite(write, pi[1], from, str_len(from)); + allwrite(write, pi[1], "",1); + allwrite(write, pi[1], "T",1); + allwrite(write, pi[1], to->s, to->len); + allwrite(write, pi[1], "", 1); + allwrite(write, pi[1], "", 1); + allwrite(write, pi[1], "H",1); + allwrite(write, pi[1], qldap_me.s, qldap_me.len); + allwrite(write, pi[1], "", 1); + close(pi[1]); + wait_pid(&wstat,child); + if (wait_crashed(wstat)) { + _exit(238); + } + + switch(i=wait_exitcode(wstat)) { + case 0: + debug(8, "was successful\n"); + _exit(0); + case 31: case 61: + debug(8, "failed (hard error %i)/n", i); + _exit(240); + default: + debug(8, "failed (soft error %i)/n", i); + _exit(239); + } +} +#endif + diff -u -N qmail-1.03-orig/qmail-pop3d.c test/qmail-pop3d.c --- qmail-1.03-orig/qmail-pop3d.c Mon Jun 15 12:53:16 1998 +++ test/qmail-pop3d.c Thu Mar 1 23:58:54 2001 @@ -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 -u -N qmail-1.03-orig/qmail-pop3d.c.orig test/qmail-pop3d.c.orig --- qmail-1.03-orig/qmail-pop3d.c.orig Thu Jan 1 01:00:00 1970 +++ test/qmail-pop3d.c.orig Thu Mar 1 23:58:54 2001 @@ -0,0 +1,305 @@ +#include +#include +#include "commands.h" +#include "sig.h" +#include "getln.h" +#include "stralloc.h" +#include "substdio.h" +#include "alloc.h" +#include "open.h" +#include "prioq.h" +#include "scan.h" +#include "fmt.h" +#include "str.h" +#include "exit.h" +#include "maildir.h" +#include "readwrite.h" +#include "timeoutread.h" +#include "timeoutwrite.h" + +void die() { _exit(0); } + +int saferead(fd,buf,len) int fd; char *buf; int len; +{ + int r; + r = timeoutread(1200,fd,buf,len); + if (r <= 0) die(); + return r; +} + +int safewrite(fd,buf,len) int fd; char *buf; int len; +{ + int r; + r = timeoutwrite(1200,fd,buf,len); + if (r <= 0) die(); + return r; +} + +char ssoutbuf[1024]; +substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); + +char ssinbuf[128]; +substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); + +void put(buf,len) char *buf; int len; +{ + substdio_put(&ssout,buf,len); +} +void puts(s) char *s; +{ + substdio_puts(&ssout,s); +} +void flush() +{ + substdio_flush(&ssout); +} +void err(s) char *s; +{ + puts("-ERR "); + puts(s); + puts("\r\n"); + flush(); +} + +void die_nomem() { err("out of memory"); die(); } +void die_nomaildir() { err("this user has no $HOME/Maildir"); die(); } +void die_scan() { err("unable to scan $HOME/Maildir"); die(); } + +void err_syntax() { err("syntax error"); } +void err_unimpl() { err("unimplemented"); } +void err_deleted() { err("already deleted"); } +void err_nozero() { err("messages are counted from 1"); } +void err_toobig() { err("not that many messages"); } +void err_nosuch() { err("unable to open that message"); } +void err_nounlink() { err("unable to unlink all deleted messages"); } + +void okay() { puts("+OK \r\n"); flush(); } + +void printfn(fn) char *fn; +{ + fn += 4; + put(fn,str_chr(fn,':')); +} + +char strnum[FMT_ULONG]; +stralloc line = {0}; + +void blast(ssfrom,limit) +substdio *ssfrom; +unsigned long limit; +{ + int match; + int inheaders = 1; + + for (;;) { + if (getln(ssfrom,&line,&match,'\n') != 0) die(); + if (!match && !line.len) break; + if (match) --line.len; /* no way to pass this info over POP */ + if (limit) if (!inheaders) if (!--limit) break; + if (!line.len) + inheaders = 0; + else + if (line.s[0] == '.') + put(".",1); + put(line.s,line.len); + put("\r\n",2); + if (!match) break; + } + put("\r\n.\r\n",5); + flush(); +} + +stralloc filenames = {0}; +prioq pq = {0}; + +struct message { + int flagdeleted; + unsigned long size; + char *fn; +} *m; +int numm; + +int last = 0; + +void getlist() +{ + struct prioq_elt pe; + struct stat st; + int i; + + maildir_clean(&line); + if (maildir_scan(&pq,&filenames,1,1) == -1) die_scan(); + + numm = pq.p ? pq.len : 0; + m = (struct message *) alloc(numm * sizeof(struct message)); + if (!m) die_nomem(); + + for (i = 0;i < numm;++i) { + if (!prioq_min(&pq,&pe)) { numm = i; break; } + prioq_delmin(&pq); + m[i].fn = filenames.s + pe.id; + m[i].flagdeleted = 0; + if (stat(m[i].fn,&st) == -1) + m[i].size = 0; + else + m[i].size = st.st_size; + } +} + +void pop3_stat() +{ + int i; + unsigned long total; + + total = 0; + for (i = 0;i < numm;++i) if (!m[i].flagdeleted) total += m[i].size; + puts("+OK "); + put(strnum,fmt_uint(strnum,numm)); + puts(" "); + put(strnum,fmt_ulong(strnum,total)); + puts("\r\n"); + flush(); +} + +void pop3_rset() +{ + int i; + for (i = 0;i < numm;++i) m[i].flagdeleted = 0; + last = 0; + okay(); +} + +void pop3_last() +{ + puts("+OK "); + put(strnum,fmt_uint(strnum,last)); + puts("\r\n"); + flush(); +} + +void pop3_quit() +{ + int i; + for (i = 0;i < numm;++i) + if (m[i].flagdeleted) { + if (unlink(m[i].fn) == -1) err_nounlink(); + } + else + if (str_start(m[i].fn,"new/")) { + if (!stralloc_copys(&line,"cur/")) die_nomem(); + if (!stralloc_cats(&line,m[i].fn + 4)) die_nomem(); + if (!stralloc_cats(&line,":2,")) die_nomem(); + if (!stralloc_0(&line)) die_nomem(); + rename(m[i].fn,line.s); /* if it fails, bummer */ + } + okay(); + die(); +} + +int msgno(arg) char *arg; +{ + unsigned long u; + if (!scan_ulong(arg,&u)) { err_syntax(); return -1; } + if (!u) { err_nozero(); return -1; } + --u; + if (u >= numm) { err_toobig(); return -1; } + if (m[u].flagdeleted) { err_deleted(); return -1; } + return u; +} + +void pop3_dele(arg) char *arg; +{ + int i; + i = msgno(arg); + if (i == -1) return; + m[i].flagdeleted = 1; + if (i + 1 > last) last = i + 1; + okay(); +} + +void list(i,flaguidl) +int i; +int flaguidl; +{ + put(strnum,fmt_uint(strnum,i + 1)); + puts(" "); + if (flaguidl) printfn(m[i].fn); + else put(strnum,fmt_ulong(strnum,m[i].size)); + puts("\r\n"); +} + +void dolisting(arg,flaguidl) char *arg; int flaguidl; +{ + unsigned int i; + if (*arg) { + i = msgno(arg); + if (i == -1) return; + puts("+OK "); + list(i,flaguidl); + } + else { + okay(); + for (i = 0;i < numm;++i) + if (!m[i].flagdeleted) + list(i,flaguidl); + puts(".\r\n"); + } + flush(); +} + +void pop3_uidl(arg) char *arg; { dolisting(arg,1); } +void pop3_list(arg) char *arg; { dolisting(arg,0); } + +substdio ssmsg; char ssmsgbuf[1024]; + +void pop3_top(arg) char *arg; +{ + int i; + unsigned long limit; + int fd; + + i = msgno(arg); + if (i == -1) return; + + arg += scan_ulong(arg,&limit); + while (*arg == ' ') ++arg; + if (scan_ulong(arg,&limit)) ++limit; else limit = 0; + + fd = open_read(m[i].fn); + if (fd == -1) { err_nosuch(); return; } + okay(); + substdio_fdbuf(&ssmsg,read,fd,ssmsgbuf,sizeof(ssmsgbuf)); + blast(&ssmsg,limit); + close(fd); +} + +struct commands pop3commands[] = { + { "quit", pop3_quit, 0 } +, { "stat", pop3_stat, 0 } +, { "list", pop3_list, 0 } +, { "uidl", pop3_uidl, 0 } +, { "dele", pop3_dele, 0 } +, { "retr", pop3_top, 0 } +, { "rset", pop3_rset, 0 } +, { "last", pop3_last, 0 } +, { "top", pop3_top, 0 } +, { "noop", okay, 0 } +, { 0, err_unimpl, 0 } +} ; + +void main(argc,argv) +int argc; +char **argv; +{ + sig_alarmcatch(die); + sig_pipeignore(); + + if (!argv[1]) die_nomaildir(); + if (chdir(argv[1]) == -1) die_nomaildir(); + + getlist(); + + okay(); + commands(&ssin,pop3commands); + die(); +} diff -u -N qmail-1.03-orig/qmail-popup.c test/qmail-popup.c --- qmail-1.03-orig/qmail-popup.c Mon Jun 15 12:53:16 1998 +++ test/qmail-popup.c Thu Mar 1 23:58:54 2001 @@ -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 -u -N qmail-1.03-orig/qmail-popup.c.orig test/qmail-popup.c.orig --- qmail-1.03-orig/qmail-popup.c.orig Thu Jan 1 01:00:00 1970 +++ test/qmail-popup.c.orig Thu Mar 1 23:58:54 2001 @@ -0,0 +1,183 @@ +#include "commands.h" +#include "fd.h" +#include "sig.h" +#include "stralloc.h" +#include "substdio.h" +#include "alloc.h" +#include "wait.h" +#include "str.h" +#include "byte.h" +#include "now.h" +#include "fmt.h" +#include "exit.h" +#include "readwrite.h" +#include "timeoutread.h" +#include "timeoutwrite.h" + +void die() { _exit(1); } + +int saferead(fd,buf,len) int fd; char *buf; int len; +{ + int r; + r = timeoutread(1200,fd,buf,len); + if (r <= 0) die(); + return r; +} + +int safewrite(fd,buf,len) int fd; char *buf; int len; +{ + int r; + r = timeoutwrite(1200,fd,buf,len); + if (r <= 0) die(); + return r; +} + +char ssoutbuf[128]; +substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); + +char ssinbuf[128]; +substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); + +void puts(s) char *s; +{ + substdio_puts(&ssout,s); +} +void flush() +{ + substdio_flush(&ssout); +} +void err(s) char *s; +{ + puts("-ERR "); + puts(s); + puts("\r\n"); + flush(); +} + +void die_usage() { err("usage: popup hostname subprogram"); die(); } +void die_nomem() { err("out of memory"); die(); } +void die_pipe() { err("unable to open pipe"); die(); } +void die_write() { err("unable to write pipe"); die(); } +void die_fork() { err("unable to fork"); die(); } +void die_childcrashed() { err("aack, child crashed"); } +void die_badauth() { err("authorization failed"); } + +void err_syntax() { err("syntax error"); } +void err_wantuser() { err("USER first"); } +void err_authoriz() { err("authorization first"); } + +void okay() { puts("+OK \r\n"); flush(); } +void pop3_quit() { okay(); die(); } + + +char unique[FMT_ULONG + FMT_ULONG + 3]; +char *hostname; +stralloc username = {0}; +int seenuser = 0; +char **childargs; +substdio ssup; +char upbuf[128]; + + +void doanddie(user,userlen,pass) +char *user; +unsigned int userlen; /* including 0 byte */ +char *pass; +{ + int child; + int wstat; + int pi[2]; + + if (fd_copy(2,1) == -1) die_pipe(); + close(3); + if (pipe(pi) == -1) die_pipe(); + if (pi[0] != 3) die_pipe(); + switch(child = fork()) { + case -1: + die_fork(); + case 0: + close(pi[1]); + sig_pipedefault(); + execvp(*childargs,childargs); + _exit(1); + } + close(pi[0]); + substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf); + if (substdio_put(&ssup,user,userlen) == -1) die_write(); + if (substdio_put(&ssup,pass,str_len(pass) + 1) == -1) die_write(); + if (substdio_puts(&ssup,"<") == -1) die_write(); + if (substdio_puts(&ssup,unique) == -1) die_write(); + if (substdio_puts(&ssup,hostname) == -1) die_write(); + if (substdio_put(&ssup,">",2) == -1) die_write(); + if (substdio_flush(&ssup) == -1) die_write(); + close(pi[1]); + byte_zero(pass,str_len(pass)); + byte_zero(upbuf,sizeof upbuf); + if (wait_pid(&wstat,child) == -1) die(); + if (wait_crashed(wstat)) die_childcrashed(); + if (wait_exitcode(wstat)) die_badauth(); + die(); +} +void pop3_greet() +{ + char *s; + s = unique; + s += fmt_uint(s,getpid()); + *s++ = '.'; + s += fmt_ulong(s,(unsigned long) now()); + *s++ = '@'; + *s++ = 0; + puts("+OK <"); + puts(unique); + puts(hostname); + puts(">\r\n"); + flush(); +} +void pop3_user(arg) char *arg; +{ + if (!*arg) { err_syntax(); return; } + okay(); + seenuser = 1; + if (!stralloc_copys(&username,arg)) die_nomem(); + if (!stralloc_0(&username)) die_nomem(); +} +void pop3_pass(arg) char *arg; +{ + if (!seenuser) { err_wantuser(); return; } + if (!*arg) { err_syntax(); return; } + doanddie(username.s,username.len,arg); +} +void pop3_apop(arg) char *arg; +{ + char *space; + space = arg + str_chr(arg,' '); + if (!*space) { err_syntax(); return; } + *space++ = 0; + doanddie(arg,space - arg,space); +} + +struct commands pop3commands[] = { + { "user", pop3_user, 0 } +, { "pass", pop3_pass, 0 } +, { "apop", pop3_apop, 0 } +, { "quit", pop3_quit, 0 } +, { "noop", okay, 0 } +, { 0, err_authoriz, 0 } +} ; + +void main(argc,argv) +int argc; +char **argv; +{ + sig_alarmcatch(die); + sig_pipeignore(); + + hostname = argv[1]; + if (!hostname) die_usage(); + childargs = argv + 2; + if (!*childargs) die_usage(); + + pop3_greet(); + commands(&ssin,pop3commands); + die(); +} diff -u -N qmail-1.03-orig/qmail-qmqpc.c test/qmail-qmqpc.c --- qmail-1.03-orig/qmail-qmqpc.c Mon Jun 15 12:53:16 1998 +++ test/qmail-qmqpc.c Thu Mar 1 23:58:54 2001 @@ -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 -u -N qmail-1.03-orig/qmail-qmqpc.c.orig test/qmail-qmqpc.c.orig --- qmail-1.03-orig/qmail-qmqpc.c.orig Thu Jan 1 01:00:00 1970 +++ test/qmail-qmqpc.c.orig Thu Mar 1 23:58:54 2001 @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include "substdio.h" +#include "getln.h" +#include "readwrite.h" +#include "exit.h" +#include "stralloc.h" +#include "slurpclose.h" +#include "error.h" +#include "sig.h" +#include "ip.h" +#include "timeoutconn.h" +#include "timeoutread.h" +#include "timeoutwrite.h" +#include "auto_qmail.h" +#include "control.h" +#include "fmt.h" + +#define PORT_QMQP 628 + +void die_success() { _exit(0); } +void die_perm() { _exit(31); } +void nomem() { _exit(51); } +void die_read() { if (errno == error_nomem) nomem(); _exit(54); } +void die_control() { _exit(55); } +void die_socket() { _exit(56); } +void die_home() { _exit(61); } +void die_temp() { _exit(71); } +void die_conn() { _exit(74); } +void die_format() { _exit(91); } + +int lasterror = 55; +int qmqpfd; + +int saferead(fd,buf,len) int fd; char *buf; int len; +{ + int r; + r = timeoutread(60,qmqpfd,buf,len); + if (r <= 0) die_conn(); + return r; +} +int safewrite(fd,buf,len) int fd; char *buf; int len; +{ + int r; + r = timeoutwrite(60,qmqpfd,buf,len); + if (r <= 0) die_conn(); + return r; +} + +char buf[1024]; +substdio to = SUBSTDIO_FDBUF(safewrite,-1,buf,sizeof buf); +substdio from = SUBSTDIO_FDBUF(saferead,-1,buf,sizeof buf); +substdio envelope = SUBSTDIO_FDBUF(read,1,buf,sizeof buf); +/* WARNING: can use only one of these at a time! */ + +stralloc beforemessage = {0}; +stralloc message = {0}; +stralloc aftermessage = {0}; + +char strnum[FMT_ULONG]; +stralloc line = {0}; + +void getmess() +{ + int match; + + if (slurpclose(0,&message,1024) == -1) die_read(); + + strnum[fmt_ulong(strnum,(unsigned long) message.len)] = 0; + if (!stralloc_copys(&beforemessage,strnum)) nomem(); + if (!stralloc_cats(&beforemessage,":")) nomem(); + if (!stralloc_copys(&aftermessage,",")) nomem(); + + if (getln(&envelope,&line,&match,'\0') == -1) die_read(); + if (!match) die_format(); + if (line.len < 2) die_format(); + if (line.s[0] != 'F') die_format(); + + strnum[fmt_ulong(strnum,(unsigned long) line.len - 2)] = 0; + if (!stralloc_cats(&aftermessage,strnum)) nomem(); + if (!stralloc_cats(&aftermessage,":")) nomem(); + if (!stralloc_catb(&aftermessage,line.s + 1,line.len - 2)) nomem(); + if (!stralloc_cats(&aftermessage,",")) nomem(); + + for (;;) { + if (getln(&envelope,&line,&match,'\0') == -1) die_read(); + if (!match) die_format(); + if (line.len < 2) break; + if (line.s[0] != 'T') die_format(); + + strnum[fmt_ulong(strnum,(unsigned long) line.len - 2)] = 0; + if (!stralloc_cats(&aftermessage,strnum)) nomem(); + if (!stralloc_cats(&aftermessage,":")) nomem(); + if (!stralloc_catb(&aftermessage,line.s + 1,line.len - 2)) nomem(); + if (!stralloc_cats(&aftermessage,",")) nomem(); + } +} + +void doit(server) +char *server; +{ + struct ip_address ip; + char ch; + + if (!ip_scan(server,&ip)) return; + + qmqpfd = socket(AF_INET,SOCK_STREAM,0); + if (qmqpfd == -1) die_socket(); + + if (timeoutconn(qmqpfd,&ip,PORT_QMQP,10) != 0) { + lasterror = 73; + if (errno == error_timeout) lasterror = 72; + close(qmqpfd); + return; + } + + strnum[fmt_ulong(strnum,(unsigned long) (beforemessage.len + message.len + aftermessage.len))] = 0; + substdio_puts(&to,strnum); + substdio_puts(&to,":"); + substdio_put(&to,beforemessage.s,beforemessage.len); + substdio_put(&to,message.s,message.len); + substdio_put(&to,aftermessage.s,aftermessage.len); + substdio_puts(&to,","); + substdio_flush(&to); + + for (;;) { + substdio_get(&from,&ch,1); + if (ch == 'K') die_success(); + if (ch == 'Z') die_temp(); + if (ch == 'D') die_perm(); + } +} + +stralloc servers = {0}; + +main() +{ + int i; + int j; + + sig_pipeignore(); + + if (chdir(auto_qmail) == -1) die_home(); + if (control_init() == -1) die_control(); + if (control_readfile(&servers,"control/qmqpservers",0) != 1) die_control(); + + getmess(); + + i = 0; + for (j = 0;j < servers.len;++j) + if (!servers.s[j]) { + doit(servers.s + i); + i = j + 1; + } + + _exit(lasterror); +} diff -u -N qmail-1.03-orig/qmail-qmqpd.c test/qmail-qmqpd.c --- qmail-1.03-orig/qmail-qmqpd.c Mon Jun 15 12:53:16 1998 +++ test/qmail-qmqpd.c Thu Mar 1 23:58:54 2001 @@ -78,7 +78,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 -u -N qmail-1.03-orig/qmail-qmqpd.c.orig test/qmail-qmqpd.c.orig --- qmail-1.03-orig/qmail-qmqpd.c.orig Thu Jan 1 01:00:00 1970 +++ test/qmail-qmqpd.c.orig Thu Mar 1 23:58:54 2001 @@ -0,0 +1,174 @@ +#include "auto_qmail.h" +#include "qmail.h" +#include "received.h" +#include "sig.h" +#include "substdio.h" +#include "readwrite.h" +#include "exit.h" +#include "now.h" +#include "fmt.h" +#include "env.h" + +void resources() { _exit(111); } + +int safewrite(fd,buf,len) int fd; char *buf; int len; +{ + int r; + r = write(fd,buf,len); + if (r <= 0) _exit(0); + return r; +} +int saferead(fd,buf,len) int fd; char *buf; int len; +{ + int r; + r = read(fd,buf,len); + if (r <= 0) _exit(0); + return r; +} + +char ssinbuf[512]; +substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); +char ssoutbuf[256]; +substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); + +unsigned long bytesleft = 100; + +void getbyte(ch) +char *ch; +{ + if (!bytesleft--) _exit(100); + substdio_get(&ssin,ch,1); +} + +unsigned long getlen() +{ + unsigned long len = 0; + char ch; + + for (;;) { + getbyte(&ch); + if (ch == ':') return len; + if (len > 200000000) resources(); + len = 10 * len + (ch - '0'); + } +} + +void getcomma() +{ + char ch; + getbyte(&ch); + if (ch != ',') _exit(100); +} + +struct qmail qq; + +void identify() +{ + char *remotehost; + char *remoteinfo; + char *remoteip; + char *local; + + remotehost = env_get("TCPREMOTEHOST"); + if (!remotehost) remotehost = "unknown"; + remoteinfo = env_get("TCPREMOTEINFO"); + remoteip = env_get("TCPREMOTEIP"); + if (!remoteip) remoteip = "unknown"; + local = env_get("TCPLOCALHOST"); + if (!local) local = env_get("TCPLOCALIP"); + if (!local) local = "unknown"; + + received(&qq,"QMQP",local,remoteip,remotehost,remoteinfo,(char *) 0); +} + +char buf[1000]; +char strnum[FMT_ULONG]; + +int getbuf() +{ + unsigned long len; + int i; + + len = getlen(); + if (len >= 1000) { + for (i = 0;i < len;++i) getbyte(buf); + getcomma(); + buf[0] = 0; + return 0; + } + + for (i = 0;i < len;++i) getbyte(buf + i); + getcomma(); + buf[len] = 0; + return byte_chr(buf,len,'\0') == len; +} + +int flagok = 1; + +main() +{ + char *result; + unsigned long qp; + unsigned long len; + char ch; + + sig_pipeignore(); + sig_alarmcatch(resources); + alarm(3600); + + bytesleft = getlen(); + + len = getlen(); + + if (chdir(auto_qmail) == -1) resources(); + if (qmail_open(&qq) == -1) resources(); + qp = qmail_qp(&qq); + identify(); + + while (len > 0) { /* XXX: could speed this up */ + getbyte(&ch); + --len; + qmail_put(&qq,&ch,1); + } + getcomma(); + + if (getbuf()) + qmail_from(&qq,buf); + else { + qmail_from(&qq,""); + qmail_fail(&qq); + flagok = 0; + } + + while (bytesleft) + if (getbuf()) + qmail_to(&qq,buf); + else { + qmail_fail(&qq); + flagok = 0; + } + + bytesleft = 1; + getcomma(); + + result = qmail_close(&qq); + + if (!*result) { + len = fmt_str(buf,"Kok "); + len += fmt_ulong(buf + len,(unsigned long) now()); + len += fmt_str(buf + len," qp "); + len += fmt_ulong(buf + len,qp); + buf[len] = 0; + result = buf; + } + + if (!flagok) + result = "Dsorry, I can't accept addresses like that (#5.1.3)"; + + substdio_put(&ssout,strnum,fmt_ulong(strnum,(unsigned long) str_len(result))); + substdio_puts(&ssout,":"); + substdio_puts(&ssout,result); + substdio_puts(&ssout,","); + substdio_flush(&ssout); + _exit(0); +} diff -u -N qmail-1.03-orig/qmail-qmtpd.c test/qmail-qmtpd.c --- qmail-1.03-orig/qmail-qmtpd.c Mon Jun 15 12:53:16 1998 +++ test/qmail-qmtpd.c Thu Mar 1 23:58:54 2001 @@ -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 -u -N qmail-1.03-orig/qmail-qmtpd.c.orig test/qmail-qmtpd.c.orig --- qmail-1.03-orig/qmail-qmtpd.c.orig Thu Jan 1 01:00:00 1970 +++ test/qmail-qmtpd.c.orig Thu Mar 1 23:58:54 2001 @@ -0,0 +1,268 @@ +#include "stralloc.h" +#include "substdio.h" +#include "qmail.h" +#include "now.h" +#include "str.h" +#include "fmt.h" +#include "env.h" +#include "sig.h" +#include "rcpthosts.h" +#include "auto_qmail.h" +#include "readwrite.h" +#include "control.h" +#include "received.h" + +void badproto() { _exit(100); } +void resources() { _exit(111); } + +int safewrite(fd,buf,len) int fd; char *buf; int len; +{ + int r; + r = write(fd,buf,len); + if (r <= 0) _exit(0); + return r; +} + +char ssoutbuf[256]; +substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); + +int saferead(fd,buf,len) int fd; char *buf; int len; +{ + int r; + substdio_flush(&ssout); + r = read(fd,buf,len); + if (r <= 0) _exit(0); + return r; +} + +char ssinbuf[512]; +substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); + +unsigned long getlen() +{ + unsigned long len = 0; + char ch; + for (;;) { + substdio_get(&ssin,&ch,1); + if (ch == ':') return len; + if (len > 200000000) resources(); + len = 10 * len + (ch - '0'); + } +} + +void getcomma() +{ + char ch; + substdio_get(&ssin,&ch,1); + if (ch != ',') badproto(); +} + +unsigned int databytes = 0; +unsigned int bytestooverflow = 0; +struct qmail qq; + +char buf[1000]; +char buf2[100]; + +char *remotehost; +char *remoteinfo; +char *remoteip; +char *local; + +stralloc failure = {0}; + +char *relayclient; +int relayclientlen; + +main() +{ + char ch; + int i; + unsigned long biglen; + unsigned long len; + int flagdos; + int flagsenderok; + int flagbother; + unsigned long qp; + char *result; + char *x; + unsigned long u; + + sig_pipeignore(); + sig_alarmcatch(resources); + alarm(3600); + + if (chdir(auto_qmail) == -1) resources(); + + if (control_init() == -1) resources(); + if (rcpthosts_init() == -1) resources(); + relayclient = env_get("RELAYCLIENT"); + relayclientlen = relayclient ? str_len(relayclient) : 0; + + if (control_readint(&databytes,"control/databytes") == -1) resources(); + x = env_get("DATABYTES"); + if (x) { scan_ulong(x,&u); databytes = u; } + if (!(databytes + 1)) --databytes; + + remotehost = env_get("TCPREMOTEHOST"); + if (!remotehost) remotehost = "unknown"; + remoteinfo = env_get("TCPREMOTEINFO"); + remoteip = env_get("TCPREMOTEIP"); + if (!remoteip) remoteip = "unknown"; + local = env_get("TCPLOCALHOST"); + if (!local) local = env_get("TCPLOCALIP"); + if (!local) local = "unknown"; + + for (;;) { + if (!stralloc_copys(&failure,"")) resources(); + flagsenderok = 1; + + len = getlen(); + if (len == 0) badproto(); + + if (databytes) bytestooverflow = databytes + 1; + if (qmail_open(&qq) == -1) resources(); + qp = qmail_qp(&qq); + + substdio_get(&ssin,&ch,1); + --len; + if (ch == 10) flagdos = 0; + else if (ch == 13) flagdos = 1; + else badproto(); + + received(&qq,"QMTP",local,remoteip,remotehost,remoteinfo,(char *) 0); + + /* XXX: check for loops? only if len is big? */ + + if (flagdos) + while (len > 0) { + substdio_get(&ssin,&ch,1); + --len; + while ((ch == 13) && len) { + substdio_get(&ssin,&ch,1); + --len; + if (ch == 10) break; + if (bytestooverflow) if (!--bytestooverflow) qmail_fail(&qq); + qmail_put(&qq,"\015",1); + } + if (bytestooverflow) if (!--bytestooverflow) qmail_fail(&qq); + qmail_put(&qq,&ch,1); + } + else { + if (databytes) + if (len > databytes) { + bytestooverflow = 0; + qmail_fail(&qq); + } + while (len > 0) { /* XXX: could speed this up, obviously */ + substdio_get(&ssin,&ch,1); + --len; + qmail_put(&qq,&ch,1); + } + } + getcomma(); + + len = getlen(); + + if (len >= 1000) { + buf[0] = 0; + flagsenderok = 0; + for (i = 0;i < len;++i) + substdio_get(&ssin,&ch,1); + } + else { + for (i = 0;i < len;++i) { + substdio_get(&ssin,buf + i,1); + if (!buf[i]) flagsenderok = 0; + } + buf[len] = 0; + } + getcomma(); + + flagbother = 0; + qmail_from(&qq,buf); + if (!flagsenderok) qmail_fail(&qq); + + biglen = getlen(); + while (biglen > 0) { + if (!stralloc_append(&failure,"")) resources(); + + len = 0; + for (;;) { + if (!biglen) badproto(); + substdio_get(&ssin,&ch,1); + --biglen; + if (ch == ':') break; + if (len > 200000000) resources(); + len = 10 * len + (ch - '0'); + } + if (len >= biglen) badproto(); + if (len + relayclientlen >= 1000) { + failure.s[failure.len - 1] = 'L'; + for (i = 0;i < len;++i) + substdio_get(&ssin,&ch,1); + } + else { + for (i = 0;i < len;++i) { + substdio_get(&ssin,buf + i,1); + if (!buf[i]) failure.s[failure.len - 1] = 'N'; + } + buf[len] = 0; + + if (relayclient) + str_copy(buf + len,relayclient); + else + switch(rcpthosts(buf,len)) { + case -1: resources(); + case 0: failure.s[failure.len - 1] = 'D'; + } + + if (!failure.s[failure.len - 1]) { + qmail_to(&qq,buf); + flagbother = 1; + } + } + getcomma(); + biglen -= (len + 1); + } + getcomma(); + + if (!flagbother) qmail_fail(&qq); + result = qmail_close(&qq); + if (!flagsenderok) result = "Dunacceptable sender (#5.1.7)"; + if (databytes) if (!bytestooverflow) result = "Dsorry, that message size exceeds my databytes limit (#5.3.4)"; + + if (*result) + len = str_len(result); + else { + /* success! */ + len = 0; + len += fmt_str(buf2 + len,"Kok "); + len += fmt_ulong(buf2 + len,(unsigned long) now()); + len += fmt_str(buf2 + len," qp "); + len += fmt_ulong(buf2 + len,qp); + buf2[len] = 0; + result = buf2; + } + + len = fmt_ulong(buf,len); + buf[len++] = ':'; + len += fmt_str(buf + len,result); + buf[len++] = ','; + + for (i = 0;i < failure.len;++i) + switch(failure.s[i]) { + case 0: + substdio_put(&ssout,buf,len); + break; + case 'D': + substdio_puts(&ssout,"66:Dsorry, that domain isn't in my list of allowed rcpthosts (#5.7.1),"); + break; + default: + substdio_puts(&ssout,"46:Dsorry, I can't handle that recipient (#5.1.3),"); + break; + } + + /* ssout will be flushed when we read from the network again */ + } +} diff -u -N qmail-1.03-orig/qmail-quotawarn.c test/qmail-quotawarn.c --- qmail-1.03-orig/qmail-quotawarn.c Thu Jan 1 01:00:00 1970 +++ test/qmail-quotawarn.c Thu Mar 1 23:58:54 2001 @@ -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 -u -N qmail-1.03-orig/qmail-remote.c test/qmail-remote.c --- qmail-1.03-orig/qmail-remote.c Mon Jun 15 12:53:16 1998 +++ test/qmail-remote.c Thu Mar 1 23:59:20 2001 @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "sig.h" #include "stralloc.h" @@ -26,13 +27,32 @@ #include "tcpto.h" #include "readwrite.h" #include "timeoutconn.h" +#ifndef TLS #include "timeoutread.h" #include "timeoutwrite.h" +#endif + +#ifdef MXPS +#include +#include "fmt.h" +#endif + +#ifdef TLS +#ifndef MXPS +#include +#endif +#include + +SSL *ssl = 0; +char *fqdn = 0; +#endif #define HUGESMTPTEXT 5000 -#define PORT_SMTP 25 /* silly rabbit, /etc/services is for users */ -unsigned long port = PORT_SMTP; +unsigned long smtp_port = 25; /* silly rabbit, /etc/services is for users */ +#ifdef MXPS +unsigned long qmtp_port = 209; +#endif GEN_ALLOC_typedef(saa,stralloc,sa,len,a) GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus) @@ -70,6 +90,10 @@ Unable to switch to home directory. (#4.3.0)\n"); zerodie(); } void temp_control() { out("Z\ Unable to read control files. (#4.3.0)\n"); zerodie(); } +#ifdef MXPS +void temp_proto() { out("Z\ +recipient did not talk proper QMTP (#4.3.0)\n"); zerodie(); } +#endif void perm_partialline() { out("D\ SMTP cannot transfer messages with partial final lines. (#5.6.2)\n"); zerodie(); } void perm_usage() { out("D\ @@ -107,24 +131,68 @@ 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; } - +#ifdef MXPS +char inbuf[1500]; +char smtptobuf[1500]; +#else char inbuf[1024]; -substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf); char smtptobuf[1024]; +#endif +substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf); substdio smtpto = SUBSTDIO_FDBUF(safewrite,-1,smtptobuf,sizeof smtptobuf); char smtpfrombuf[128]; substdio smtpfrom = SUBSTDIO_FDBUF(saferead,-1,smtpfrombuf,sizeof smtpfrombuf); @@ -179,6 +247,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 +316,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"); @@ -273,6 +500,115 @@ quit("K"," accepted message"); } +#ifdef MXPS +int qmtp_priority(int pref) +{ + if (pref < 12800) return 0; + if (pref > 13055) return 0; + if (pref % 16 == 1) return 1; + return 0; +} + +void qmtp() +{ + struct stat st; + unsigned long len; + int len2; + char *x; + int i; + int n; + unsigned char ch; + char num[FMT_ULONG]; + int flagallok; + + if (fstat(0,&st) == -1) quit("Z", " unable to fstat stdin"); + len = st.st_size; + + /* the following code was substantially taken from serialmail'ss serialqmtp.c */ + substdio_put(&smtpto,num,fmt_ulong(num,len+1)); + substdio_put(&smtpto,":\n",2); + while (len > 0) { + n = substdio_feed(&ssin); + if (n <= 0) _exit(32); /* wise guy again */ + x = substdio_PEEK(&ssin); + substdio_put(&smtpto,x,n); + substdio_SEEK(&ssin,n); + len -= n; + } + substdio_put(&smtpto,",",1); + + len = sender.len; + substdio_put(&smtpto,num,fmt_ulong(num,len)); + substdio_put(&smtpto,":",1); + substdio_put(&smtpto,sender.s,sender.len); + substdio_put(&smtpto,",",1); + + len = 0; + for (i = 0;i < reciplist.len;++i) + len += fmt_ulong(num,reciplist.sa[i].len) + 1 + reciplist.sa[i].len + 1; + substdio_put(&smtpto,num,fmt_ulong(num,len)); + substdio_put(&smtpto,":",1); + for (i = 0;i < reciplist.len;++i) { + substdio_put(&smtpto,num,fmt_ulong(num,reciplist.sa[i].len)); + substdio_put(&smtpto,":",1); + substdio_put(&smtpto,reciplist.sa[i].s,reciplist.sa[i].len); + substdio_put(&smtpto,",",1); + } + substdio_put(&smtpto,",",1); + substdio_flush(&smtpto); + + flagallok = 1; + + for (i = 0;i < reciplist.len;++i) { + len = 0; + for (;;) { + get(&ch); + if (ch == ':') break; + if (len > 200000000) temp_proto(); + if (ch - '0' > 9) temp_proto(); + len = 10 * len + (ch - '0'); + } + if (!len) temp_proto(); + get(&ch); --len; + if ((ch != 'Z') && (ch != 'D') && (ch != 'K')) temp_proto(); + + if (!stralloc_copyb(&smtptext,&ch,1)) temp_proto(); + if (!stralloc_cats(&smtptext,"qmtp: ")) temp_nomem(); + + while (len > 0) { + get(&ch); + --len; + } + + for (len = 0;len < smtptext.len;++len) { + ch = smtptext.s[len]; + if ((ch < 32) || (ch > 126)) smtptext.s[len] = '?'; + } + get(&ch); + if (ch != ',') temp_proto(); + smtptext.s[smtptext.len-1] = '\n'; + + if (smtptext.s[0] == 'K') out("r"); + else if (smtptext.s[0] == 'D') { + out("h"); + flagallok = 0; + } + else { /* if (smtptext.s[0] == 'Z') */ + out("s"); + flagallok = 0; + } + if (substdio_put(subfdoutsmall,smtptext.s+1,smtptext.len-1) == -1) temp_noconn(); + zero(); + } + if (!flagallok) { + out("DGiving up on ");outhost();out("\n"); + } else { + out("KAll received okay by ");outhost();out("\n"); + } + zerodie(); +} +#endif + stralloc canonhost = {0}; stralloc canonbox = {0}; @@ -332,13 +668,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(); @@ -357,7 +697,7 @@ if (relayhost) { i = str_chr(relayhost,':'); if (relayhost[i]) { - scan_ulong(relayhost + i + 1,&port); + scan_ulong(relayhost + i + 1,&smtp_port); relayhost[i] = 0; } if (!stralloc_copys(&host,relayhost)) temp_nomem(); @@ -413,10 +753,29 @@ smtpfd = socket(AF_INET,SOCK_STREAM,0); if (smtpfd == -1) temp_oserr(); - - if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) { + + /* performace hack to send TCP ACK's without delay */ + setsockopt(smtpfd, IPPROTO_TCP, TCP_NODELAY, &tcpnodelay, sizeof(tcpnodelay)); + +#ifdef MXPS + if (qmtp_priority(ip.ix[i].pref)) { + if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) qmtp_port,timeoutconnect) == 0) { + tcpto_err(&ip.ix[i].ip,0); + partner = ip.ix[i].ip; + qmtp(); /* does not return */ + } + close(smtpfd); /* in case of failure: it is not allowed to call connect twice on the same socket */ + smtpfd = socket(AF_INET,SOCK_STREAM,0); + if (smtpfd == -1) temp_oserr(); + } +#endif + + if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) smtp_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 -u -N qmail-1.03-orig/qmail-remote.c.orig test/qmail-remote.c.orig --- qmail-1.03-orig/qmail-remote.c.orig Thu Jan 1 01:00:00 1970 +++ test/qmail-remote.c.orig Thu Mar 1 23:58:54 2001 @@ -0,0 +1,650 @@ +#include +#include +#include +#include +#include +#include "sig.h" +#include "stralloc.h" +#include "substdio.h" +#include "subfd.h" +#include "scan.h" +#include "case.h" +#include "error.h" +#include "auto_qmail.h" +#include "control.h" +#include "dns.h" +#include "alloc.h" +#include "quote.h" +#include "ip.h" +#include "ipalloc.h" +#include "ipme.h" +#include "gen_alloc.h" +#include "gen_allocdefs.h" +#include "str.h" +#include "now.h" +#include "exit.h" +#include "constmap.h" +#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) +GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus) +static stralloc sauninit = {0}; + +stralloc helohost = {0}; +stralloc routes = {0}; +struct constmap maproutes; +stralloc host = {0}; +stralloc sender = {0}; + +saa reciplist = {0}; + +struct ip_address partner; + +void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); } +void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); } +void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); } +void outsafe(sa) stralloc *sa; { int i; char ch; +for (i = 0;i < sa->len;++i) { +ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126) ch = '?'; +if (substdio_put(subfdoutsmall,&ch,1) == -1) _exit(0); } } + +void temp_nomem() { out("ZOut of memory. (#4.3.0)\n"); zerodie(); } +void temp_oserr() { out("Z\ +System resources temporarily unavailable. (#4.3.0)\n"); zerodie(); } +void temp_noconn() { out("Z\ +Sorry, I wasn't able to establish an SMTP connection. (#4.4.1)\n"); zerodie(); } +void temp_read() { out("ZUnable to read message. (#4.3.0)\n"); zerodie(); } +void temp_dnscanon() { out("Z\ +CNAME lookup failed temporarily. (#4.4.3)\n"); zerodie(); } +void temp_dns() { out("Z\ +Sorry, I couldn't find any host by that name. (#4.1.2)\n"); zerodie(); } +void temp_chdir() { out("Z\ +Unable to switch to home directory. (#4.3.0)\n"); zerodie(); } +void temp_control() { out("Z\ +Unable to read control files. (#4.3.0)\n"); zerodie(); } +void perm_partialline() { out("D\ +SMTP cannot transfer messages with partial final lines. (#5.6.2)\n"); zerodie(); } +void perm_usage() { out("D\ +I (qmail-remote) was invoked improperly. (#5.3.5)\n"); zerodie(); } +void perm_dns() { out("D\ +Sorry, I couldn't find any host named "); +outsafe(&host); +out(". (#5.1.2)\n"); zerodie(); } +void perm_nomx() { out("D\ +Sorry, I couldn't find a mail exchanger or IP address. (#5.4.4)\n"); +zerodie(); } +void perm_ambigmx() { out("D\ +Sorry. Although I'm listed as a best-preference MX or A for that host,\n\ +it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n"); +zerodie(); } + +void outhost() +{ + char x[IPFMT]; + if (substdio_put(subfdoutsmall,x,ip_fmt(x,&partner)) == -1) _exit(0); +} + +int flagcritical = 0; + +void dropped() { + out("ZConnected to "); + outhost(); + out(" but connection died. "); + if (flagcritical) out("Possible duplicate! "); + out("(#4.4.2)\n"); + zerodie(); +} + +int timeoutconnect = 60; +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; +} + +char inbuf[1024]; +substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf); +char smtptobuf[1024]; +substdio smtpto = SUBSTDIO_FDBUF(safewrite,-1,smtptobuf,sizeof smtptobuf); +char smtpfrombuf[128]; +substdio smtpfrom = SUBSTDIO_FDBUF(saferead,-1,smtpfrombuf,sizeof smtpfrombuf); + +stralloc smtptext = {0}; + +void get(ch) +char *ch; +{ + substdio_get(&smtpfrom,ch,1); + if (*ch != '\r') + if (smtptext.len < HUGESMTPTEXT) + if (!stralloc_append(&smtptext,ch)) temp_nomem(); +} + +unsigned long smtpcode() +{ + unsigned char ch; + unsigned long code; + + if (!stralloc_copys(&smtptext,"")) temp_nomem(); + + get(&ch); code = ch - '0'; + get(&ch); code = code * 10 + (ch - '0'); + get(&ch); code = code * 10 + (ch - '0'); + for (;;) { + get(&ch); + if (ch != '-') break; + while (ch != '\n') get(&ch); + get(&ch); + get(&ch); + get(&ch); + } + while (ch != '\n') get(&ch); + + return code; +} + +void outsmtptext() +{ + int i; + if (smtptext.s) if (smtptext.len) { + out("Remote host said: "); + for (i = 0;i < smtptext.len;++i) + if (!smtptext.s[i]) smtptext.s[i] = '?'; + if (substdio_put(subfdoutsmall,smtptext.s,smtptext.len) == -1) _exit(0); + smtptext.len = 0; + } +} + +void quit(prepend,append) +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); + outhost(); + out(append); + out(".\n"); + outsmtptext(); + zerodie(); +} + +void blast() +{ + int r; + char ch; + + for (;;) { + r = substdio_get(&ssin,&ch,1); + if (r == 0) break; + if (r == -1) temp_read(); + if (ch == '.') + substdio_put(&smtpto,".",1); + while (ch != '\n') { + substdio_put(&smtpto,&ch,1); + r = substdio_get(&ssin,&ch,1); + if (r == 0) perm_partialline(); + if (r == -1) temp_read(); + } + substdio_put(&smtpto,"\r\n",2); + } + + flagcritical = 1; + substdio_put(&smtpto,".\r\n",3); + substdio_flush(&smtpto); +} + +stralloc recip = {0}; + +void smtp() +{ + 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"); + substdio_flush(&smtpto); + code = smtpcode(); + if (code >= 500) quit("DConnected to "," but sender was rejected"); + if (code >= 400) quit("ZConnected to "," but sender was rejected"); + + flagbother = 0; + for (i = 0;i < reciplist.len;++i) { + substdio_puts(&smtpto,"RCPT TO:<"); + substdio_put(&smtpto,reciplist.sa[i].s,reciplist.sa[i].len); + substdio_puts(&smtpto,">\r\n"); + substdio_flush(&smtpto); + code = smtpcode(); + if (code >= 500) { + out("h"); outhost(); out(" does not like recipient.\n"); + outsmtptext(); zero(); + } + else if (code >= 400) { + out("s"); outhost(); out(" does not like recipient.\n"); + outsmtptext(); zero(); + } + else { + out("r"); zero(); + flagbother = 1; + } + } + if (!flagbother) quit("DGiving up on ",""); + + substdio_putsflush(&smtpto,"DATA\r\n"); + code = smtpcode(); + if (code >= 500) quit("D"," failed on DATA command"); + if (code >= 400) quit("Z"," failed on DATA command"); + + blast(); + code = smtpcode(); + flagcritical = 0; + if (code >= 500) quit("D"," failed after I sent the message"); + if (code >= 400) quit("Z"," failed after I sent the message"); + quit("K"," accepted message"); +} + +stralloc canonhost = {0}; +stralloc canonbox = {0}; + +void addrmangle(saout,s,flagalias,flagcname) +stralloc *saout; /* host has to be canonical, box has to be quoted */ +char *s; +int *flagalias; +int flagcname; +{ + int j; + + *flagalias = flagcname; + + j = str_rchr(s,'@'); + if (!s[j]) { + if (!stralloc_copys(saout,s)) temp_nomem(); + return; + } + if (!stralloc_copys(&canonbox,s)) temp_nomem(); + canonbox.len = j; + if (!quote(saout,&canonbox)) temp_nomem(); + if (!stralloc_cats(saout,"@")) temp_nomem(); + + if (!stralloc_copys(&canonhost,s + j + 1)) temp_nomem(); + if (flagcname) + switch(dns_cname(&canonhost)) { + case 0: *flagalias = 0; break; + case DNS_MEM: temp_nomem(); + case DNS_SOFT: temp_dnscanon(); + case DNS_HARD: ; /* alias loop, not our problem */ + } + + if (!stralloc_cat(saout,&canonhost)) temp_nomem(); +} + +void getcontrols() +{ + if (control_init() == -1) temp_control(); + if (control_readint(&timeout,"control/timeoutremote") == -1) temp_control(); + if (control_readint(&timeoutconnect,"control/timeoutconnect") == -1) + temp_control(); + if (control_rldef(&helohost,"control/helohost",1,(char *) 0) != 1) + temp_control(); + switch(control_readfile(&routes,"control/smtproutes",0)) { + case -1: + temp_control(); + case 0: + if (!constmap_init(&maproutes,"",0,1)) temp_nomem(); break; + case 1: + if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break; + } +} + +void main(argc,argv) +int argc; +char **argv; +{ + 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(); + getcontrols(); + + + if (!stralloc_copys(&host,argv[1])) temp_nomem(); + + relayhost = 0; + for (i = 0;i <= host.len;++i) + if ((i == 0) || (i == host.len) || (host.s[i] == '.')) + if (relayhost = constmap(&maproutes,host.s + i,host.len - i)) + break; + if (relayhost && !*relayhost) relayhost = 0; + + if (relayhost) { + i = str_chr(relayhost,':'); + if (relayhost[i]) { + scan_ulong(relayhost + i + 1,&port); + relayhost[i] = 0; + } + if (!stralloc_copys(&host,relayhost)) temp_nomem(); + } + + + addrmangle(&sender,argv[2],&flagalias,0); + + if (!saa_readyplus(&reciplist,0)) temp_nomem(); + if (ipme_init() != 1) temp_oserr(); + + flagallaliases = 1; + recips = argv + 3; + while (*recips) { + if (!saa_readyplus(&reciplist,1)) temp_nomem(); + reciplist.sa[reciplist.len] = sauninit; + addrmangle(reciplist.sa + reciplist.len,*recips,&flagalias,!relayhost); + if (!flagalias) flagallaliases = 0; + ++reciplist.len; + ++recips; + } + + + random = now() + (getpid() << 16); + switch (relayhost ? dns_ip(&ip,&host) : dns_mxip(&ip,&host,random)) { + case DNS_MEM: temp_nomem(); + case DNS_SOFT: temp_dns(); + case DNS_HARD: perm_dns(); + case 1: + if (ip.len <= 0) temp_dns(); + } + + if (ip.len <= 0) perm_nomx(); + + prefme = 100000; + for (i = 0;i < ip.len;++i) + if (ipme_is(&ip.ix[i].ip)) + if (ip.ix[i].pref < prefme) + prefme = ip.ix[i].pref; + + if (relayhost) prefme = 300000; + if (flagallaliases) prefme = 500000; + + for (i = 0;i < ip.len;++i) + if (ip.ix[i].pref < prefme) + break; + + if (i >= ip.len) + perm_ambigmx(); + + for (i = 0;i < ip.len;++i) if (ip.ix[i].pref < prefme) { + if (tcpto(&ip.ix[i].ip)) continue; + + 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); + close(smtpfd); + } + + temp_noconn(); +} diff -u -N qmail-1.03-orig/qmail-reply.c test/qmail-reply.c --- qmail-1.03-orig/qmail-reply.c Thu Jan 1 01:00:00 1970 +++ test/qmail-reply.c Thu Mar 1 23:58:54 2001 @@ -0,0 +1,224 @@ +#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 get_env(stralloc *dtl, stralloc *to, stralloc *from, stralloc *replytext); +void check_header_and_get_subject(stralloc *subject); +void send_reply(stralloc *dtl, stralloc *to, stralloc *from, stralloc *subject, stralloc *replytext); + +/* global vars */ +char buf[1024]; +char *(ignore[7]); + +stralloc subj={0}; +stralloc replytext={0}; +stralloc to={0}; +stralloc from={0}; +stralloc dtline={0}; +stralloc prog={0}; +stralloc line = {0}; + +int main() +{ + + ignore[0] = "root"; + ignore[1] = "-request@"; + ignore[2] = "daemon"; + ignore[3] = "postmaster"; + ignore[4] = "mailer-daemon"; + ignore[5] = "mailer"; + ignore[6] = 0; + + if (!env_init()) temp_nomem(); + + get_env(&dtline, &to, &from, &replytext); + + check_header_and_get_subject(&subj); + + send_reply(&dtline, &to, &from, &subj, &replytext); + + return 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; + + t = len-pat_len+1; + for(i=0; i < t; i++) { + if (!str_diffn( pattern, string+i, pat_len) ) + return 0; + } + return 1; +} + +/* check and get the environment */ +void get_env(stralloc *dtl, stralloc *to, stralloc *from, stralloc *replytext) +{ + char *s; + unsigned int i; + + if ( s = env_get("DTLINE") ) { + if (!stralloc_copys(dtl,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 { /* paranoia */ + 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); + i=0; + while ( ignore[i] ) { + if (!wild_matchb(ignore[i], str_len( ignore[i] ), s, str_len(s) ) ) { + exit(0); + } + i++; + } + } else { /* paranoia */ + strerr_die1x(111,"SENDER not present (LDAP-ERR #4.1.3)"); + } + if ( s = env_get("RECIPIENT") ) { + if (!stralloc_copys(from,s)) temp_nomem(); + } else { /* paranoia */ + strerr_die1x(111,"RECIPIENT not present (LDAP-ERR #4.1.4)"); + } + + +} + + +/* get the subject, for replymode */ +void check_header_and_get_subject(stralloc *subject) +{ + 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 */ + + 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(stralloc *dtl, stralloc *to, stralloc *from, stralloc *subject, stralloc *replytext) +{ + 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],dtl->s,dtl->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 -u -N qmail-1.03-orig/qmail-send.c test/qmail-send.c --- qmail-1.03-orig/qmail-send.c Mon Jun 15 12:53:16 1998 +++ test/qmail-send.c Thu Mar 1 23:58:54 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,41 +931,42 @@ 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; @@ -1453,6 +1479,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 +1573,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 -u -N qmail-1.03-orig/qmail-send.c.orig test/qmail-send.c.orig --- qmail-1.03-orig/qmail-send.c.orig Thu Jan 1 01:00:00 1970 +++ test/qmail-send.c.orig Thu Mar 1 23:58:54 2001 @@ -0,0 +1,1612 @@ +#include +#include +#include "readwrite.h" +#include "sig.h" +#include "direntry.h" +#include "control.h" +#include "select.h" +#include "open.h" +#include "seek.h" +#include "exit.h" +#include "lock.h" +#include "ndelay.h" +#include "now.h" +#include "getln.h" +#include "substdio.h" +#include "alloc.h" +#include "error.h" +#include "stralloc.h" +#include "str.h" +#include "byte.h" +#include "fmt.h" +#include "scan.h" +#include "case.h" +#include "auto_qmail.h" +#include "trigger.h" +#include "newfield.h" +#include "quote.h" +#include "qmail.h" +#include "qsutil.h" +#include "prioq.h" +#include "constmap.h" +#include "fmtqfn.h" +#include "readsubdir.h" + +/* critical timing feature #1: if not triggered, do not busy-loop */ +/* critical timing feature #2: if triggered, respond within fixed time */ +/* important timing feature: when triggered, respond instantly */ +#define SLEEP_TODO 1500 /* check todo/ every 25 minutes in any case */ +#define SLEEP_FUZZ 1 /* slop a bit on sleeps to avoid zeno effect */ +#define SLEEP_FOREVER 86400 /* absolute maximum time spent in select() */ +#define SLEEP_CLEANUP 76431 /* time between cleanups */ +#define SLEEP_SYSFAIL 123 +#define OSSIFIED 129600 /* 36 hours; _must_ exceed q-q's DEATH (24 hours) */ + +int lifetime = 604800; + +stralloc percenthack = {0}; +struct constmap mappercenthack; +stralloc locals = {0}; +struct constmap maplocals; +stralloc vdoms = {0}; +struct constmap mapvdoms; +stralloc envnoathost = {0}; +stralloc bouncefrom = {0}; +stralloc bouncehost = {0}; +stralloc doublebounceto = {0}; +stralloc doublebouncehost = {0}; + +char strnum2[FMT_ULONG]; +char strnum3[FMT_ULONG]; + +#define CHANNELS 2 +char *chanaddr[CHANNELS] = { "local/", "remote/" }; +char *chanstatusmsg[CHANNELS] = { " local ", " remote " }; +char *tochan[CHANNELS] = { " to local ", " to remote " }; +int chanfdout[CHANNELS] = { 1, 3 }; +int chanfdin[CHANNELS] = { 2, 4 }; +int chanskip[CHANNELS] = { 10, 20 }; + +int flagexitasap = 0; void sigterm() { flagexitasap = 1; } +int flagrunasap = 0; void sigalrm() { flagrunasap = 1; } +int flagreadasap = 0; void sighup() { flagreadasap = 1; } + +void cleandied() { log1("alert: oh no! lost qmail-clean connection! dying...\n"); + flagexitasap = 1; } + +int flagspawnalive[CHANNELS]; +void spawndied(c) int c; { log1("alert: oh no! lost spawn connection! dying...\n"); + flagspawnalive[c] = 0; flagexitasap = 1; } + +#define REPORTMAX 10000 + +datetime_sec recent; + + +/* this file is too long ----------------------------------------- FILENAMES */ + +stralloc fn = {0}; +stralloc fn2 = {0}; +char fnmake_strnum[FMT_ULONG]; + +void fnmake_init() +{ + while (!stralloc_ready(&fn,FMTQFN)) nomem(); + while (!stralloc_ready(&fn2,FMTQFN)) nomem(); +} + +void fnmake_info(id) unsigned long id; { fn.len = fmtqfn(fn.s,"info/",id,1); } +void fnmake_todo(id) unsigned long id; { fn.len = fmtqfn(fn.s,"todo/",id,0); } +void fnmake_mess(id) unsigned long id; { fn.len = fmtqfn(fn.s,"mess/",id,1); } +void fnmake_foop(id) unsigned long id; { fn.len = fmtqfn(fn.s,"foop/",id,0); } +void fnmake_split(id) unsigned long id; { fn.len = fmtqfn(fn.s,"",id,1); } +void fnmake2_bounce(id) unsigned long id; +{ fn2.len = fmtqfn(fn2.s,"bounce/",id,0); } +void fnmake_chanaddr(id,c) unsigned long id; int c; +{ fn.len = fmtqfn(fn.s,chanaddr[c],id,1); } + + +/* this file is too long ----------------------------------------- REWRITING */ + +stralloc rwline = {0}; + +/* 1 if by land, 2 if by sea, 0 if out of memory. not allowed to barf. */ +/* may trash recip. must set up rwline, between a T and a \0. */ +int rewrite(recip) +char *recip; +{ + int i; + int j; + char *x; + static stralloc addr = {0}; + int at; + + if (!stralloc_copys(&rwline,"T")) return 0; + if (!stralloc_copys(&addr,recip)) return 0; + + i = byte_rchr(addr.s,addr.len,'@'); + if (i == addr.len) { + if (!stralloc_cats(&addr,"@")) return 0; + if (!stralloc_cat(&addr,&envnoathost)) return 0; + } + + while (constmap(&mappercenthack,addr.s + i + 1,addr.len - i - 1)) { + j = byte_rchr(addr.s,i,'%'); + if (j == i) break; + addr.len = i; + i = j; + addr.s[i] = '@'; + } + + at = byte_rchr(addr.s,addr.len,'@'); + + if (constmap(&maplocals,addr.s + at + 1,addr.len - at - 1)) { + if (!stralloc_cat(&rwline,&addr)) return 0; + if (!stralloc_0(&rwline)) return 0; + return 1; + } + + for (i = 0;i <= addr.len;++i) + if (!i || (i == at + 1) || (i == addr.len) || ((i > at) && (addr.s[i] == '.'))) + if (x = constmap(&mapvdoms,addr.s + i,addr.len - i)) { + if (!*x) break; + if (!stralloc_cats(&rwline,x)) return 0; + if (!stralloc_cats(&rwline,"-")) return 0; + if (!stralloc_cat(&rwline,&addr)) return 0; + if (!stralloc_0(&rwline)) return 0; + return 1; + } + + if (!stralloc_cat(&rwline,&addr)) return 0; + if (!stralloc_0(&rwline)) return 0; + return 2; +} + +void senderadd(sa,sender,recip) +stralloc *sa; +char *sender; +char *recip; +{ + int i; + int j; + int k; + + i = str_len(sender); + if (i >= 4) + if (str_equal(sender + i - 4,"-@[]")) + { + j = byte_rchr(sender,i - 4,'@'); + k = str_rchr(recip,'@'); + if (recip[k] && (j + 5 <= i)) + { + /* owner-@host-@[] -> owner-recipbox=reciphost@host */ + while (!stralloc_catb(sa,sender,j)) nomem(); + while (!stralloc_catb(sa,recip,k)) nomem(); + while (!stralloc_cats(sa,"=")) nomem(); + while (!stralloc_cats(sa,recip + k + 1)) nomem(); + while (!stralloc_cats(sa,"@")) nomem(); + while (!stralloc_catb(sa,sender + j + 1,i - 5 - j)) nomem(); + return; + } + } + while (!stralloc_cats(sa,sender)) nomem(); +} + + +/* this file is too long ---------------------------------------------- INFO */ + +int getinfo(sa,dt,id) +stralloc *sa; +datetime_sec *dt; +unsigned long id; +{ + int fdinfo; + struct stat st; + static stralloc line = {0}; + int match; + substdio ss; + char buf[128]; + + fnmake_info(id); + fdinfo = open_read(fn.s); + if (fdinfo == -1) return 0; + if (fstat(fdinfo,&st) == -1) { close(fdinfo); return 0; } + substdio_fdbuf(&ss,read,fdinfo,buf,sizeof(buf)); + if (getln(&ss,&line,&match,'\0') == -1) { close(fdinfo); return 0; } + close(fdinfo); + if (!match) return 0; + if (line.s[0] != 'F') return 0; + + *dt = st.st_mtime; + while (!stralloc_copys(sa,line.s + 1)) nomem(); + while (!stralloc_0(sa)) nomem(); + return 1; +} + + +/* this file is too long ------------------------------------- COMMUNICATION */ + +substdio sstoqc; char sstoqcbuf[1024]; +substdio ssfromqc; char ssfromqcbuf[1024]; +stralloc comm_buf[CHANNELS] = { {0}, {0} }; +int comm_pos[CHANNELS]; + +void comm_init() +{ + int c; + substdio_fdbuf(&sstoqc,write,5,sstoqcbuf,sizeof(sstoqcbuf)); + substdio_fdbuf(&ssfromqc,read,6,ssfromqcbuf,sizeof(ssfromqcbuf)); + for (c = 0;c < CHANNELS;++c) + if (ndelay_on(chanfdout[c]) == -1) + /* this is so stupid: NDELAY semantics should be default on write */ + spawndied(c); /* drastic, but better than risking deadlock */ +} + +int comm_canwrite(c) +int c; +{ + /* XXX: could allow a bigger buffer; say 10 recipients */ + if (comm_buf[c].s && comm_buf[c].len) return 0; + return 1; +} + +void comm_write(c,delnum,id,sender,recip) +int c; +int delnum; +unsigned long id; +char *sender; +char *recip; +{ + char ch; + if (comm_buf[c].s && comm_buf[c].len) return; + while (!stralloc_copys(&comm_buf[c],"")) nomem(); + ch = delnum; + 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(); + senderadd(&comm_buf[c],sender,recip); + while (!stralloc_0(&comm_buf[c])) nomem(); + while (!stralloc_cats(&comm_buf[c],recip)) nomem(); + while (!stralloc_0(&comm_buf[c])) nomem(); + comm_pos[c] = 0; +} + +void comm_selprep(nfds,wfds) +int *nfds; +fd_set *wfds; +{ + int c; + for (c = 0;c < CHANNELS;++c) + if (flagspawnalive[c]) + if (comm_buf[c].s && comm_buf[c].len) + { + FD_SET(chanfdout[c],wfds); + if (*nfds <= chanfdout[c]) + *nfds = chanfdout[c] + 1; + } +} + +void comm_do(wfds) +fd_set *wfds; +{ + int c; + for (c = 0;c < CHANNELS;++c) + if (flagspawnalive[c]) + if (comm_buf[c].s && comm_buf[c].len) + if (FD_ISSET(chanfdout[c],wfds)) + { + int w; + int len; + len = comm_buf[c].len; + w = write(chanfdout[c],comm_buf[c].s + comm_pos[c],len - comm_pos[c]); + if (w <= 0) + { + if ((w == -1) && (errno == error_pipe)) + spawndied(c); + else + continue; /* kernel select() bug; can't avoid busy-looping */ + } + else + { + comm_pos[c] += w; + if (comm_pos[c] == len) + comm_buf[c].len = 0; + } + } +} + + +/* this file is too long ------------------------------------------ CLEANUPS */ + +int flagcleanup; /* if 1, cleanupdir is initialized and ready */ +readsubdir cleanupdir; +datetime_sec cleanuptime; + +void cleanup_init() +{ + flagcleanup = 0; + cleanuptime = now(); +} + +void cleanup_selprep(wakeup) +datetime_sec *wakeup; +{ + if (flagcleanup) *wakeup = 0; + if (*wakeup > cleanuptime) *wakeup = cleanuptime; +} + +void cleanup_do() +{ + char ch; + struct stat st; + unsigned long id; + + if (!flagcleanup) + { + if (recent < cleanuptime) return; + readsubdir_init(&cleanupdir,"mess",pausedir); + flagcleanup = 1; + } + + switch(readsubdir_next(&cleanupdir,&id)) + { + case 1: + break; + case 0: + flagcleanup = 0; + cleanuptime = recent + SLEEP_CLEANUP; + default: + return; + } + + fnmake_mess(id); + if (stat(fn.s,&st) == -1) return; /* probably qmail-queue deleted it */ + if (recent <= st.st_atime + OSSIFIED) return; + + fnmake_info(id); + if (stat(fn.s,&st) == 0) return; + if (errno != error_noent) return; + fnmake_todo(id); + if (stat(fn.s,&st) == 0) return; + if (errno != error_noent) return; + + fnmake_foop(id); + if (substdio_putflush(&sstoqc,fn.s,fn.len) == -1) { cleandied(); return; } + if (substdio_get(&ssfromqc,&ch,1) != 1) { cleandied(); return; } + if (ch != '+') + log3("warning: qmail-clean unable to clean up ",fn.s,"\n"); +} + + +/* this file is too long ----------------------------------- PRIORITY QUEUES */ + +prioq pqdone = {0}; /* -todo +info; HOPEFULLY -local -remote */ +prioq pqchan[CHANNELS] = { {0}, {0} }; +/* pqchan 0: -todo +info +local ?remote */ +/* pqchan 1: -todo +info ?local +remote */ +prioq pqfail = {0}; /* stat() failure; has to be pqadded again */ + +void pqadd(id) +unsigned long id; +{ + struct prioq_elt pe; + struct prioq_elt pechan[CHANNELS]; + int flagchan[CHANNELS]; + struct stat st; + int c; + +#define CHECKSTAT if (errno != error_noent) goto fail; + + fnmake_info(id); + if (stat(fn.s,&st) == -1) + { + CHECKSTAT + return; /* someone yanking our chain */ + } + + fnmake_todo(id); + if (stat(fn.s,&st) != -1) return; /* look, ma, dad crashed writing info! */ + CHECKSTAT + + for (c = 0;c < CHANNELS;++c) + { + fnmake_chanaddr(id,c); + if (stat(fn.s,&st) == -1) { flagchan[c] = 0; CHECKSTAT } + else { flagchan[c] = 1; pechan[c].id = id; pechan[c].dt = st.st_mtime; } + } + + for (c = 0;c < CHANNELS;++c) + if (flagchan[c]) + while (!prioq_insert(&pqchan[c],&pechan[c])) nomem(); + + for (c = 0;c < CHANNELS;++c) if (flagchan[c]) break; + if (c == CHANNELS) + { + pe.id = id; pe.dt = now(); + while (!prioq_insert(&pqdone,&pe)) nomem(); + } + + return; + + fail: + log3("warning: unable to stat ",fn.s,"; will try again later\n"); + pe.id = id; pe.dt = now() + SLEEP_SYSFAIL; + while (!prioq_insert(&pqfail,&pe)) nomem(); +} + +void pqstart() +{ + readsubdir rs; + int x; + unsigned long id; + + readsubdir_init(&rs,"info",pausedir); + + while (x = readsubdir_next(&rs,&id)) + if (x > 0) + pqadd(id); +} + +void pqfinish() +{ + int c; + struct prioq_elt pe; + time_t ut[2]; /* XXX: more portable than utimbuf, but still worrisome */ + + for (c = 0;c < CHANNELS;++c) + while (prioq_min(&pqchan[c],&pe)) + { + prioq_delmin(&pqchan[c]); + fnmake_chanaddr(pe.id,c); + ut[0] = ut[1] = pe.dt; + if (utime(fn.s,ut) == -1) + log3("warning: unable to utime ",fn.s,"; message will be retried too soon\n"); + } +} + +void pqrun() +{ + int c; + int i; + for (c = 0;c < CHANNELS;++c) + if (pqchan[c].p) + if (pqchan[c].len) + for (i = 0;i < pqchan[c].len;++i) + pqchan[c].p[i].dt = recent; +} + + +/* this file is too long ---------------------------------------------- JOBS */ + +struct job + { + int refs; /* if 0, this struct is unused */ + unsigned long id; + int channel; + datetime_sec retry; + stralloc sender; + int numtodo; + int flaghiteof; + int flagdying; + } +; + +int numjobs; +struct job *jo; + +void job_init() +{ + int j; + while (!(jo = (struct job *) alloc(numjobs * sizeof(struct job)))) nomem(); + for (j = 0;j < numjobs;++j) + { + jo[j].refs = 0; + jo[j].sender.s = 0; + } +} + +int job_avail() +{ + int j; + for (j = 0;j < numjobs;++j) if (!jo[j].refs) return 1; + return 0; +} + +int job_open(id,channel) +unsigned long id; +int channel; +{ + int j; + for (j = 0;j < numjobs;++j) if (!jo[j].refs) break; + if (j == numjobs) return -1; + jo[j].refs = 1; + jo[j].id = id; + jo[j].channel = channel; + jo[j].numtodo = 0; + jo[j].flaghiteof = 0; + return j; +} + +void job_close(j) +int j; +{ + struct prioq_elt pe; + struct stat st; + + if (0 < --jo[j].refs) return; + + pe.id = jo[j].id; + pe.dt = jo[j].retry; + if (jo[j].flaghiteof && !jo[j].numtodo) + { + fnmake_chanaddr(jo[j].id,jo[j].channel); + if (unlink(fn.s) == -1) + { + log3("warning: unable to unlink ",fn.s,"; will try again later\n"); + pe.dt = now() + SLEEP_SYSFAIL; + } + else + { + int c; + for (c = 0;c < CHANNELS;++c) if (c != jo[j].channel) + { + fnmake_chanaddr(jo[j].id,c); + if (stat(fn.s,&st) == 0) return; /* more channels going */ + if (errno != error_noent) + { + log3("warning: unable to stat ",fn.s,"\n"); + break; /* this is the only reason for HOPEFULLY */ + } + } + pe.dt = now(); + while (!prioq_insert(&pqdone,&pe)) nomem(); + return; + } + } + + while (!prioq_insert(&pqchan[jo[j].channel],&pe)) nomem(); +} + + +/* this file is too long ------------------------------------------- BOUNCES */ + +char *stripvdomprepend(recip) +char *recip; +{ + int i; + char *domain; + int domainlen; + char *prepend; + + i = str_rchr(recip,'@'); + if (!recip[i]) return recip; + domain = recip + i + 1; + domainlen = str_len(domain); + + for (i = 0;i <= domainlen;++i) + if ((i == 0) || (i == domainlen) || (domain[i] == '.')) + if (prepend = constmap(&mapvdoms,domain + i,domainlen - i)) + { + if (!*prepend) break; + i = str_len(prepend); + if (str_diffn(recip,prepend,i)) break; + if (recip[i] != '-') break; + return recip + i + 1; + } + return recip; +} + +stralloc bouncetext = {0}; + +void addbounce(id,recip,report) +unsigned long id; +char *recip; +char *report; +{ + int fd; + int pos; + int w; + while (!stralloc_copys(&bouncetext,"<")) nomem(); + while (!stralloc_cats(&bouncetext,stripvdomprepend(recip))) nomem(); + for (pos = 0;pos < bouncetext.len;++pos) + if (bouncetext.s[pos] == '\n') + bouncetext.s[pos] = '_'; + while (!stralloc_cats(&bouncetext,">:\n")) nomem(); + while (!stralloc_cats(&bouncetext,report)) nomem(); + if (report[0]) + if (report[str_len(report) - 1] != '\n') + while (!stralloc_cats(&bouncetext,"\n")) nomem(); + for (pos = bouncetext.len - 2;pos > 0;--pos) + if (bouncetext.s[pos] == '\n') + if (bouncetext.s[pos - 1] == '\n') + bouncetext.s[pos] = '/'; + while (!stralloc_cats(&bouncetext,"\n")) nomem(); + fnmake2_bounce(id); + for (;;) + { + fd = open_append(fn2.s); + if (fd != -1) break; + log1("alert: unable to append to bounce message; HELP! sleeping...\n"); + sleep(10); + } + pos = 0; + while (pos < bouncetext.len) + { + w = write(fd,bouncetext.s + pos,bouncetext.len - pos); + if (w <= 0) + { + log1("alert: unable to append to bounce message; HELP! sleeping...\n"); + sleep(10); + } + else + pos += w; + } + close(fd); +} + +int injectbounce(id) +unsigned long id; +{ + struct qmail qqt; + struct stat st; + char *bouncesender; + char *bouncerecip; + int r; + int fd; + substdio ssread; + char buf[128]; + char inbuf[128]; + static stralloc sender = {0}; + static stralloc quoted = {0}; + datetime_sec birth; + unsigned long qp; + + if (!getinfo(&sender,&birth,id)) return 0; /* XXX: print warning */ + + /* owner-@host-@[] -> owner-@host */ + if (sender.len >= 5) + if (str_equal(sender.s + sender.len - 5,"-@[]")) + { + sender.len -= 4; + sender.s[sender.len - 1] = 0; + } + + fnmake2_bounce(id); + fnmake_mess(id); + if (stat(fn2.s,&st) == -1) + { + if (errno == error_noent) + return 1; + log3("warning: unable to stat ",fn2.s,"\n"); + return 0; + } + if (str_equal(sender.s,"#@[]")) + log3("triple bounce: discarding ",fn2.s,"\n"); + else + { + if (qmail_open(&qqt) == -1) + { log1("warning: unable to start qmail-queue, will try later\n"); return 0; } + qp = qmail_qp(&qqt); + + if (*sender.s) { bouncesender = ""; bouncerecip = sender.s; } + else { bouncesender = "#@[]"; bouncerecip = doublebounceto.s; } + + while (!newfield_datemake(now())) nomem(); + qmail_put(&qqt,newfield_date.s,newfield_date.len); + qmail_puts(&qqt,"From: "); + while (!quote("ed,&bouncefrom)) nomem(); + qmail_put(&qqt,quoted.s,quoted.len); + qmail_puts(&qqt,"@"); + qmail_put(&qqt,bouncehost.s,bouncehost.len); + qmail_puts(&qqt,"\nTo: "); + while (!quote2("ed,bouncerecip)) nomem(); + qmail_put(&qqt,quoted.s,quoted.len); + qmail_puts(&qqt,"\n\ +Subject: failure notice\n\ +\n\ +Hi. This is the qmail-send program at "); + qmail_put(&qqt,bouncehost.s,bouncehost.len); + qmail_puts(&qqt,*sender.s ? ".\n\ +I'm afraid I wasn't able to deliver your message to the following addresses.\n\ +This is a permanent error; I've given up. Sorry it didn't work out.\n\ +\n\ +" : ".\n\ +I tried to deliver a bounce message to this address, but the bounce bounced!\n\ +\n\ +"); + + fd = open_read(fn2.s); + if (fd == -1) + qmail_fail(&qqt); + else + { + substdio_fdbuf(&ssread,read,fd,inbuf,sizeof(inbuf)); + while ((r = substdio_get(&ssread,buf,sizeof(buf))) > 0) + qmail_put(&qqt,buf,r); + close(fd); + if (r == -1) + qmail_fail(&qqt); + } + + qmail_puts(&qqt,*sender.s ? "--- Below this line is a copy of the message.\n\n" : "--- Below this line is the original bounce.\n\n"); + qmail_puts(&qqt,"Return-Path: <"); + while (!quote2("ed,sender.s)) nomem(); + qmail_put(&qqt,quoted.s,quoted.len); + qmail_puts(&qqt,">\n"); + + fd = open_read(fn.s); + if (fd == -1) + qmail_fail(&qqt); + else + { + substdio_fdbuf(&ssread,read,fd,inbuf,sizeof(inbuf)); + while ((r = substdio_get(&ssread,buf,sizeof(buf))) > 0) + qmail_put(&qqt,buf,r); + close(fd); + if (r == -1) + qmail_fail(&qqt); + } + + qmail_from(&qqt,bouncesender); + qmail_to(&qqt,bouncerecip); + if (*qmail_close(&qqt)) + { log1("warning: trouble injecting bounce message, will try later\n"); return 0; } + + strnum2[fmt_ulong(strnum2,id)] = 0; + log2("bounce msg ",strnum2); + strnum2[fmt_ulong(strnum2,qp)] = 0; + log3(" qp ",strnum2,"\n"); + } + if (unlink(fn2.s) == -1) + { + log3("warning: unable to unlink ",fn2.s,"\n"); + return 0; + } + return 1; +} + + +/* this file is too long ---------------------------------------- DELIVERIES */ + +struct del + { + int used; + int j; + unsigned long delid; + seek_pos mpos; + stralloc recip; + } +; + +unsigned long masterdelid = 1; +unsigned int concurrency[CHANNELS] = { 10, 20 }; +unsigned int concurrencyused[CHANNELS] = { 0, 0 }; +struct del *d[CHANNELS]; +stralloc dline[CHANNELS]; +char delbuf[2048]; + +void del_status() +{ + int c; + + log1("status:"); + for (c = 0;c < CHANNELS;++c) { + strnum2[fmt_ulong(strnum2,(unsigned long) concurrencyused[c])] = 0; + strnum3[fmt_ulong(strnum3,(unsigned long) concurrency[c])] = 0; + log2(chanstatusmsg[c],strnum2); + log2("/",strnum3); + } + if (flagexitasap) log1(" exitasap"); + log1("\n"); +} + +void del_init() +{ + int c; + int i; + for (c = 0;c < CHANNELS;++c) + { + flagspawnalive[c] = 1; + while (!(d[c] = (struct del *) alloc(concurrency[c] * sizeof(struct del)))) + nomem(); + for (i = 0;i < concurrency[c];++i) + { d[c][i].used = 0; d[c][i].recip.s = 0; } + dline[c].s = 0; + while (!stralloc_copys(&dline[c],"")) nomem(); + } + del_status(); +} + +int del_canexit() +{ + int c; + for (c = 0;c < CHANNELS;++c) + if (flagspawnalive[c]) /* if dead, nothing we can do about its jobs */ + if (concurrencyused[c]) return 0; + return 1; +} + +int del_avail(c) +int c; +{ + return flagspawnalive[c] && comm_canwrite(c) && (concurrencyused[c] < concurrency[c]); +} + +void del_start(j,mpos,recip) +int j; +seek_pos mpos; +char *recip; +{ + int i; + int c; + + c = jo[j].channel; + if (!flagspawnalive[c]) return; + if (!comm_canwrite(c)) return; + + for (i = 0;i < concurrency[c];++i) if (!d[c][i].used) break; + if (i == concurrency[c]) return; + + if (!stralloc_copys(&d[c][i].recip,recip)) { nomem(); return; } + if (!stralloc_0(&d[c][i].recip)) { nomem(); return; } + d[c][i].j = j; ++jo[j].refs; + d[c][i].delid = masterdelid++; + d[c][i].mpos = mpos; + d[c][i].used = 1; ++concurrencyused[c]; + + comm_write(c,i,jo[j].id,jo[j].sender.s,recip); + + strnum2[fmt_ulong(strnum2,d[c][i].delid)] = 0; + strnum3[fmt_ulong(strnum3,jo[j].id)] = 0; + log2("starting delivery ",strnum2); + log3(": msg ",strnum3,tochan[c]); + logsafe(recip); + log1("\n"); + del_status(); +} + +void markdone(c,id,pos) +int c; +unsigned long id; +seek_pos pos; +{ + struct stat st; + int fd; + fnmake_chanaddr(id,c); + for (;;) + { + fd = open_write(fn.s); + if (fd == -1) break; + if (fstat(fd,&st) == -1) { close(fd); break; } + if (seek_set(fd,pos) == -1) { close(fd); break; } + if (write(fd,"D",1) != 1) { close(fd); break; } + /* further errors -> double delivery without us knowing about it, oh well */ + close(fd); + return; + } + log3("warning: trouble marking ",fn.s,"; message will be delivered twice!\n"); +} + +void del_dochan(c) +int c; +{ + int r; + char ch; + int i; + int delnum; + r = read(chanfdin[c],delbuf,sizeof(delbuf)); + if (r == -1) return; + if (r == 0) { spawndied(c); return; } + for (i = 0;i < r;++i) + { + ch = delbuf[i]; + while (!stralloc_append(&dline[c],&ch)) nomem(); + if (dline[c].len > REPORTMAX) + 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)) + { + delnum = (unsigned int) (unsigned char) dline[c].s[0]; + 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 (jo[d[c][delnum].j].flagdying) + { + dline[c].s[1] = '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]) + { + case 'K': + log3("delivery ",strnum3,": success: "); + logsafe(dline[c].s + 2); + 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); + log1("\n"); + break; + case 'D': + log3("delivery ",strnum3,": failure: "); + logsafe(dline[c].s + 2); + log1("\n"); + addbounce(jo[d[c][delnum].j].id,d[c][delnum].recip.s,dline[c].s + 2); + markdone(c,jo[d[c][delnum].j].id,d[c][delnum].mpos); + --jo[d[c][delnum].j].numtodo; + break; + default: + log3("delivery ",strnum3,": report mangled, will defer\n"); + } + job_close(d[c][delnum].j); + d[c][delnum].used = 0; --concurrencyused[c]; + del_status(); + } + dline[c].len = 0; + } + } +} + +void del_selprep(nfds,rfds) +int *nfds; +fd_set *rfds; +{ + int c; + for (c = 0;c < CHANNELS;++c) + if (flagspawnalive[c]) + { + FD_SET(chanfdin[c],rfds); + if (*nfds <= chanfdin[c]) + *nfds = chanfdin[c] + 1; + } +} + +void del_do(rfds) +fd_set *rfds; +{ + int c; + for (c = 0;c < CHANNELS;++c) + if (flagspawnalive[c]) + if (FD_ISSET(chanfdin[c],rfds)) + del_dochan(c); +} + + +/* this file is too long -------------------------------------------- PASSES */ + +struct + { + unsigned long id; /* if 0, need a new pass */ + int j; /* defined if id; job number */ + int fd; /* defined if id; reading from {local,remote} */ + seek_pos mpos; /* defined if id; mark position */ + substdio ss; + char buf[128]; + } +pass[CHANNELS]; + +void pass_init() +{ + int c; + for (c = 0;c < CHANNELS;++c) pass[c].id = 0; +} + +void pass_selprep(wakeup) +datetime_sec *wakeup; +{ + int c; + struct prioq_elt pe; + if (flagexitasap) return; + for (c = 0;c < CHANNELS;++c) + if (pass[c].id) + if (del_avail(c)) + { *wakeup = 0; return; } + if (job_avail()) + for (c = 0;c < CHANNELS;++c) + if (!pass[c].id) + if (prioq_min(&pqchan[c],&pe)) + if (*wakeup > pe.dt) + *wakeup = pe.dt; + if (prioq_min(&pqfail,&pe)) + if (*wakeup > pe.dt) + *wakeup = pe.dt; + if (prioq_min(&pqdone,&pe)) + if (*wakeup > pe.dt) + *wakeup = pe.dt; +} + +static datetime_sec squareroot(x) /* result^2 <= x < (result + 1)^2 */ +datetime_sec x; /* assuming: >= 0 */ +{ + datetime_sec y; + datetime_sec yy; + datetime_sec y21; + int j; + + y = 0; yy = 0; + for (j = 15;j >= 0;--j) + { + y21 = (y << (j + 1)) + (1 << (j + j)); + if (y21 <= x - yy) { y += (1 << j); yy += y21; } + } + return y; +} + +datetime_sec nextretry(birth,c) +datetime_sec birth; +int c; +{ + int n; + + if (birth > recent) n = 0; + else n = squareroot(recent - birth); /* no need to add fuzz to recent */ + n += chanskip[c]; + return birth + n * n; +} + +void pass_dochan(c) +int c; +{ + datetime_sec birth; + struct prioq_elt pe; + static stralloc line = {0}; + int match; + + if (flagexitasap) return; + + if (!pass[c].id) + { + if (!job_avail()) return; + if (!prioq_min(&pqchan[c],&pe)) return; + if (pe.dt > recent) return; + fnmake_chanaddr(pe.id,c); + + prioq_delmin(&pqchan[c]); + pass[c].mpos = 0; + pass[c].fd = open_read(fn.s); + if (pass[c].fd == -1) goto trouble; + if (!getinfo(&line,&birth,pe.id)) { close(pass[c].fd); goto trouble; } + pass[c].id = pe.id; + substdio_fdbuf(&pass[c].ss,read,pass[c].fd,pass[c].buf,sizeof(pass[c].buf)); + pass[c].j = job_open(pe.id,c); + jo[pass[c].j].retry = nextretry(birth,c); + jo[pass[c].j].flagdying = (recent > birth + lifetime); + while (!stralloc_copy(&jo[pass[c].j].sender,&line)) nomem(); + } + + if (!del_avail(c)) return; + + if (getln(&pass[c].ss,&line,&match,'\0') == -1) + { + fnmake_chanaddr(pass[c].id,c); + log3("warning: trouble reading ",fn.s,"; will try again later\n"); + close(pass[c].fd); + job_close(pass[c].j); + pass[c].id = 0; + return; + } + if (!match) + { + close(pass[c].fd); + jo[pass[c].j].flaghiteof = 1; + job_close(pass[c].j); + pass[c].id = 0; + return; + } + switch(line.s[0]) + { + case 'T': + ++jo[pass[c].j].numtodo; + del_start(pass[c].j,pass[c].mpos,line.s + 1); + break; + case 'D': + break; + default: + fnmake_chanaddr(pass[c].id,c); + log3("warning: unknown record type in ",fn.s,"!\n"); + close(pass[c].fd); + job_close(pass[c].j); + pass[c].id = 0; + return; + } + + pass[c].mpos += line.len; + return; + + trouble: + log3("warning: trouble opening ",fn.s,"; will try again later\n"); + pe.dt = recent + SLEEP_SYSFAIL; + while (!prioq_insert(&pqchan[c],&pe)) nomem(); +} + +void messdone(id) +unsigned long id; +{ + char ch; + int c; + struct prioq_elt pe; + struct stat st; + + for (c = 0;c < CHANNELS;++c) + { + fnmake_chanaddr(id,c); + if (stat(fn.s,&st) == 0) return; /* false alarm; consequence of HOPEFULLY */ + if (errno != error_noent) + { + log3("warning: unable to stat ",fn.s,"; will try again later\n"); + goto fail; + } + } + + fnmake_todo(id); + if (stat(fn.s,&st) == 0) return; + if (errno != error_noent) + { + log3("warning: unable to stat ",fn.s,"; will try again later\n"); + goto fail; + } + + fnmake_info(id); + if (stat(fn.s,&st) == -1) + { + if (errno == error_noent) return; + log3("warning: unable to stat ",fn.s,"; will try again later\n"); + goto fail; + } + + /* -todo +info -local -remote ?bounce */ + if (!injectbounce(id)) + goto fail; /* injectbounce() produced error message */ + + strnum3[fmt_ulong(strnum3,id)] = 0; + log3("end msg ",strnum3,"\n"); + + /* -todo +info -local -remote -bounce */ + fnmake_info(id); + if (unlink(fn.s) == -1) + { + log3("warning: unable to unlink ",fn.s,"; will try again later\n"); + goto fail; + } + + /* -todo -info -local -remote -bounce; we can relax */ + fnmake_foop(id); + if (substdio_putflush(&sstoqc,fn.s,fn.len) == -1) { cleandied(); return; } + if (substdio_get(&ssfromqc,&ch,1) != 1) { cleandied(); return; } + if (ch != '+') + log3("warning: qmail-clean unable to clean up ",fn.s,"\n"); + + return; + + fail: + pe.id = id; pe.dt = now() + SLEEP_SYSFAIL; + while (!prioq_insert(&pqdone,&pe)) nomem(); +} + +void pass_do() +{ + int c; + struct prioq_elt pe; + + for (c = 0;c < CHANNELS;++c) pass_dochan(c); + if (prioq_min(&pqfail,&pe)) + if (pe.dt <= recent) + { + prioq_delmin(&pqfail); + pqadd(pe.id); + } + if (prioq_min(&pqdone,&pe)) + if (pe.dt <= recent) + { + prioq_delmin(&pqdone); + messdone(pe.id); + } +} + + +/* this file is too long ---------------------------------------------- TODO */ + +datetime_sec nexttodorun; +DIR *tododir; /* if 0, have to opendir again */ +stralloc todoline = {0}; +char todobuf[SUBSTDIO_INSIZE]; +char todobufinfo[512]; +char todobufchan[CHANNELS][1024]; + +void todo_init() +{ + tododir = 0; + nexttodorun = now(); + trigger_set(); +} + +void todo_selprep(nfds,rfds,wakeup) +int *nfds; +fd_set *rfds; +datetime_sec *wakeup; +{ + if (flagexitasap) return; + trigger_selprep(nfds,rfds); + if (tododir) *wakeup = 0; + if (*wakeup > nexttodorun) *wakeup = nexttodorun; +} + +void todo_do(rfds) +fd_set *rfds; +{ + struct stat st; + substdio ss; int fd; + substdio ssinfo; int fdinfo; + substdio sschan[CHANNELS]; + int fdchan[CHANNELS]; + int flagchan[CHANNELS]; + struct prioq_elt pe; + char ch; + int match; + unsigned long id; + unsigned int len; + direntry *d; + int c; + unsigned long uid; + unsigned long pid; + + fd = -1; + fdinfo = -1; + for (c = 0;c < CHANNELS;++c) fdchan[c] = -1; + + if (flagexitasap) return; + + if (!tododir) + { + if (!trigger_pulled(rfds)) + if (recent < nexttodorun) + return; + trigger_set(); + tododir = opendir("todo"); + if (!tododir) + { + pausedir("todo"); + return; + } + nexttodorun = recent + SLEEP_TODO; + } + + d = readdir(tododir); + if (!d) + { + closedir(tododir); + tododir = 0; + return; + } + if (str_equal(d->d_name,".")) return; + if (str_equal(d->d_name,"..")) return; + len = scan_ulong(d->d_name,&id); + if (!len || d->d_name[len]) return; + + fnmake_todo(id); + + fd = open_read(fn.s); + if (fd == -1) { log3("warning: unable to open ",fn.s,"\n"); return; } + + fnmake_mess(id); + /* just for the statistics */ + if (stat(fn.s,&st) == -1) + { log3("warning: unable to stat ",fn.s,"\n"); goto fail; } + + for (c = 0;c < CHANNELS;++c) + { + fnmake_chanaddr(id,c); + if (unlink(fn.s) == -1) if (errno != error_noent) + { log3("warning: unable to unlink ",fn.s,"\n"); goto fail; } + } + + fnmake_info(id); + if (unlink(fn.s) == -1) if (errno != error_noent) + { log3("warning: unable to unlink ",fn.s,"\n"); goto fail; } + + fdinfo = open_excl(fn.s); + if (fdinfo == -1) + { log3("warning: unable to create ",fn.s,"\n"); goto fail; } + + strnum3[fmt_ulong(strnum3,id)] = 0; + log3("new msg ",strnum3,"\n"); + + for (c = 0;c < CHANNELS;++c) flagchan[c] = 0; + + substdio_fdbuf(&ss,read,fd,todobuf,sizeof(todobuf)); + substdio_fdbuf(&ssinfo,write,fdinfo,todobufinfo,sizeof(todobufinfo)); + + uid = 0; + pid = 0; + + for (;;) + { + if (getln(&ss,&todoline,&match,'\0') == -1) + { + /* perhaps we're out of memory, perhaps an I/O error */ + fnmake_todo(id); + log3("warning: trouble reading ",fn.s,"\n"); goto fail; + } + if (!match) break; + + switch(todoline.s[0]) + { + case 'u': + scan_ulong(todoline.s + 1,&uid); + break; + case 'p': + scan_ulong(todoline.s + 1,&pid); + break; + case 'F': + if (substdio_putflush(&ssinfo,todoline.s,todoline.len) == -1) + { + fnmake_info(id); + log3("warning: trouble writing to ",fn.s,"\n"); goto fail; + } + log2("info msg ",strnum3); + strnum2[fmt_ulong(strnum2,(unsigned long) st.st_size)] = 0; + log2(": bytes ",strnum2); + log1(" from <"); logsafe(todoline.s + 1); + strnum2[fmt_ulong(strnum2,pid)] = 0; + log2("> qp ",strnum2); + strnum2[fmt_ulong(strnum2,uid)] = 0; + log2(" uid ",strnum2); + log1("\n"); + break; + case 'T': + switch(rewrite(todoline.s + 1)) + { + case 0: nomem(); goto fail; + case 2: c = 1; break; + default: c = 0; break; + } + if (fdchan[c] == -1) + { + fnmake_chanaddr(id,c); + fdchan[c] = open_excl(fn.s); + if (fdchan[c] == -1) + { log3("warning: unable to create ",fn.s,"\n"); goto fail; } + substdio_fdbuf(&sschan[c] + ,write,fdchan[c],todobufchan[c],sizeof(todobufchan[c])); + flagchan[c] = 1; + } + if (substdio_bput(&sschan[c],rwline.s,rwline.len) == -1) + { + fnmake_chanaddr(id,c); + log3("warning: trouble writing to ",fn.s,"\n"); goto fail; + } + break; + default: + fnmake_todo(id); + log3("warning: unknown record type in ",fn.s,"\n"); goto fail; + } + } + + close(fd); fd = -1; + + fnmake_info(id); + if (substdio_flush(&ssinfo) == -1) + { log3("warning: trouble writing to ",fn.s,"\n"); goto fail; } + if (fsync(fdinfo) == -1) + { log3("warning: trouble fsyncing ",fn.s,"\n"); goto fail; } + close(fdinfo); fdinfo = -1; + + for (c = 0;c < CHANNELS;++c) + if (fdchan[c] != -1) + { + fnmake_chanaddr(id,c); + if (substdio_flush(&sschan[c]) == -1) + { log3("warning: trouble writing to ",fn.s,"\n"); goto fail; } + if (fsync(fdchan[c]) == -1) + { log3("warning: trouble fsyncing ",fn.s,"\n"); goto fail; } + close(fdchan[c]); fdchan[c] = -1; + } + + fnmake_todo(id); + if (substdio_putflush(&sstoqc,fn.s,fn.len) == -1) { cleandied(); return; } + if (substdio_get(&ssfromqc,&ch,1) != 1) { cleandied(); return; } + if (ch != '+') + { + log3("warning: qmail-clean unable to clean up ",fn.s,"\n"); + return; + } + + pe.id = id; pe.dt = now(); + for (c = 0;c < CHANNELS;++c) + if (flagchan[c]) + while (!prioq_insert(&pqchan[c],&pe)) nomem(); + + for (c = 0;c < CHANNELS;++c) if (flagchan[c]) break; + if (c == CHANNELS) + while (!prioq_insert(&pqdone,&pe)) nomem(); + + return; + + fail: + if (fd != -1) close(fd); + if (fdinfo != -1) close(fdinfo); + for (c = 0;c < CHANNELS;++c) + if (fdchan[c] != -1) close(fdchan[c]); +} + + +/* this file is too long ---------------------------------------------- MAIN */ + +int getcontrols() { if (control_init() == -1) return 0; + if (control_readint(&lifetime,"control/queuelifetime") == -1) return 0; + if (control_readint(&concurrency[0],"control/concurrencylocal") == -1) return 0; + if (control_readint(&concurrency[1],"control/concurrencyremote") == -1) return 0; + if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1) return 0; + if (control_rldef(&bouncefrom,"control/bouncefrom",0,"MAILER-DAEMON") != 1) return 0; + if (control_rldef(&bouncehost,"control/bouncehost",1,"bouncehost") != 1) return 0; + if (control_rldef(&doublebouncehost,"control/doublebouncehost",1,"doublebouncehost") != 1) return 0; + if (control_rldef(&doublebounceto,"control/doublebounceto",0,"postmaster") != 1) return 0; + if (!stralloc_cats(&doublebounceto,"@")) return 0; + if (!stralloc_cat(&doublebounceto,&doublebouncehost)) return 0; + if (!stralloc_0(&doublebounceto)) 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)) + { + case -1: return 0; + case 0: if (!constmap_init(&mappercenthack,"",0,0)) return 0; break; + case 1: if (!constmap_init(&mappercenthack,percenthack.s,percenthack.len,0)) return 0; break; + } + switch(control_readfile(&vdoms,"control/virtualdomains",0)) + { + case -1: return 0; + case 0: if (!constmap_init(&mapvdoms,"",0,1)) return 0; break; + case 1: if (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) return 0; break; + } + return 1; } + +stralloc newlocals = {0}; +stralloc newvdoms = {0}; + +void regetcontrols() +{ + int r; + + if (control_readfile(&newlocals,"control/locals",1) != 1) + { log1("alert: unable to reread control/locals\n"); return; } + r = control_readfile(&newvdoms,"control/virtualdomains",0); + if (r == -1) + { log1("alert: unable to reread control/virtualdomains\n"); return; } + + constmap_free(&maplocals); + constmap_free(&mapvdoms); + + while (!stralloc_copy(&locals,&newlocals)) nomem(); + while (!constmap_init(&maplocals,locals.s,locals.len,0)) nomem(); + + if (r) + { + while (!stralloc_copy(&vdoms,&newvdoms)) nomem(); + while (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) nomem(); + } + else + while (!constmap_init(&mapvdoms,"",0,1)) nomem(); +} + +void reread() +{ + if (chdir(auto_qmail) == -1) + { + log1("alert: unable to reread controls: unable to switch to home directory\n"); + return; + } + regetcontrols(); + while (chdir("queue") == -1) + { + log1("alert: unable to switch back to queue directory; HELP! sleeping...\n"); + sleep(10); + } +} + +void main() +{ + int fd; + datetime_sec wakeup; + fd_set rfds; + fd_set wfds; + int nfds; + struct timeval tv; + int c; + + if (chdir(auto_qmail) == -1) + { log1("alert: cannot start: unable to switch to home directory\n"); _exit(111); } + if (!getcontrols()) + { log1("alert: cannot start: unable to read controls\n"); _exit(111); } + if (chdir("queue") == -1) + { log1("alert: cannot start: unable to switch to queue directory\n"); _exit(111); } + sig_pipeignore(); + sig_termcatch(sigterm); + sig_alarmcatch(sigalrm); + sig_hangupcatch(sighup); + sig_childdefault(); + umask(077); + + fd = open_write("lock/sendmutex"); + if (fd == -1) + { log1("alert: cannot start: unable to open mutex\n"); _exit(111); } + if (lock_exnb(fd) == -1) + { log1("alert: cannot start: qmail-send is already running\n"); _exit(111); } + + numjobs = 0; + for (c = 0;c < CHANNELS;++c) + { + char ch; + int u; + int r; + do + r = read(chanfdin[c],&ch,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; + if (concurrency[c] > u) concurrency[c] = u; + numjobs += concurrency[c]; + } + + fnmake_init(); + + comm_init(); + + pqstart(); + job_init(); + del_init(); + pass_init(); + todo_init(); + cleanup_init(); + + while (!flagexitasap || !del_canexit()) + { + recent = now(); + + if (flagrunasap) { flagrunasap = 0; pqrun(); } + if (flagreadasap) { flagreadasap = 0; reread(); } + + wakeup = recent + SLEEP_FOREVER; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + nfds = 1; + + comm_selprep(&nfds,&wfds); + del_selprep(&nfds,&rfds); + pass_selprep(&wakeup); + todo_selprep(&nfds,&rfds,&wakeup); + cleanup_selprep(&wakeup); + + if (wakeup <= recent) tv.tv_sec = 0; + else tv.tv_sec = wakeup - recent + SLEEP_FUZZ; + tv.tv_usec = 0; + + if (select(nfds,&rfds,&wfds,(fd_set *) 0,&tv) == -1) + if (errno == error_intr) + ; + else + log1("warning: trouble in select\n"); + else + { + recent = now(); + + comm_do(&wfds); + del_do(&rfds); + todo_do(&rfds); + pass_do(); + cleanup_do(); + } + } + pqfinish(); + log1("status: exiting\n"); + _exit(0); +} diff -u -N qmail-1.03-orig/qmail-showctl.c test/qmail-showctl.c --- qmail-1.03-orig/qmail-showctl.c Mon Jun 15 12:53:16 1998 +++ test/qmail-showctl.c Thu Mar 1 23:58:54 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,34 @@ 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("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 +338,32 @@ 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,"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 -u -N qmail-1.03-orig/qmail-showctl.c.orig test/qmail-showctl.c.orig --- qmail-1.03-orig/qmail-showctl.c.orig Thu Jan 1 01:00:00 1970 +++ test/qmail-showctl.c.orig Thu Mar 1 23:58:54 2001 @@ -0,0 +1,306 @@ +#include +#include +#include "substdio.h" +#include "subfd.h" +#include "exit.h" +#include "fmt.h" +#include "str.h" +#include "control.h" +#include "constmap.h" +#include "stralloc.h" +#include "direntry.h" +#include "auto_uids.h" +#include "auto_qmail.h" +#include "auto_break.h" +#include "auto_patrn.h" +#include "auto_spawn.h" +#include "auto_split.h" + +stralloc me = {0}; +int meok; + +stralloc line = {0}; +char num[FMT_ULONG]; + +void safeput(buf,len) +char *buf; +unsigned int len; +{ + char ch; + + while (len > 0) { + ch = *buf; + if ((ch < 32) || (ch > 126)) ch = '?'; + substdio_put(subfdout,&ch,1); + ++buf; + --len; + } +} + +void do_int(fn,def,pre,post) +char *fn; +char *def; +char *pre; +char *post; +{ + int i; + substdio_puts(subfdout,"\n"); + substdio_puts(subfdout,fn); + substdio_puts(subfdout,": "); + switch(control_readint(&i,fn)) { + case 0: + substdio_puts(subfdout,"(Default.) "); + substdio_puts(subfdout,pre); + substdio_puts(subfdout,def); + substdio_puts(subfdout,post); + substdio_puts(subfdout,".\n"); + break; + case 1: + if (i < 0) i = 0; + substdio_puts(subfdout,pre); + substdio_put(subfdout,num,fmt_uint(num,i)); + substdio_puts(subfdout,post); + substdio_puts(subfdout,".\n"); + break; + default: + substdio_puts(subfdout,"Oops! Trouble reading this file.\n"); + break; + } +} + +void do_str(fn,flagme,def,pre) +char *fn; +int flagme; +char *def; +char *pre; +{ + substdio_puts(subfdout,"\n"); + substdio_puts(subfdout,fn); + substdio_puts(subfdout,": "); + switch(control_readline(&line,fn)) { + case 0: + substdio_puts(subfdout,"(Default.) "); + if (!stralloc_copys(&line,def)) { + substdio_puts(subfdout,"Oops! Out of memory.\n"); + break; + } + if (flagme && meok) + if (!stralloc_copy(&line,&me)) { + substdio_puts(subfdout,"Oops! Out of memory.\n"); + break; + } + case 1: + substdio_puts(subfdout,pre); + safeput(line.s,line.len); + substdio_puts(subfdout,".\n"); + break; + default: + substdio_puts(subfdout,"Oops! Trouble reading this file.\n"); + break; + } +} + +int do_lst(fn,def,pre,post) +char *fn; +char *def; +char *pre; +char *post; +{ + int i; + int j; + + substdio_puts(subfdout,"\n"); + substdio_puts(subfdout,fn); + substdio_puts(subfdout,": "); + switch(control_readfile(&line,fn)) { + case 0: + substdio_puts(subfdout,"(Default.) "); + substdio_puts(subfdout,def); + substdio_puts(subfdout,"\n"); + return 0; + case 1: + substdio_puts(subfdout,"\n"); + i = 0; + for (j = 0;j < line.len;++j) + if (!line.s[j]) { + substdio_puts(subfdout,pre); + safeput(line.s + i,j - i); + substdio_puts(subfdout,post); + substdio_puts(subfdout,"\n"); + i = j + 1; + } + return 1; + default: + substdio_puts(subfdout,"Oops! Trouble reading this file.\n"); + return -1; + } +} + +void main() +{ + DIR *dir; + direntry *d; + struct stat stmrh; + struct stat stmrhcdb; + + substdio_puts(subfdout,"qmail home directory: "); + substdio_puts(subfdout,auto_qmail); + substdio_puts(subfdout,".\n"); + + substdio_puts(subfdout,"user-ext delimiter: "); + substdio_puts(subfdout,auto_break); + substdio_puts(subfdout,".\n"); + + substdio_puts(subfdout,"paternalism (in decimal): "); + substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_patrn)); + substdio_puts(subfdout,".\n"); + + substdio_puts(subfdout,"silent concurrency limit: "); + substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_spawn)); + substdio_puts(subfdout,".\n"); + + substdio_puts(subfdout,"subdirectory split: "); + substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_split)); + substdio_puts(subfdout,".\n"); + + substdio_puts(subfdout,"user ids: "); + substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uida)); + substdio_puts(subfdout,", "); + substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidd)); + substdio_puts(subfdout,", "); + substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidl)); + substdio_puts(subfdout,", "); + substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uido)); + substdio_puts(subfdout,", "); + substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidp)); + substdio_puts(subfdout,", "); + substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidq)); + substdio_puts(subfdout,", "); + substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidr)); + substdio_puts(subfdout,", "); + substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uids)); + substdio_puts(subfdout,".\n"); + + substdio_puts(subfdout,"group ids: "); + substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_gidn)); + substdio_puts(subfdout,", "); + substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_gidq)); + substdio_puts(subfdout,".\n"); + + if (chdir(auto_qmail) == -1) { + substdio_puts(subfdout,"Oops! Unable to chdir to "); + substdio_puts(subfdout,auto_qmail); + substdio_puts(subfdout,".\n"); + substdio_flush(subfdout); + _exit(111); + } + if (chdir("control") == -1) { + substdio_puts(subfdout,"Oops! Unable to chdir to control.\n"); + substdio_flush(subfdout); + _exit(111); + } + + dir = opendir("."); + if (!dir) { + substdio_puts(subfdout,"Oops! Unable to open current directory.\n"); + substdio_flush(subfdout); + _exit(111); + } + + meok = control_readline(&me,"me"); + if (meok == -1) { + substdio_puts(subfdout,"Oops! Trouble reading control/me."); + substdio_flush(subfdout); + _exit(111); + } + + do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM."); + do_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is "); + do_str("bouncehost",1,"bouncehost","Bounce host name is "); + do_int("concurrencylocal","10","Local concurrency is ",""); + do_int("concurrencyremote","20","Remote concurrency is ",""); + do_int("databytes","0","SMTP DATA limit is "," bytes"); + do_str("defaultdomain",1,"defaultdomain","Default domain name is "); + do_str("defaulthost",1,"defaulthost","Default host name is "); + do_str("doublebouncehost",1,"doublebouncehost","2B recipient host: "); + do_str("doublebounceto",0,"postmaster","2B recipient user: "); + do_str("envnoathost",1,"envnoathost","Presumed domain name is "); + do_str("helohost",1,"helohost","SMTP client HELO host name is "); + do_str("idhost",1,"idhost","Message-ID host name is "); + do_str("localiphost",1,"localiphost","Local IP address becomes "); + do_lst("locals","Messages for me are delivered locally.","Messages for "," are delivered locally."); + do_str("me",0,"undefined! Uh-oh","My name is "); + do_lst("percenthack","The percent hack is not allowed.","The percent hack is allowed for user%host@","."); + do_str("plusdomain",1,"plusdomain","Plus domain name is "); + do_lst("qmqpservers","No QMQP servers.","QMQP server: ","."); + do_int("queuelifetime","604800","Message lifetime in the queue is "," seconds"); + + if (do_lst("rcpthosts","SMTP clients may send messages to any recipient.","SMTP clients may send messages to recipients at ",".")) + do_lst("morercpthosts","No effect.","SMTP clients may send messages to recipients at ","."); + else + do_lst("morercpthosts","No rcpthosts; morercpthosts is irrelevant.","No rcpthosts; doesn't matter that morercpthosts has ","."); + /* XXX: check morercpthosts.cdb contents */ + substdio_puts(subfdout,"\nmorercpthosts.cdb: "); + if (stat("morercpthosts",&stmrh) == -1) + if (stat("morercpthosts.cdb",&stmrhcdb) == -1) + substdio_puts(subfdout,"(Default.) No effect.\n"); + else + substdio_puts(subfdout,"Oops! morercpthosts.cdb exists but morercpthosts doesn't.\n"); + else + if (stat("morercpthosts.cdb",&stmrhcdb) == -1) + substdio_puts(subfdout,"Oops! morercpthosts exists but morercpthosts.cdb doesn't.\n"); + else + if (stmrh.st_mtime > stmrhcdb.st_mtime) + substdio_puts(subfdout,"Oops! morercpthosts.cdb is older than morercpthosts.\n"); + else + substdio_puts(subfdout,"Modified recently enough; hopefully up to date.\n"); + + do_str("smtpgreeting",1,"smtpgreeting","SMTP greeting: 220 "); + do_lst("smtproutes","No artificial SMTP routes.","SMTP route: ",""); + do_int("timeoutconnect","60","SMTP client connection timeout is "," seconds"); + do_int("timeoutremote","1200","SMTP client data timeout is "," seconds"); + do_int("timeoutsmtpd","1200","SMTP server data timeout is "," seconds"); + do_lst("virtualdomains","No virtual domains.","Virtual domain: ",""); + + while (d = readdir(dir)) { + if (str_equal(d->d_name,".")) continue; + if (str_equal(d->d_name,"..")) continue; + if (str_equal(d->d_name,"bouncefrom")) continue; + if (str_equal(d->d_name,"bouncehost")) continue; + if (str_equal(d->d_name,"badmailfrom")) continue; + if (str_equal(d->d_name,"bouncefrom")) continue; + if (str_equal(d->d_name,"bouncehost")) continue; + if (str_equal(d->d_name,"concurrencylocal")) continue; + if (str_equal(d->d_name,"concurrencyremote")) continue; + if (str_equal(d->d_name,"databytes")) continue; + if (str_equal(d->d_name,"defaultdomain")) continue; + if (str_equal(d->d_name,"defaulthost")) continue; + if (str_equal(d->d_name,"doublebouncehost")) continue; + if (str_equal(d->d_name,"doublebounceto")) continue; + if (str_equal(d->d_name,"envnoathost")) continue; + if (str_equal(d->d_name,"helohost")) continue; + if (str_equal(d->d_name,"idhost")) continue; + if (str_equal(d->d_name,"localiphost")) continue; + if (str_equal(d->d_name,"locals")) continue; + if (str_equal(d->d_name,"me")) continue; + if (str_equal(d->d_name,"morercpthosts")) continue; + if (str_equal(d->d_name,"morercpthosts.cdb")) continue; + if (str_equal(d->d_name,"percenthack")) continue; + if (str_equal(d->d_name,"plusdomain")) continue; + if (str_equal(d->d_name,"qmqpservers")) continue; + if (str_equal(d->d_name,"queuelifetime")) continue; + if (str_equal(d->d_name,"rcpthosts")) continue; + if (str_equal(d->d_name,"smtpgreeting")) continue; + if (str_equal(d->d_name,"smtproutes")) continue; + if (str_equal(d->d_name,"timeoutconnect")) continue; + 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"); + substdio_puts(subfdout,d->d_name); + substdio_puts(subfdout,": I have no idea what this file does.\n"); + } + + substdio_flush(subfdout); + _exit(0); +} diff -u -N qmail-1.03-orig/qmail-smtpd.c test/qmail-smtpd.c --- qmail-1.03-orig/qmail-smtpd.c Mon Jun 15 12:53:16 1998 +++ test/qmail-smtpd.c Thu Mar 1 23:58:54 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(); + 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() { out("553 sorry, your mailserver is listed in an RBL, 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 (#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,10 @@ char *remoteinfo; char *local; char *relayclient; +char *relayok; +char *denymail; +char *rblenabled; +int spamflag = 0; stralloc helohost = {0}; char *fakehelo; /* pointer into helohost, or 0 */ @@ -96,27 +202,68 @@ int bmfok = 0; stralloc bmf = {0}; struct constmap mapbmf; +int rmfok = 0; +stralloc rmf = {0}; +struct constmap maprmf; +int rblok = 0; +stralloc rbl = {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"); + if (control_readint(&databytes,"control/databytes") == -1) die_control(); x = env_get("DATABYTES"); if (x) { scan_ulong(x,&u); databytes = u; } @@ -124,13 +271,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 +354,159 @@ 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; + } +} + +int rblcheck() +{ + int r; + 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(); + return 2; + } + if (r == 1) + { + logstring(2,"found match, sender is blocked"); logflush(); + return 1; + } + /* continue */ + logstring(2,"no match found, continue"); logflush(); + 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 +514,339 @@ 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"); } + 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 */ + err_rbl(); + return; + default: /* ok, go ahead */ + logline(3,"RBL checking completed without match"); + } + } + + /* 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 +855,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; @@ -280,6 +870,7 @@ struct qmail qqt; unsigned int bytestooverflow = 0; +unsigned int bytesreceived = 0; void put(ch) char *ch; @@ -288,6 +879,7 @@ if (!--bytestooverflow) qmail_fail(&qqt); qmail_put(&qqt,ch,1); + ++bytesreceived; } void blast(hops) @@ -359,41 +951,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 +1096,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 +1106,9 @@ void main() { +#ifdef TLS + sig_alarmcatch(sigalrm); +#endif sig_pipeignore(); if (chdir(auto_qmail) == -1) die_control(); setup(); diff -u -N qmail-1.03-orig/qmail-smtpd.c.orig test/qmail-smtpd.c.orig --- qmail-1.03-orig/qmail-smtpd.c.orig Thu Jan 1 01:00:00 1970 +++ test/qmail-smtpd.c.orig Thu Mar 1 23:58:54 2001 @@ -0,0 +1,421 @@ +#include "sig.h" +#include "readwrite.h" +#include "stralloc.h" +#include "substdio.h" +#include "alloc.h" +#include "auto_qmail.h" +#include "control.h" +#include "received.h" +#include "constmap.h" +#include "error.h" +#include "ipme.h" +#include "ip.h" +#include "qmail.h" +#include "str.h" +#include "fmt.h" +#include "scan.h" +#include "byte.h" +#include "case.h" +#include "env.h" +#include "now.h" +#include "exit.h" +#include "rcpthosts.h" +#include "timeoutread.h" +#include "timeoutwrite.h" +#include "commands.h" + +#define MAXHOPS 100 +unsigned int databytes = 0; +int timeout = 1200; + +int safewrite(fd,buf,len) int fd; char *buf; int len; +{ + int r; + r = timeoutwrite(timeout,fd,buf,len); + if (r <= 0) _exit(1); + return r; +} + +char ssoutbuf[512]; +substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); + +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); } + +void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#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"); } +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_qqt() { out("451 qqt failure (#4.3.0)\r\n"); } + + +stralloc greeting = {0}; + +void smtp_greet(code) char *code; +{ + substdio_puts(&ssout,code); + substdio_put(&ssout,greeting.s,greeting.len); +} +void smtp_help() +{ + out("214 qmail home page: http://pobox.com/~djb/qmail.html\r\n"); +} +void smtp_quit() +{ + smtp_greet("221 "); out("\r\n"); flush(); _exit(0); +} + +char *remoteip; +char *remotehost; +char *remoteinfo; +char *local; +char *relayclient; + +stralloc helohost = {0}; +char *fakehelo; /* pointer into helohost, or 0 */ + +void dohelo(arg) char *arg; { + if (!stralloc_copys(&helohost,arg)) die_nomem(); + if (!stralloc_0(&helohost)) die_nomem(); + fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0; +} + +int liphostok = 0; +stralloc liphost = {0}; +int bmfok = 0; +stralloc bmf = {0}; +struct constmap mapbmf; + +void setup() +{ + char *x; + unsigned long u; + + 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 (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(); + + if (control_readint(&databytes,"control/databytes") == -1) die_control(); + x = env_get("DATABYTES"); + if (x) { scan_ulong(x,&u); databytes = u; } + if (!(databytes + 1)) --databytes; + + remoteip = env_get("TCPREMOTEIP"); + if (!remoteip) remoteip = "unknown"; + local = env_get("TCPLOCALHOST"); + if (!local) local = env_get("TCPLOCALIP"); + if (!local) local = "unknown"; + remotehost = env_get("TCPREMOTEHOST"); + if (!remotehost) remotehost = "unknown"; + remoteinfo = env_get("TCPREMOTEINFO"); + relayclient = env_get("RELAYCLIENT"); + dohelo(remotehost); +} + + +stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */ + +int addrparse(arg) +char *arg; +{ + int i; + char ch; + char terminator; + struct ip_address ip; + int flagesc; + int flagquoted; + + terminator = '>'; + i = str_chr(arg,'<'); + if (arg[i]) + arg += i + 1; + else { /* partner should go read rfc 821 */ + terminator = ' '; + arg += str_chr(arg,':'); + if (*arg == ':') ++arg; + while (*arg == ' ') ++arg; + } + + /* strip source route */ + if (*arg == '@') while (*arg) if (*arg++ == ':') break; + + if (!stralloc_copys(&addr,"")) die_nomem(); + flagesc = 0; + flagquoted = 0; + for (i = 0;ch = arg[i];++i) { /* copy arg to addr, stripping quotes */ + if (flagesc) { + if (!stralloc_append(&addr,&ch)) die_nomem(); + flagesc = 0; + } + else { + if (!flagquoted && (ch == terminator)) break; + switch(ch) { + case '\\': flagesc = 1; break; + case '"': flagquoted = !flagquoted; break; + default: if (!stralloc_append(&addr,&ch)) die_nomem(); + } + } + } + /* could check for termination failure here, but why bother? */ + if (!stralloc_append(&addr,"")) die_nomem(); + + if (liphostok) { + i = byte_rchr(addr.s,addr.len,'@'); + if (i < addr.len) /* if not, partner should go read rfc 821 */ + if (addr.s[i + 1] == '[') + if (!addr.s[i + 1 + ip_scanbracket(addr.s + i + 1,&ip)]) + if (ipme_is(&ip)) { + addr.len = i + 1; + if (!stralloc_cat(&addr,&liphost)) die_nomem(); + if (!stralloc_0(&addr)) die_nomem(); + } + } + + if (addr.len > 900) return 0; + return 1; +} + +int bmfcheck() +{ + int j; + if (!bmfok) return 0; + 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; + return 0; +} + +int addrallowed() +{ + int r; + 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); +} +void smtp_ehlo(arg) char *arg; +{ + smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); + seenmail = 0; dohelo(arg); +} +void smtp_rset() +{ + seenmail = 0; + out("250 flushed\r\n"); +} +void smtp_mail(arg) char *arg; +{ + if (!addrparse(arg)) { err_syntax(); return; } + flagbarf = bmfcheck(); + seenmail = 1; + if (!stralloc_copys(&rcptto,"")) die_nomem(); + if (!stralloc_copys(&mailfrom,addr.s)) die_nomem(); + if (!stralloc_0(&mailfrom)) die_nomem(); + 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; } + if (relayclient) { + --addr.len; + if (!stralloc_cats(&addr,relayclient)) die_nomem(); + if (!stralloc_0(&addr)) die_nomem(); + } + else + if (!addrallowed()) { err_nogateway(); return; } + if (!stralloc_cats(&rcptto,"T")) die_nomem(); + if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); + if (!stralloc_0(&rcptto)) die_nomem(); + out("250 ok\r\n"); +} + + +int saferead(fd,buf,len) int fd; char *buf; int len; +{ + int r; + flush(); + r = timeoutread(timeout,fd,buf,len); + if (r == -1) if (errno == error_timeout) die_alarm(); + if (r <= 0) die_read(); + return r; +} + +char ssinbuf[1024]; +substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); + +struct qmail qqt; +unsigned int bytestooverflow = 0; + +void put(ch) +char *ch; +{ + if (bytestooverflow) + if (!--bytestooverflow) + qmail_fail(&qqt); + qmail_put(&qqt,ch,1); +} + +void blast(hops) +int *hops; +{ + char ch; + int state; + int flaginheader; + int pos; /* number of bytes since most recent \n, if fih */ + int flagmaybex; /* 1 if this line might match RECEIVED, if fih */ + int flagmaybey; /* 1 if this line might match \r\n, if fih */ + int flagmaybez; /* 1 if this line might match DELIVERED, if fih */ + + state = 1; + *hops = 0; + flaginheader = 1; + pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; + for (;;) { + substdio_get(&ssin,&ch,1); + if (flaginheader) { + if (pos < 9) { + if (ch != "delivered"[pos]) if (ch != "DELIVERED"[pos]) flagmaybez = 0; + if (flagmaybez) if (pos == 8) ++*hops; + if (pos < 8) + if (ch != "received"[pos]) if (ch != "RECEIVED"[pos]) flagmaybex = 0; + if (flagmaybex) if (pos == 7) ++*hops; + if (pos < 2) if (ch != "\r\n"[pos]) flagmaybey = 0; + if (flagmaybey) if (pos == 1) flaginheader = 0; + } + ++pos; + if (ch == '\n') { pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; } + } + switch(state) { + case 0: + if (ch == '\n') straynewline(); + if (ch == '\r') { state = 4; continue; } + break; + case 1: /* \r\n */ + if (ch == '\n') straynewline(); + if (ch == '.') { state = 2; continue; } + if (ch == '\r') { state = 4; continue; } + state = 0; + break; + case 2: /* \r\n + . */ + if (ch == '\n') straynewline(); + if (ch == '\r') { state = 3; continue; } + state = 0; + break; + case 3: /* \r\n + .\r */ + if (ch == '\n') return; + put("."); + put("\r"); + if (ch == '\r') { state = 4; continue; } + state = 0; + break; + case 4: /* + \r */ + if (ch == '\n') { state = 1; break; } + if (ch != '\r') { put("\r"); state = 0; } + } + put(&ch); + } +} + +char accept_buf[FMT_ULONG]; +void acceptmessage(qp) unsigned long qp; +{ + datetime_sec when; + when = now(); + out("250 ok "); + accept_buf[fmt_ulong(accept_buf,(unsigned long) when)] = 0; + out(accept_buf); + out(" qp "); + accept_buf[fmt_ulong(accept_buf,qp)] = 0; + out(accept_buf); + out("\r\n"); +} + +void smtp_data() { + int hops; + unsigned long qp; + char *qqx; + + 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; } + qp = qmail_qp(&qqt); + out("354 go ahead\r\n"); + + received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo); + blast(&hops); + hops = (hops >= MAXHOPS); + if (hops) 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 "); + out(qqx + 1); + out("\r\n"); +} + +struct commands smtpcommands[] = { + { "rcpt", smtp_rcpt, 0 } +, { "mail", smtp_mail, 0 } +, { "data", smtp_data, flush } +, { "quit", smtp_quit, flush } +, { "helo", smtp_helo, flush } +, { "ehlo", smtp_ehlo, flush } +, { "rset", smtp_rset, 0 } +, { "help", smtp_help, flush } +, { "noop", err_noop, flush } +, { "vrfy", err_vrfy, flush } +, { 0, err_unimpl, flush } +} ; + +void main() +{ + sig_pipeignore(); + if (chdir(auto_qmail) == -1) die_control(); + setup(); + if (ipme_init() != 1) die_ipme(); + smtp_greet("220 "); + out(" ESMTP\r\n"); + if (commands(&ssin,&smtpcommands) == 0) die_read(); + die_nomem(); +} diff -u -N qmail-1.03-orig/qmail.schema test/qmail.schema --- qmail-1.03-orig/qmail.schema Thu Jan 1 01:00:00 1970 +++ test/qmail.schema Thu Mar 1 23:58:54 2001 @@ -0,0 +1,97 @@ +# +# 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' + 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 ) ) + diff -u -N qmail-1.03-orig/received.c test/received.c --- qmail-1.03-orig/received.c Mon Jun 15 12:53:16 1998 +++ test/received.c Thu Mar 1 23:58:54 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,22 @@ 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)); } diff -u -N qmail-1.03-orig/received.c.orig test/received.c.orig --- qmail-1.03-orig/received.c.orig Thu Jan 1 01:00:00 1970 +++ test/received.c.orig Thu Mar 1 23:58:54 2001 @@ -0,0 +1,71 @@ +#include "fmt.h" +#include "qmail.h" +#include "now.h" +#include "datetime.h" +#include "date822fmt.h" +#include "received.h" + +static int issafe(ch) char ch; +{ + if (ch == '.') return 1; + if (ch == '@') return 1; + if (ch == '%') return 1; + if (ch == '+') return 1; + if (ch == '/') return 1; + if (ch == '=') return 1; + if (ch == ':') return 1; + if (ch == '-') return 1; + if ((ch >= 'a') && (ch <= 'z')) return 1; + if ((ch >= 'A') && (ch <= 'Z')) return 1; + if ((ch >= '0') && (ch <= '9')) return 1; + return 0; +} + +void safeput(qqt,s) +struct qmail *qqt; +char *s; +{ + char ch; + while (ch = *s++) { + if (!issafe(ch)) ch = '?'; + qmail_put(qqt,&ch,1); + } +} + +static char buf[DATE822FMT]; + +/* "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) +struct qmail *qqt; +char *protocol; +char *local; +char *remoteip; +char *remotehost; +char *remoteinfo; +char *helo; +{ + struct datetime dt; + + qmail_puts(qqt,"Received: from "); + safeput(qqt,remotehost); + if (helo) { + qmail_puts(qqt," (HELO "); + safeput(qqt,helo); + qmail_puts(qqt,")"); + } + qmail_puts(qqt," ("); + if (remoteinfo) { + safeput(qqt,remoteinfo); + qmail_puts(qqt,"@"); + } + safeput(qqt,remoteip); + qmail_puts(qqt,")\n by "); + safeput(qqt,local); + qmail_puts(qqt," with "); + qmail_puts(qqt,protocol); + qmail_puts(qqt,"; "); + datetime_tai(&dt,now()); + qmail_put(qqt,buf,date822fmt(buf,&dt)); +} diff -u -N qmail-1.03-orig/spawn.c test/spawn.c --- qmail-1.03-orig/spawn.c Mon Jun 15 12:53:16 1998 +++ test/spawn.c Thu Mar 1 23:58:54 2001 @@ -63,7 +63,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 +73,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 +156,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 +205,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,7 +241,8 @@ 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); diff -u -N qmail-1.03-orig/spawn.c.orig test/spawn.c.orig --- qmail-1.03-orig/spawn.c.orig Thu Jan 1 01:00:00 1970 +++ test/spawn.c.orig Thu Mar 1 23:58:54 2001 @@ -0,0 +1,259 @@ +#include +#include +#include "sig.h" +#include "wait.h" +#include "substdio.h" +#include "byte.h" +#include "str.h" +#include "stralloc.h" +#include "select.h" +#include "exit.h" +#include "coe.h" +#include "open.h" +#include "error.h" +#include "auto_qmail.h" +#include "auto_uids.h" +#include "auto_spawn.h" + +extern int truncreport; +extern int spawn(); +extern void report(); +extern void initialize(); + +struct delivery + { + int used; + int fdin; /* pipe input */ + int pid; /* zero if child is dead */ + int wstat; /* if !pid: status of child */ + int fdout; /* pipe output, -1 if !pid; delays eof until after death */ + stralloc output; + } +; + +struct delivery *d; + +void sigchld() +{ + int wstat; + int pid; + int i; + while ((pid = wait_nohang(&wstat)) > 0) + for (i = 0;i < auto_spawn;++i) if (d[i].used) + if (d[i].pid == pid) + { + close(d[i].fdout); d[i].fdout = -1; + d[i].wstat = wstat; d[i].pid = 0; + } +} + +int flagwriting = 1; + +int okwrite(fd,buf,n) int fd; char *buf; int n; +{ + int w; + if (!flagwriting) return n; + w = write(fd,buf,n); + if (w != -1) return w; + if (errno == error_intr) return -1; + flagwriting = 0; close(fd); + return n; +} + +int flagreading = 1; +char outbuf[1024]; substdio ssout; + +int stage = 0; /* reading 0:delnum 1:messid 2:sender 3:recip */ +int flagabort = 0; /* if 1, everything except delnum is garbage */ +int delnum; +stralloc messid = {0}; +stralloc sender = {0}; +stralloc recip = {0}; + +void err(s) char *s; +{ + char ch; ch = delnum; substdio_put(&ssout,&ch,1); + substdio_puts(&ssout,s); substdio_putflush(&ssout,"",1); +} + +void docmd() +{ + int f; + int i; + int j; + int fdmess; + int pi[2]; + struct stat st; + + if (flagabort) { err("Zqmail-spawn out of memory. (#4.3.0)\n"); return; } + if (delnum < 0) { err("ZInternal error: delnum negative. (#4.3.5)\n"); return; } + if (delnum >= auto_spawn) { err("ZInternal error: delnum too big. (#4.3.5)\n"); return; } + if (d[delnum].used) { err("ZInternal error: delnum in use. (#4.3.5)\n"); return; } + for (i = 0;i < messid.len;++i) + if (messid.s[i]) + if (!i || (messid.s[i] != '/')) + if ((unsigned char) (messid.s[i] - '0') > 9) + { err("DInternal error: messid has nonnumerics. (#5.3.5)\n"); return; } + if (messid.len > 100) { err("DInternal error: messid too long. (#5.3.5)\n"); return; } + if (!messid.s[0]) { err("DInternal error: messid too short. (#5.3.5)\n"); return; } + + if (!stralloc_copys(&d[delnum].output,"")) + { err("Zqmail-spawn out of memory. (#4.3.0)\n"); return; } + + j = byte_rchr(recip.s,recip.len,'@'); + if (j >= recip.len) { err("DSorry, address must include host name. (#5.1.3)\n"); return; } + + fdmess = open_read(messid.s); + if (fdmess == -1) { err("Zqmail-spawn unable to open message. (#4.3.0)\n"); return; } + + if (fstat(fdmess,&st) == -1) + { close(fdmess); err("Zqmail-spawn unable to fstat message. (#4.3.0)\n"); return; } + if ((st.st_mode & S_IFMT) != S_IFREG) + { close(fdmess); err("ZSorry, message has wrong type. (#4.3.5)\n"); return; } + if (st.st_uid != auto_uidq) /* aaack! qmailq has to be trusted! */ + /* your security is already toast at this point. damage control... */ + { close(fdmess); err("ZSorry, message has wrong owner. (#4.3.5)\n"); return; } + + if (pipe(pi) == -1) + { close(fdmess); err("Zqmail-spawn unable to create pipe. (#4.3.0)\n"); return; } + + coe(pi[0]); + + f = spawn(fdmess,pi[1],sender.s,recip.s,j); + close(fdmess); + if (f == -1) + { close(pi[0]); close(pi[1]); err("Zqmail-spawn unable to fork. (#4.3.0)\n"); return; } + + d[delnum].fdin = pi[0]; + d[delnum].fdout = pi[1]; coe(pi[1]); + d[delnum].pid = f; + d[delnum].used = 1; +} + +char cmdbuf[1024]; + +void getcmd() +{ + int i; + int r; + char ch; + + r = read(0,cmdbuf,sizeof(cmdbuf)); + if (r == 0) + { flagreading = 0; return; } + if (r == -1) + { + if (errno != error_intr) + flagreading = 0; + return; + } + + for (i = 0;i < r;++i) + { + ch = cmdbuf[i]; + switch(stage) + { + case 0: + delnum = (unsigned int) (unsigned char) ch; + messid.len = 0; stage = 1; break; + case 1: + if (!stralloc_append(&messid,&ch)) flagabort = 1; + if (ch) break; + sender.len = 0; stage = 2; break; + case 2: + if (!stralloc_append(&sender,&ch)) flagabort = 1; + if (ch) break; + recip.len = 0; stage = 3; break; + case 3: + if (!stralloc_append(&recip,&ch)) flagabort = 1; + if (ch) break; + docmd(); + flagabort = 0; stage = 0; break; + } + } +} + +char inbuf[128]; + +void main(argc,argv) +int argc; +char **argv; +{ + char ch; + int i; + int r; + fd_set rfds; + int nfds; + + if (chdir(auto_qmail) == -1) _exit(111); + if (chdir("queue/mess") == -1) _exit(111); + if (!stralloc_copys(&messid,"")) _exit(111); + if (!stralloc_copys(&sender,"")) _exit(111); + if (!stralloc_copys(&recip,"")) _exit(111); + + d = (struct delivery *) alloc((auto_spawn + 10) * sizeof(struct delivery)); + if (!d) _exit(111); + + substdio_fdbuf(&ssout,okwrite,1,outbuf,sizeof(outbuf)); + + sig_pipeignore(); + sig_childcatch(sigchld); + + initialize(argc,argv); + + ch = auto_spawn; substdio_putflush(&ssout,&ch,1); + + for (i = 0;i < auto_spawn;++i) { d[i].used = 0; d[i].output.s = 0; } + + for (;;) + { + if (!flagreading) + { + for (i = 0;i < auto_spawn;++i) if (d[i].used) break; + if (i >= auto_spawn) _exit(0); + } + sig_childunblock(); + + FD_ZERO(&rfds); + if (flagreading) FD_SET(0,&rfds); + nfds = 1; + for (i = 0;i < auto_spawn;++i) if (d[i].used) + { FD_SET(d[i].fdin,&rfds); if (d[i].fdin >= nfds) nfds = d[i].fdin + 1; } + + r = select(nfds,&rfds,(fd_set *) 0,(fd_set *) 0,(struct timeval *) 0); + sig_childblock(); + + if (r != -1) + { + if (flagreading) + if (FD_ISSET(0,&rfds)) + getcmd(); + for (i = 0;i < auto_spawn;++i) if (d[i].used) + if (FD_ISSET(d[i].fdin,&rfds)) + { + r = read(d[i].fdin,inbuf,128); + if (r == -1) + continue; /* read error on a readable pipe? be serious */ + if (r == 0) + { + ch = i; 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; + } + 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; + 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); + } + } + } + } +}